about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-08-27 21:46:52 -0400
committerNiko Matsakis <niko@alum.mit.edu>2014-08-27 21:46:52 -0400
commit1b487a890695e7d6dfbfe5dcd7d4fa0e8ca8003f (patch)
tree552fabade603ab0d148a49ae3cf1abd3f399740a /src
parent3ee047ae1ffab454270bc1859b3beef3556ef8f9 (diff)
downloadrust-1b487a890695e7d6dfbfe5dcd7d4fa0e8ca8003f.tar.gz
rust-1b487a890695e7d6dfbfe5dcd7d4fa0e8ca8003f.zip
Implement generalized object and type parameter bounds (Fixes #16462)
Diffstat (limited to 'src')
-rw-r--r--src/liballoc/boxed.rs6
-rw-r--r--src/libcollections/dlist.rs25
-rw-r--r--src/libcollections/priority_queue.rs9
-rw-r--r--src/libcollections/ringbuf.rs23
-rw-r--r--src/libcollections/smallintmap.rs22
-rw-r--r--src/libcollections/treemap.rs130
-rw-r--r--src/libcollections/trie.rs24
-rw-r--r--src/libcollections/vec.rs16
-rw-r--r--src/libcore/any.rs4
-rw-r--r--src/libcore/cell.rs20
-rw-r--r--src/libcore/finally.rs7
-rw-r--r--src/libcore/fmt/mod.rs6
-rw-r--r--src/libcore/iter.rs14
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libcore/mem.rs4
-rw-r--r--src/libcore/slice.rs61
-rw-r--r--src/libdebug/lib.rs2
-rw-r--r--src/libdebug/repr.rs2
-rw-r--r--src/libfourcc/lib.rs4
-rw-r--r--src/libgraphviz/lib.rs3
-rw-r--r--src/libgraphviz/maybe_owned_vec.rs10
-rw-r--r--src/libgreen/simple.rs2
-rw-r--r--src/libgreen/task.rs4
-rw-r--r--src/libhexfloat/lib.rs2
-rw-r--r--src/libnative/task.rs4
-rw-r--r--src/librand/distributions/mod.rs10
-rw-r--r--src/librand/lib.rs18
-rw-r--r--src/librbml/lib.rs10
-rw-r--r--src/libregex_macros/lib.rs2
-rw-r--r--src/librustc/driver/driver.rs4
-rw-r--r--src/librustc/front/feature_gate.rs7
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/metadata/common.rs24
-rw-r--r--src/librustc/metadata/decoder.rs141
-rw-r--r--src/librustc/metadata/encoder.rs164
-rw-r--r--src/librustc/metadata/tydecode.rs86
-rw-r--r--src/librustc/metadata/tyencode.rs35
-rw-r--r--src/librustc/middle/astencode.rs38
-rw-r--r--src/librustc/middle/cfg/construct.rs10
-rw-r--r--src/librustc/middle/check_match.rs2
-rw-r--r--src/librustc/middle/dataflow.rs9
-rw-r--r--src/librustc/middle/expr_use_visitor.rs10
-rw-r--r--src/librustc/middle/graph.rs1
-rw-r--r--src/librustc/middle/kind.rs168
-rw-r--r--src/librustc/middle/mem_categorization.rs6
-rw-r--r--src/librustc/middle/privacy.rs4
-rw-r--r--src/librustc/middle/region.rs33
-rw-r--r--src/librustc/middle/resolve.rs62
-rw-r--r--src/librustc/middle/resolve_lifetime.rs112
-rw-r--r--src/librustc/middle/save/mod.rs16
-rw-r--r--src/librustc/middle/save/recorder.rs2
-rw-r--r--src/librustc/middle/subst.rs6
-rw-r--r--src/librustc/middle/trans/_match.rs9
-rw-r--r--src/librustc/middle/trans/cleanup.rs27
-rw-r--r--src/librustc/middle/trans/debuginfo.rs3
-rw-r--r--src/librustc/middle/trans/glue.rs4
-rw-r--r--src/librustc/middle/ty.rs312
-rw-r--r--src/librustc/middle/ty_fold.rs35
-rw-r--r--src/librustc/middle/typeck/astconv.rs429
-rw-r--r--src/librustc/middle/typeck/check/method.rs98
-rw-r--r--src/librustc/middle/typeck/check/mod.rs737
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs695
-rw-r--r--src/librustc/middle/typeck/check/regionmanip.rs434
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs7
-rw-r--r--src/librustc/middle/typeck/collect.rs472
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs23
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs232
-rw-r--r--src/librustc/middle/typeck/infer/glb.rs5
-rw-r--r--src/librustc/middle/typeck/infer/lub.rs5
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs80
-rw-r--r--src/librustc/middle/typeck/infer/region_inference/mod.rs477
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs3
-rw-r--r--src/librustc/middle/typeck/infer/unify.rs9
-rw-r--r--src/librustc/middle/typeck/rscope.rs68
-rw-r--r--src/librustc/util/common.rs50
-rw-r--r--src/librustc/util/ppaux.rs293
-rw-r--r--src/librustc_llvm/lib.rs6
-rw-r--r--src/librustdoc/clean/inline.rs12
-rw-r--r--src/librustdoc/clean/mod.rs33
-rw-r--r--src/librustdoc/doctree.rs2
-rw-r--r--src/librustdoc/html/format.rs9
-rw-r--r--src/librustdoc/html/render.rs14
-rw-r--r--src/librustdoc/visit_ast.rs4
-rw-r--r--src/librustrt/exclusive.rs12
-rw-r--r--src/librustrt/lib.rs3
-rw-r--r--src/librustrt/local_data.rs10
-rw-r--r--src/librustrt/rtio.rs4
-rw-r--r--src/librustrt/task.rs8
-rw-r--r--src/librustuv/access.rs7
-rw-r--r--src/librustuv/timeout.rs8
-rw-r--r--src/libserialize/json.rs4
-rw-r--r--src/libserialize/lib.rs1
-rw-r--r--src/libstd/collections/hashmap.rs22
-rw-r--r--src/libstd/io/extensions.rs19
-rw-r--r--src/libstd/io/mod.rs107
-rw-r--r--src/libstd/io/util.rs4
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/path/mod.rs10
-rw-r--r--src/libstd/rt/backtrace.rs2
-rw-r--r--src/libsync/comm/mod.rs8
-rw-r--r--src/libsync/comm/select.rs20
-rw-r--r--src/libsync/lib.rs1
-rw-r--r--src/libsync/lock.rs34
-rw-r--r--src/libsync/raw.rs7
-rw-r--r--src/libsync/spsc_queue.rs21
-rw-r--r--src/libsyntax/ast.rs19
-rw-r--r--src/libsyntax/ast_map/mod.rs22
-rw-r--r--src/libsyntax/ast_util.rs8
-rw-r--r--src/libsyntax/diagnostics/plugin.rs18
-rw-r--r--src/libsyntax/ext/asm.rs4
-rw-r--r--src/libsyntax/ext/base.rs70
-rw-r--r--src/libsyntax/ext/bytes.rs6
-rw-r--r--src/libsyntax/ext/cfg.rs6
-rw-r--r--src/libsyntax/ext/concat.rs2
-rw-r--r--src/libsyntax/ext/concat_idents.rs4
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs6
-rw-r--r--src/libsyntax/ext/env.rs8
-rw-r--r--src/libsyntax/ext/expand.rs191
-rw-r--r--src/libsyntax/ext/fmt.rs2
-rw-r--r--src/libsyntax/ext/format.rs11
-rw-r--r--src/libsyntax/ext/log_syntax.rs8
-rw-r--r--src/libsyntax/ext/quote.rs39
-rw-r--r--src/libsyntax/ext/source_util.rs16
-rw-r--r--src/libsyntax/ext/trace_macros.rs2
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs39
-rw-r--r--src/libsyntax/fold.rs42
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax/parse/parser.rs184
-rw-r--r--src/libsyntax/print/pp.rs4
-rw-r--r--src/libsyntax/print/pprust.rs139
-rw-r--r--src/libsyntax/visit.rs38
-rw-r--r--src/libtest/lib.rs6
-rw-r--r--src/test/auxiliary/issue-2380.rs4
-rw-r--r--src/test/auxiliary/issue-7178.rs2
-rw-r--r--src/test/auxiliary/macro_crate_test.rs6
-rw-r--r--src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs33
-rw-r--r--src/test/auxiliary/syntax-extension-with-dll-deps-2.rs2
-rw-r--r--src/test/bench/shootout-fasta-redux.rs4
-rw-r--r--src/test/bench/shootout-meteor.rs4
-rw-r--r--src/test/compile-fail/bad-method-typaram-kind.rs2
-rw-r--r--src/test/compile-fail/borrowck-call-sendfn.rs2
-rw-r--r--src/test/compile-fail/borrowck-object-lifetime.rs15
-rw-r--r--src/test/compile-fail/box-static-bound.rs2
-rw-r--r--src/test/compile-fail/builtin-superkinds-self-type.rs2
-rw-r--r--src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs2
-rw-r--r--src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs4
-rw-r--r--src/test/compile-fail/closure-bounds-subtype.rs4
-rw-r--r--src/test/compile-fail/drop-on-non-struct.rs1
-rw-r--r--src/test/compile-fail/issue-12470.rs (renamed from src/test/compile-fail/isuue-12470.rs)2
-rw-r--r--src/test/compile-fail/issue-14285.rs2
-rw-r--r--src/test/compile-fail/issue-3154.rs2
-rw-r--r--src/test/compile-fail/issue-3907-2.rs4
-rw-r--r--src/test/compile-fail/issue-3953.rs12
-rw-r--r--src/test/compile-fail/issue-4972.rs4
-rw-r--r--src/test/compile-fail/issue-5035-2.rs4
-rw-r--r--src/test/compile-fail/issue-5216.rs4
-rw-r--r--src/test/compile-fail/issue-5883.rs8
-rw-r--r--src/test/compile-fail/kindck-impl-type-params.rs2
-rw-r--r--src/test/compile-fail/kindck-proc-bounds.rs (renamed from src/test/compile-fail/proc-bounds.rs)7
-rw-r--r--src/test/compile-fail/kindck-send-object.rs44
-rw-r--r--src/test/compile-fail/kindck-send.rs60
-rw-r--r--src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs30
-rw-r--r--src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs15
-rw-r--r--src/test/compile-fail/moves-sru-moved-field.rs2
-rw-r--r--src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs44
-rw-r--r--src/test/compile-fail/region-object-lifetime-1.rs49
-rw-r--r--src/test/compile-fail/regionck-closure-lifetimes.rs2
-rw-r--r--src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs3
-rw-r--r--src/test/compile-fail/regions-bound-missing-bound-in-impl.rs57
-rw-r--r--src/test/compile-fail/regions-bounded-by-send.rs91
-rw-r--r--src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs73
-rw-r--r--src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs33
-rw-r--r--src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs44
-rw-r--r--src/test/compile-fail/regions-bounded-method-type-parameters.rs (renamed from src/test/compile-fail/proc-static-bound.rs)30
-rw-r--r--src/test/compile-fail/regions-close-object-into-object.rs (renamed from src/test/compile-fail/owned-ptr-static-bound.rs)18
-rw-r--r--src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs (renamed from src/test/compile-fail/regions-bound-lists-feature-gate-2.rs)13
-rw-r--r--src/test/compile-fail/regions-close-over-type-parameter-1.rs31
-rw-r--r--src/test/compile-fail/regions-close-over-type-parameter-2.rs (renamed from src/test/compile-fail/kindck-owned-trait-contains.rs)20
-rw-r--r--src/test/compile-fail/regions-early-bound-error.rs2
-rw-r--r--src/test/compile-fail/regions-enum-not-wf.rs37
-rw-r--r--src/test/compile-fail/regions-escape-bound-fn-2.rs1
-rw-r--r--src/test/compile-fail/regions-escape-via-trait-or-not.rs10
-rw-r--r--src/test/compile-fail/regions-free-region-ordering-callee.rs6
-rw-r--r--src/test/compile-fail/regions-free-region-ordering-caller.rs8
-rw-r--r--src/test/compile-fail/regions-free-region-ordering-incorrect.rs2
-rw-r--r--src/test/compile-fail/regions-freevar.rs4
-rw-r--r--src/test/compile-fail/regions-infer-bound-from-trait-self.rs61
-rw-r--r--src/test/compile-fail/regions-infer-bound-from-trait.rs50
-rw-r--r--src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs2
-rw-r--r--src/test/compile-fail/regions-lifetime-bounds-on-fns.rs41
-rw-r--r--src/test/compile-fail/regions-proc-bound-capture.rs26
-rw-r--r--src/test/compile-fail/regions-proc-bounds.rs (renamed from src/test/compile-fail/regions-bound-lists-feature-gate.rs)10
-rw-r--r--src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs2
-rw-r--r--src/test/compile-fail/regions-ret-borrowed-1.rs5
-rw-r--r--src/test/compile-fail/regions-ret-borrowed.rs5
-rw-r--r--src/test/compile-fail/regions-struct-not-wf.rs32
-rw-r--r--src/test/compile-fail/regions-trait-variance.rs2
-rw-r--r--src/test/compile-fail/regions-variance-covariant-use-contravariant.rs2
-rw-r--r--src/test/compile-fail/regions-variance-invariant-use-contravariant.rs2
-rw-r--r--src/test/compile-fail/regions-variance-invariant-use-covariant.rs2
-rw-r--r--src/test/compile-fail/selftype-traittype.rs2
-rw-r--r--src/test/compile-fail/static-region-bound.rs4
-rw-r--r--src/test/compile-fail/trailing-plus-in-bounds.rs2
-rw-r--r--src/test/compile-fail/trait-bounds-sugar.rs7
-rw-r--r--src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs2
-rw-r--r--src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs2
-rw-r--r--src/test/compile-fail/unconstrained-ref.rs2
-rw-r--r--src/test/compile-fail/unsized4.rs2
-rw-r--r--src/test/compile-fail/use-after-move-implicity-coerced-object.rs4
-rw-r--r--src/test/compile-fail/variance-regions-direct.rs4
-rw-r--r--src/test/compile-fail/variance-regions-indirect.rs10
-rw-r--r--src/test/pretty/closure-reform-pretty.rs2
-rw-r--r--src/test/pretty/issue-4264.pp14
-rw-r--r--src/test/pretty/path-type-bounds.rs2
-rw-r--r--src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot30
-rw-r--r--src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot50
-rw-r--r--src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot34
-rw-r--r--src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot34
-rw-r--r--src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot54
-rw-r--r--src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot56
-rw-r--r--src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot32
-rw-r--r--src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot118
-rw-r--r--src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot124
-rw-r--r--src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot6
-rw-r--r--src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot16
-rw-r--r--src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot24
-rw-r--r--src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot14
-rw-r--r--src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot114
-rw-r--r--src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot120
-rw-r--r--src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot128
-rw-r--r--src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot196
-rw-r--r--src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot196
-rw-r--r--src/test/run-pass/alignment-gep-tup-like-1.rs4
-rw-r--r--src/test/run-pass/borrowck-freeze-frozen-mut.rs2
-rw-r--r--src/test/run-pass/close-over-big-then-small-data.rs4
-rw-r--r--src/test/run-pass/closure-reform.rs2
-rw-r--r--src/test/run-pass/closure-syntax.rs12
-rw-r--r--src/test/run-pass/colorful-write-macros.rs2
-rw-r--r--src/test/run-pass/explicit-self-generic.rs4
-rw-r--r--src/test/run-pass/issue-10802.rs4
-rw-r--r--src/test/run-pass/issue-11205.rs6
-rw-r--r--src/test/run-pass/issue-11612.rs2
-rw-r--r--src/test/run-pass/issue-11677.rs3
-rw-r--r--src/test/run-pass/issue-14958.rs2
-rw-r--r--src/test/run-pass/issue-14959.rs4
-rw-r--r--src/test/run-pass/issue-2734.rs4
-rw-r--r--src/test/run-pass/issue-2735.rs4
-rw-r--r--src/test/run-pass/issue-3424.rs2
-rw-r--r--src/test/run-pass/issue-5192.rs4
-rw-r--r--src/test/run-pass/issue-5554.rs5
-rw-r--r--src/test/run-pass/issue-5708.rs4
-rw-r--r--src/test/run-pass/issue-6318.rs4
-rw-r--r--src/test/run-pass/issue-8249.rs2
-rw-r--r--src/test/run-pass/issue-9719.rs6
-rw-r--r--src/test/run-pass/kindck-owned-trait-contains-1.rs5
-rw-r--r--src/test/run-pass/newlambdas-ret-infer.rs2
-rw-r--r--src/test/run-pass/newlambdas-ret-infer2.rs2
-rw-r--r--src/test/run-pass/overloaded-autoderef-indexing.rs2
-rw-r--r--src/test/run-pass/regions-early-bound-trait-param.rs8
-rw-r--r--src/test/run-pass/regions-early-bound-used-in-bound.rs2
-rw-r--r--src/test/run-pass/swap-overlapping.rs4
-rw-r--r--src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs2
-rw-r--r--src/test/run-pass/trait-bounds-on-structs-and-enums.rs4
-rw-r--r--src/test/run-pass/trait-object-generics.rs2
-rw-r--r--src/test/run-pass/unboxed-closures-boxed.rs4
272 files changed, 6746 insertions, 3117 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 6a3e1fa2862..13d4a0a1f0a 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -105,9 +105,9 @@ pub trait BoxAny {
 }
 
 #[stable]
-impl BoxAny for Box<Any> {
+impl BoxAny for Box<Any+'static> {
     #[inline]
-    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
+    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any+'static>> {
         if self.is::<T>() {
             unsafe {
                 // Get the raw representation of the trait object
@@ -132,7 +132,7 @@ impl<T: fmt::Show> fmt::Show for Box<T> {
     }
 }
 
-impl fmt::Show for Box<Any> {
+impl fmt::Show for Box<Any+'static> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.pad("Box<Any>")
     }
diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs
index 418bb147d20..47c56375ada 100644
--- a/src/libcollections/dlist.rs
+++ b/src/libcollections/dlist.rs
@@ -49,19 +49,29 @@ struct Node<T> {
     value: T,
 }
 
-/// An iterator over references to the items of a `DList`.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct Items<'a, T> {
     head: &'a Link<T>,
     tail: Rawlink<Node<T>>,
     nelem: uint,
 }
 
+/// An iterator over references to the items of a `DList`.
+#[cfg(not(stage0))]
+pub struct Items<'a, T:'a> {
+    head: &'a Link<T>,
+    tail: Rawlink<Node<T>>,
+    nelem: uint,
+}
+
 // FIXME #11820: the &'a Option<> of the Link stops clone working.
 impl<'a, T> Clone for Items<'a, T> {
     fn clone(&self) -> Items<'a, T> { *self }
 }
 
-/// An iterator over mutable references to the items of a `DList`.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct MutItems<'a, T> {
     list: &'a mut DList<T>,
     head: Rawlink<Node<T>>,
@@ -69,7 +79,16 @@ pub struct MutItems<'a, T> {
     nelem: uint,
 }
 
-/// A consuming iterator over the items of a `DList`.
+/// An iterator over mutable references to the items of a `DList`.
+#[cfg(not(stage0))]
+pub struct MutItems<'a, T:'a> {
+    list: &'a mut DList<T>,
+    head: Rawlink<Node<T>>,
+    tail: Rawlink<Node<T>>,
+    nelem: uint,
+}
+
+/// An iterator over mutable references to the items of a `DList`.
 #[deriving(Clone)]
 pub struct MoveItems<T> {
     list: DList<T>
diff --git a/src/libcollections/priority_queue.rs b/src/libcollections/priority_queue.rs
index 674fa129943..905078ccc3c 100644
--- a/src/libcollections/priority_queue.rs
+++ b/src/libcollections/priority_queue.rs
@@ -515,11 +515,18 @@ impl<T: Ord> PriorityQueue<T> {
     }
 }
 
-/// `PriorityQueue` iterator.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct Items <'a, T> {
     iter: slice::Items<'a, T>,
 }
 
+/// `PriorityQueue` iterator.
+#[cfg(not(stage0))]
+pub struct Items <'a, T:'a> {
+    iter: slice::Items<'a, T>,
+}
+
 impl<'a, T> Iterator<&'a T> for Items<'a, T> {
     #[inline]
     fn next(&mut self) -> Option<(&'a T)> { self.iter.next() }
diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs
index 2f0fbfadb17..6b293c9f4d8 100644
--- a/src/libcollections/ringbuf.rs
+++ b/src/libcollections/ringbuf.rs
@@ -293,7 +293,8 @@ impl<T> RingBuf<T> {
     }
 }
 
-/// `RingBuf` iterator.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct Items<'a, T> {
     lo: uint,
     index: uint,
@@ -301,6 +302,15 @@ pub struct Items<'a, T> {
     elts: &'a [Option<T>],
 }
 
+/// `RingBuf` iterator.
+#[cfg(not(stage0))]
+pub struct Items<'a, T:'a> {
+    lo: uint,
+    index: uint,
+    rindex: uint,
+    elts: &'a [Option<T>],
+}
+
 impl<'a, T> Iterator<&'a T> for Items<'a, T> {
     #[inline]
     fn next(&mut self) -> Option<&'a T> {
@@ -348,13 +358,22 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
     }
 }
 
-/// `RingBuf` mutable iterator.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct MutItems<'a, T> {
     remaining1: &'a mut [Option<T>],
     remaining2: &'a mut [Option<T>],
     nelts: uint,
 }
 
+/// `RingBuf` mutable iterator.
+#[cfg(not(stage0))]
+pub struct MutItems<'a, T:'a> {
+    remaining1: &'a mut [Option<T>],
+    remaining2: &'a mut [Option<T>],
+    nelts: uint,
+}
+
 impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> {
     #[inline]
     #[allow(deprecated)] // mut_shift_ref
diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs
index 534262d79c9..5ef1dd2ab22 100644
--- a/src/libcollections/smallintmap.rs
+++ b/src/libcollections/smallintmap.rs
@@ -489,19 +489,37 @@ macro_rules! double_ended_iterator {
     }
 }
 
-/// Forward iterator over a map.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct Entries<'a, T> {
     front: uint,
     back: uint,
     iter: slice::Items<'a, Option<T>>
 }
 
+/// Forward iterator over a map.
+#[cfg(not(stage0))]
+pub struct Entries<'a, T:'a> {
+    front: uint,
+    back: uint,
+    iter: slice::Items<'a, Option<T>>
+}
+
 iterator!(impl Entries -> (uint, &'a T), get_ref)
 double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref)
 
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
+pub struct MutEntries<'a, T> {
+    front: uint,
+    back: uint,
+    iter: slice::MutItems<'a, Option<T>>
+}
+
 /// Forward iterator over the key-value pairs of a map, with the
 /// values being mutable.
-pub struct MutEntries<'a, T> {
+#[cfg(not(stage0))]
+pub struct MutEntries<'a, T:'a> {
     front: uint,
     back: uint,
     iter: slice::MutItems<'a, Option<T>>
diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs
index 8e5ffbd1686..6bb1e4a5ad0 100644
--- a/src/libcollections/treemap.rs
+++ b/src/libcollections/treemap.rs
@@ -668,7 +668,8 @@ impl<K: Ord, V> TreeMap<K, V> {
     }
 }
 
-/// A lazy forward iterator over a map.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct Entries<'a, K, V> {
     stack: Vec<&'a TreeNode<K, V>>,
     // See the comment on MutEntries; this is just to allow
@@ -679,13 +680,32 @@ pub struct Entries<'a, K, V> {
     remaining_max: uint
 }
 
-/// Lazy backward iterator over a map.
+/// Lazy forward iterator over a map
+#[cfg(not(stage0))]
+pub struct Entries<'a, K:'a, V:'a> {
+    stack: Vec<&'a TreeNode<K, V>>,
+    // See the comment on MutEntries; this is just to allow
+    // code-sharing (for this immutable-values iterator it *could* very
+    // well be Option<&'a TreeNode<K,V>>).
+    node: *const TreeNode<K, V>,
+    remaining_min: uint,
+    remaining_max: uint
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct RevEntries<'a, K, V> {
     iter: Entries<'a, K, V>,
 }
 
-/// A lazy forward iterator over a map that allows for the mutation of
-/// the values.
+/// Lazy backward iterator over a map
+#[cfg(not(stage0))]
+pub struct RevEntries<'a, K:'a, V:'a> {
+    iter: Entries<'a, K, V>,
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct MutEntries<'a, K, V> {
     stack: Vec<&'a mut TreeNode<K, V>>,
     // Unfortunately, we require some unsafe-ness to get around the
@@ -712,11 +732,46 @@ pub struct MutEntries<'a, K, V> {
     remaining_max: uint
 }
 
-/// Lazy backward iterator over a map.
+/// Lazy forward iterator over a map that allows for the mutation of
+/// the values.
+#[cfg(not(stage0))]
+pub struct MutEntries<'a, K:'a, V:'a> {
+    stack: Vec<&'a mut TreeNode<K, V>>,
+    // Unfortunately, we require some unsafe-ness to get around the
+    // fact that we would be storing a reference *into* one of the
+    // nodes in the stack.
+    //
+    // As far as the compiler knows, this would let us invalidate the
+    // reference by assigning a new value to this node's position in
+    // its parent, which would cause this current one to be
+    // deallocated so this reference would be invalid. (i.e. the
+    // compilers complaints are 100% correct.)
+    //
+    // However, as far as you humans reading this code know (or are
+    // about to know, if you haven't read far enough down yet), we are
+    // only reading from the TreeNode.{left,right} fields. the only
+    // thing that is ever mutated is the .value field (although any
+    // actual mutation that happens is done externally, by the
+    // iterator consumer). So, don't be so concerned, rustc, we've got
+    // it under control.
+    //
+    // (This field can legitimately be null.)
+    node: *mut TreeNode<K, V>,
+    remaining_min: uint,
+    remaining_max: uint
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct RevMutEntries<'a, K, V> {
     iter: MutEntries<'a, K, V>,
 }
 
+/// Lazy backward iterator over a map
+#[cfg(not(stage0))]
+pub struct RevMutEntries<'a, K:'a, V:'a> {
+    iter: MutEntries<'a, K, V>,
+}
 
 /// TreeMap keys iterator.
 pub type Keys<'a, K, V> =
@@ -885,9 +940,7 @@ fn mut_deref<K, V>(x: &mut Option<Box<TreeNode<K, V>>>)
     }
 }
 
-
-
-/// A lazy forward iterator over a map that consumes the map while iterating.
+/// Lazy forward iterator over a map that consumes the map while iterating
 pub struct MoveEntries<K, V> {
     stack: Vec<TreeNode<K, V>>,
     remaining: uint
@@ -1322,45 +1375,90 @@ impl<T: Ord> TreeSet<T> {
     }
 }
 
-/// A lazy forward iterator over a set.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct SetItems<'a, T> {
     iter: Entries<'a, T, ()>
 }
 
-/// Lazy backward iterator over a set.
+/// A lazy forward iterator over a set.
+#[cfg(not(stage0))]
+pub struct SetItems<'a, T:'a> {
+    iter: Entries<'a, T, ()>
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct RevSetItems<'a, T> {
     iter: RevEntries<'a, T, ()>
 }
 
+/// A lazy backward iterator over a set.
+#[cfg(not(stage0))]
+pub struct RevSetItems<'a, T:'a> {
+    iter: RevEntries<'a, T, ()>
+}
+
 /// A lazy forward iterator over a set that consumes the set while iterating.
 pub type MoveSetItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
 
-/// A lazy iterator producing elements in the set difference (in-order).
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct DifferenceItems<'a, T> {
     a: Peekable<&'a T, SetItems<'a, T>>,
     b: Peekable<&'a T, SetItems<'a, T>>,
 }
 
-/// A lazy iterator producing elements in the set symmetric difference (in-order).
+/// A lazy iterator producing elements in the set difference (in-order).
+#[cfg(not(stage0))]
+pub struct DifferenceItems<'a, T:'a> {
+    a: Peekable<&'a T, SetItems<'a, T>>,
+    b: Peekable<&'a T, SetItems<'a, T>>,
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct SymDifferenceItems<'a, T> {
     a: Peekable<&'a T, SetItems<'a, T>>,
     b: Peekable<&'a T, SetItems<'a, T>>,
 }
 
-/// A lazy iterator producing elements in the set intersection (in-order).
+/// A lazy iterator producing elements in the set symmetric difference (in-order).
+#[cfg(not(stage0))]
+pub struct SymDifferenceItems<'a, T:'a> {
+    a: Peekable<&'a T, SetItems<'a, T>>,
+    b: Peekable<&'a T, SetItems<'a, T>>,
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct IntersectionItems<'a, T> {
     a: Peekable<&'a T, SetItems<'a, T>>,
     b: Peekable<&'a T, SetItems<'a, T>>,
 }
 
-/// A lazy iterator producing elements in the set union (in-order).
+/// A lazy iterator producing elements in the set intersection (in-order).
+#[cfg(not(stage0))]
+pub struct IntersectionItems<'a, T:'a> {
+    a: Peekable<&'a T, SetItems<'a, T>>,
+    b: Peekable<&'a T, SetItems<'a, T>>,
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct UnionItems<'a, T> {
     a: Peekable<&'a T, SetItems<'a, T>>,
     b: Peekable<&'a T, SetItems<'a, T>>,
 }
 
-/// Compare `x` and `y`, but return `short` if x is None and `long` if y is
-/// `None`.
+/// A lazy iterator producing elements in the set union (in-order).
+#[cfg(not(stage0))]
+pub struct UnionItems<'a, T:'a> {
+    a: Peekable<&'a T, SetItems<'a, T>>,
+    b: Peekable<&'a T, SetItems<'a, T>>,
+}
+
+/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
 fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
                         short: Ordering, long: Ordering) -> Ordering {
     match (x, y) {
diff --git a/src/libcollections/trie.rs b/src/libcollections/trie.rs
index 7943c1da2c8..e79ec67cba0 100644
--- a/src/libcollections/trie.rs
+++ b/src/libcollections/trie.rs
@@ -857,7 +857,8 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
     return ret;
 }
 
-/// A forward iterator over a map.
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
 pub struct Entries<'a, T> {
     stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
     length: uint,
@@ -865,9 +866,28 @@ pub struct Entries<'a, T> {
     remaining_max: uint
 }
 
+/// A forward iterator over a map.
+#[cfg(not(stage0))]
+pub struct Entries<'a, T:'a> {
+    stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
+    length: uint,
+    remaining_min: uint,
+    remaining_max: uint
+}
+
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
+pub struct MutEntries<'a, T> {
+    stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
+    length: uint,
+    remaining_min: uint,
+    remaining_max: uint
+}
+
 /// A forward iterator over the key-value pairs of a map, with the
 /// values being mutable.
-pub struct MutEntries<'a, T> {
+#[cfg(not(stage0))]
+pub struct MutEntries<'a, T:'a> {
     stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
     length: uint,
     remaining_min: uint,
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index d67a01b6dee..f383677ed14 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1620,9 +1620,13 @@ pub struct MoveItems<T> {
 
 impl<T> Iterator<T> for MoveItems<T> {
     #[inline]
-    fn next(&mut self) -> Option<T> {
+    fn next<'a>(&'a mut self) -> Option<T> {
         unsafe {
-            self.iter.next().map(|x| ptr::read(x))
+            // Unsafely transmute from Items<'static, T> to Items<'a,
+            // T> because otherwise the type checker requires that T
+            // be bounded by 'static.
+            let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
+            iter.next().map(|x| ptr::read(x))
         }
     }
 
@@ -1634,9 +1638,13 @@ impl<T> Iterator<T> for MoveItems<T> {
 
 impl<T> DoubleEndedIterator<T> for MoveItems<T> {
     #[inline]
-    fn next_back(&mut self) -> Option<T> {
+    fn next_back<'a>(&'a mut self) -> Option<T> {
         unsafe {
-            self.iter.next_back().map(|x| ptr::read(x))
+            // Unsafely transmute from Items<'static, T> to Items<'a,
+            // T> because otherwise the type checker requires that T
+            // be bounded by 'static.
+            let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
+            iter.next_back().map(|x| ptr::read(x))
         }
     }
 }
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index 1809988847b..625b89b3bae 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -132,7 +132,7 @@ pub trait AnyRefExt<'a> {
 }
 
 #[stable]
-impl<'a> AnyRefExt<'a> for &'a Any {
+impl<'a> AnyRefExt<'a> for &'a Any+'a {
     #[inline]
     #[stable]
     fn is<T: 'static>(self) -> bool {
@@ -181,7 +181,7 @@ pub trait AnyMutRefExt<'a> {
 }
 
 #[stable]
-impl<'a> AnyMutRefExt<'a> for &'a mut Any {
+impl<'a> AnyMutRefExt<'a> for &'a mut Any+'a {
     #[inline]
     #[unstable = "naming conventions around acquiring references may change"]
     fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 2a7b1630edf..4cbe7d6d963 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -324,6 +324,16 @@ impl<T: PartialEq> PartialEq for RefCell<T> {
 
 /// Wraps a borrowed reference to a value in a `RefCell` box.
 #[unstable]
+#[cfg(not(stage0))]
+pub struct Ref<'b, T:'b> {
+    // FIXME #12808: strange name to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _parent: &'b RefCell<T>
+}
+
+/// Dox.
+#[unstable]
+#[cfg(stage0)]
 pub struct Ref<'b, T> {
     // FIXME #12808: strange name to try to avoid interfering with
     // field accesses of the contained type via Deref
@@ -369,6 +379,16 @@ pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
 
 /// Wraps a mutable borrowed reference to a value in a `RefCell` box.
 #[unstable]
+#[cfg(not(stage0))]
+pub struct RefMut<'b, T:'b> {
+    // FIXME #12808: strange name to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _parent: &'b RefCell<T>
+}
+
+/// Dox.
+#[unstable]
+#[cfg(stage0)]
 pub struct RefMut<'b, T> {
     // FIXME #12808: strange name to try to avoid interfering with
     // field accesses of the contained type via Deref
diff --git a/src/libcore/finally.rs b/src/libcore/finally.rs
index 514b3f90df7..c36150eb964 100644
--- a/src/libcore/finally.rs
+++ b/src/libcore/finally.rs
@@ -102,6 +102,13 @@ pub fn try_finally<T,U,R>(mutate: &mut T,
     try_fn(&mut *f.mutate, drop)
 }
 
+#[cfg(not(stage0))]
+struct Finallyalizer<'a,A:'a> {
+    mutate: &'a mut A,
+    dtor: |&mut A|: 'a
+}
+
+#[cfg(stage0)]
 struct Finallyalizer<'a,A> {
     mutate: &'a mut A,
     dtor: |&mut A|: 'a
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 85a289f1a30..f7ff92f5ce3 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -92,7 +92,7 @@ pub struct Formatter<'a> {
     /// Optionally specified precision for numeric types
     pub precision: Option<uint>,
 
-    buf: &'a mut FormatWriter,
+    buf: &'a mut FormatWriter+'a,
     curarg: slice::Items<'a, Argument<'a>>,
     args: &'a [Argument<'a>],
 }
@@ -524,7 +524,7 @@ impl<'a, T: Show> Show for &'a T {
 impl<'a, T: Show> Show for &'a mut T {
     fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
 }
-impl<'a> Show for &'a Show {
+impl<'a> Show for &'a Show+'a {
     fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) }
 }
 
@@ -692,7 +692,7 @@ macro_rules! tuple (
 
 tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
 
-impl<'a> Show for &'a any::Any {
+impl<'a> Show for &'a any::Any+'a {
     fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
 }
 
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index b2bd8d46fb5..7df8a7864d9 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -673,7 +673,7 @@ pub trait MutableDoubleEndedIterator {
     fn reverse_(&mut self);
 }
 
-impl<'a, A, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T {
+impl<'a, A:'a, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T {
     // FIXME: #5898: should be called `reverse`
     /// Use an iterator to reverse a container in-place
     fn reverse_(&mut self) {
@@ -777,18 +777,26 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
 
 /// A mutable reference to an iterator
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[cfg(not(stage0))]
+pub struct ByRef<'a, T:'a> {
+    iter: &'a mut T
+}
+
+/// Dox
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[cfg(stage0)]
 pub struct ByRef<'a, T> {
     iter: &'a mut T
 }
 
-impl<'a, A, T: Iterator<A>> Iterator<A> for ByRef<'a, T> {
+impl<'a, A, T: Iterator<A>+'a> Iterator<A> for ByRef<'a, T> {
     #[inline]
     fn next(&mut self) -> Option<A> { self.iter.next() }
     #[inline]
     fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
 }
 
-impl<'a, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for ByRef<'a, T> {
+impl<'a, A, T: DoubleEndedIterator<A>+'a> DoubleEndedIterator<A> for ByRef<'a, T> {
     #[inline]
     fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
 }
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 7e2ea492d4c..050e2348111 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -58,7 +58,7 @@
 
 #![no_std]
 #![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
-#![feature(simd, unsafe_destructor)]
+#![feature(simd, unsafe_destructor, issue_5723_bootstrap)]
 #![deny(missing_doc)]
 
 mod macros;
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index f0c39766ebb..947fa2ec92e 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -369,7 +369,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
 #[inline]
 #[unstable = "this function may be removed in the future due to its \
               questionable utility"]
-pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
+pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T {
     transmute(ptr)
 }
 
@@ -377,7 +377,7 @@ pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
 #[inline]
 #[unstable = "this function may be removed in the future due to its \
               questionable utility"]
-pub unsafe fn copy_mut_lifetime<'a, S, T>(_ptr: &'a mut S,
+pub unsafe fn copy_mut_lifetime<'a, S, T:'a>(_ptr: &'a mut S,
                                           ptr: &mut T) -> &'a mut T {
     transmute(ptr)
 }
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 475c2e94ec7..5a70cd8c847 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -996,9 +996,6 @@ impl<'a, T> Default for &'a [T] {
     fn default() -> &'a [T] { &[] }
 }
 
-
-
-
 //
 // Iterators
 //
@@ -1128,7 +1125,16 @@ impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
 
 /// An iterator over the slices of a vector separated by elements that
 /// match a predicate function.
+#[cfg(not(stage0))]
 #[experimental = "needs review"]
+pub struct Splits<'a, T:'a> {
+    v: &'a [T],
+    pred: |t: &T|: 'a -> bool,
+    finished: bool
+}
+
+/// Dox.
+#[cfg(stage0)]
 pub struct Splits<'a, T> {
     v: &'a [T],
     pred: |t: &T|: 'a -> bool,
@@ -1186,7 +1192,16 @@ impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> {
 
 /// An iterator over the subslices of the vector which are separated
 /// by elements that match `pred`.
+#[cfg(not(stage0))]
 #[experimental = "needs review"]
+pub struct MutSplits<'a, T:'a> {
+    v: &'a mut [T],
+    pred: |t: &T|: 'a -> bool,
+    finished: bool
+}
+
+/// Dox
+#[cfg(stage0)]
 pub struct MutSplits<'a, T> {
     v: &'a mut [T],
     pred: |t: &T|: 'a -> bool,
@@ -1255,7 +1270,16 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> {
 
 /// An iterator over the slices of a vector separated by elements that
 /// match a predicate function, splitting at most a fixed number of times.
+#[cfg(not(stage0))]
 #[experimental = "needs review"]
+pub struct SplitsN<'a, T:'a> {
+    iter: Splits<'a, T>,
+    count: uint,
+    invert: bool
+}
+
+/// Dox.
+#[cfg(stage0)]
 pub struct SplitsN<'a, T> {
     iter: Splits<'a, T>,
     count: uint,
@@ -1291,6 +1315,7 @@ impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
 
 /// An iterator over the (overlapping) slices of length `size` within
 /// a vector.
+#[cfg(stage0)]
 #[deriving(Clone)]
 #[experimental = "needs review"]
 pub struct Windows<'a, T> {
@@ -1298,7 +1323,16 @@ pub struct Windows<'a, T> {
     size: uint
 }
 
+/// An iterator over the (overlapping) slices of length `size` within
+/// a vector.
+#[cfg(not(stage0))]
+#[deriving(Clone)]
 #[experimental = "needs review"]
+pub struct Windows<'a, T:'a> {
+    v: &'a [T],
+    size: uint
+}
+
 impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
     #[inline]
     fn next(&mut self) -> Option<&'a [T]> {
@@ -1327,6 +1361,7 @@ impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
 ///
 /// When the vector len is not evenly divided by the chunk size,
 /// the last slice of the iteration will be the remainder.
+#[cfg(stage0)]
 #[deriving(Clone)]
 #[experimental = "needs review"]
 pub struct Chunks<'a, T> {
@@ -1334,6 +1369,18 @@ pub struct Chunks<'a, T> {
     size: uint
 }
 
+/// An iterator over a vector in (non-overlapping) chunks (`size`
+/// elements at a time).
+///
+/// When the vector len is not evenly divided by the chunk size,
+/// the last slice of the iteration will be the remainder.
+#[cfg(not(stage0))]
+#[deriving(Clone)]
+pub struct Chunks<'a, T:'a> {
+    v: &'a [T],
+    size: uint
+}
+
 #[experimental = "needs review"]
 impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
     #[inline]
@@ -1400,7 +1447,15 @@ impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> {
 /// An iterator over a vector in (non-overlapping) mutable chunks (`size`  elements at a time). When
 /// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
 /// the remainder.
+#[cfg(not(stage0))]
 #[experimental = "needs review"]
+pub struct MutChunks<'a, T:'a> {
+    v: &'a mut [T],
+    chunk_size: uint
+}
+
+/// Dox.
+#[cfg(stage0)]
 pub struct MutChunks<'a, T> {
     v: &'a mut [T],
     chunk_size: uint
diff --git a/src/libdebug/lib.rs b/src/libdebug/lib.rs
index 6341a380563..cc97eeffe7a 100644
--- a/src/libdebug/lib.rs
+++ b/src/libdebug/lib.rs
@@ -25,7 +25,7 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/master/")]
 #![experimental]
-#![feature(managed_boxes, macro_rules)]
+#![feature(managed_boxes, macro_rules, issue_5723_bootstrap)]
 #![allow(experimental)]
 
 pub mod fmt;
diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs
index 20f96d24a5f..dbd2c09497b 100644
--- a/src/libdebug/repr.rs
+++ b/src/libdebug/repr.rs
@@ -95,7 +95,7 @@ pub struct ReprVisitor<'a> {
     ptr: *const u8,
     ptr_stk: Vec<*const u8>,
     var_stk: Vec<VariantState>,
-    writer: &'a mut io::Writer,
+    writer: &'a mut io::Writer+'a,
     last_err: Option<io::IoError>,
 }
 
diff --git a/src/libfourcc/lib.rs b/src/libfourcc/lib.rs
index e4d61c47cc2..9e46da56a8e 100644
--- a/src/libfourcc/lib.rs
+++ b/src/libfourcc/lib.rs
@@ -72,8 +72,8 @@ pub fn plugin_registrar(reg: &mut Registry) {
     reg.register_macro("fourcc", expand_syntax_ext);
 }
 
-pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
     let (expr, endian) = parse_tts(cx, tts);
 
     let little = match endian {
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index 7cac0d25abf..10cc7e8afe9 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -271,6 +271,7 @@ pub fn main() {
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 #![license = "MIT/ASL2"]
+#![feature(issue_5723_bootstrap)]
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/master/")]
@@ -499,7 +500,7 @@ pub trait GraphWalk<'a, N, E> {
 
 /// Renders directed graph `g` into the writer `w` in DOT syntax.
 /// (Main entry point for the library.)
-pub fn render<'a, N, E, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>(
+pub fn render<'a, N:'a, E:'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>(
               g: &'a G,
               w: &mut W) -> io::IoResult<()>
 {
diff --git a/src/libgraphviz/maybe_owned_vec.rs b/src/libgraphviz/maybe_owned_vec.rs
index 987f214b153..17c75b76bc1 100644
--- a/src/libgraphviz/maybe_owned_vec.rs
+++ b/src/libgraphviz/maybe_owned_vec.rs
@@ -34,6 +34,14 @@ use std::slice;
 /// Some clients will have a pre-allocated vector ready to hand off in
 /// a slice; others will want to create the set on the fly and hand
 /// off ownership, via `Growable`.
+#[cfg(not(stage0))]
+pub enum MaybeOwnedVector<'a,T:'a> {
+    Growable(Vec<T>),
+    Borrowed(&'a [T]),
+}
+
+/// Stage0 only.
+#[cfg(stage0)]
 pub enum MaybeOwnedVector<'a,T> {
     Growable(Vec<T>),
     Borrowed(&'a [T]),
@@ -45,7 +53,7 @@ pub trait IntoMaybeOwnedVector<'a,T> {
     fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T>;
 }
 
-impl<'a,T> IntoMaybeOwnedVector<'a,T> for Vec<T> {
+impl<'a,T:'a> IntoMaybeOwnedVector<'a,T> for Vec<T> {
     #[inline]
     fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) }
 }
diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs
index 6254e8c55f0..058a00bcd4b 100644
--- a/src/libgreen/simple.rs
+++ b/src/libgreen/simple.rs
@@ -82,7 +82,7 @@ impl Runtime for SimpleTask {
     fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> { None }
     fn stack_bounds(&self) -> (uint, uint) { fail!() }
     fn can_block(&self) -> bool { true }
-    fn wrap(self: Box<SimpleTask>) -> Box<Any> { fail!() }
+    fn wrap(self: Box<SimpleTask>) -> Box<Any+'static> { fail!() }
 }
 
 pub fn task() -> Box<Task> {
diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs
index 73fe8f6a93f..ffd94e0b86f 100644
--- a/src/libgreen/task.rs
+++ b/src/libgreen/task.rs
@@ -488,7 +488,9 @@ impl Runtime for GreenTask {
 
     fn can_block(&self) -> bool { false }
 
-    fn wrap(self: Box<GreenTask>) -> Box<Any> { self as Box<Any> }
+    fn wrap(self: Box<GreenTask>) -> Box<Any+'static> {
+        self as Box<Any+'static>
+    }
 }
 
 #[cfg(test)]
diff --git a/src/libhexfloat/lib.rs b/src/libhexfloat/lib.rs
index 936e7cb4403..03bd96fc260 100644
--- a/src/libhexfloat/lib.rs
+++ b/src/libhexfloat/lib.rs
@@ -105,7 +105,7 @@ fn hex_float_lit_err(s: &str) -> Option<(uint, String)> {
 }
 
 pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+                         -> Box<base::MacResult+'static> {
     let (expr, ty_lit) = parse_tts(cx, tts);
 
     let ty = match ty_lit {
diff --git a/src/libnative/task.rs b/src/libnative/task.rs
index 55806caaf13..5c3beeec8ab 100644
--- a/src/libnative/task.rs
+++ b/src/libnative/task.rs
@@ -145,8 +145,8 @@ impl rt::Runtime for Ops {
         Local::put(cur_task);
     }
 
-    fn wrap(self: Box<Ops>) -> Box<Any> {
-        self as Box<Any>
+    fn wrap(self: Box<Ops>) -> Box<Any+'static> {
+        self as Box<Any+'static>
     }
 
     fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds }
diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs
index 9d401d1307c..447e3eea061 100644
--- a/src/librand/distributions/mod.rs
+++ b/src/librand/distributions/mod.rs
@@ -79,6 +79,13 @@ pub struct Weighted<T> {
     pub item: T,
 }
 
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
+pub struct WeightedChoice<'a, T> {
+    items: &'a mut [Weighted<T>],
+    weight_range: Range<uint>
+}
+
 /// A distribution that selects from a finite collection of weighted items.
 ///
 /// Each item has an associated weight that influences how likely it
@@ -105,7 +112,8 @@ pub struct Weighted<T> {
 ///      println!("{}", wc.ind_sample(&mut rng));
 /// }
 /// ```
-pub struct WeightedChoice<'a, T> {
+#[cfg(not(stage0))]
+pub struct WeightedChoice<'a, T:'a> {
     items: &'a mut [Weighted<T>],
     weight_range: Range<uint>
 }
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index 5f460225d39..f1ed9ae8997 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -269,10 +269,17 @@ pub trait Rng {
     }
 }
 
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
+pub struct Generator<'a, T, R> {
+    rng: &'a mut R,
+}
+
 /// Iterator which will generate a stream of random items.
 ///
 /// This iterator is created via the `gen_iter` method on `Rng`.
-pub struct Generator<'a, T, R> {
+#[cfg(not(stage0))]
+pub struct Generator<'a, T, R:'a> {
     rng: &'a mut R,
 }
 
@@ -282,10 +289,17 @@ impl<'a, T: Rand, R: Rng> Iterator<T> for Generator<'a, T, R> {
     }
 }
 
+/// Note: stage0-specific version.
+#[cfg(stage0)]
+pub struct AsciiGenerator<'a, R> {
+    rng: &'a mut R,
+}
+
 /// Iterator which will continuously generate random ascii characters.
 ///
 /// This iterator is created via the `gen_ascii_chars` method on `Rng`.
-pub struct AsciiGenerator<'a, R> {
+#[cfg(not(stage0))]
+pub struct AsciiGenerator<'a, R:'a> {
     rng: &'a mut R,
 }
 
diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs
index 4927a8293a4..a05c877a6a6 100644
--- a/src/librbml/lib.rs
+++ b/src/librbml/lib.rs
@@ -24,7 +24,7 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/master/",
        html_playground_url = "http://play.rust-lang.org/")]
-#![feature(macro_rules, phase)]
+#![feature(macro_rules, phase, issue_5723_bootstrap)]
 #![allow(missing_doc)]
 
 extern crate serialize;
@@ -662,11 +662,19 @@ pub mod writer {
     pub type EncodeResult = io::IoResult<()>;
 
     // rbml writing
+    #[cfg(stage0)]
     pub struct Encoder<'a, W> {
         pub writer: &'a mut W,
         size_positions: Vec<uint>,
     }
 
+    // rbml writing
+    #[cfg(not(stage0))]
+    pub struct Encoder<'a, W:'a> {
+        pub writer: &'a mut W,
+        size_positions: Vec<uint>,
+    }
+
     fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult {
         match size {
             1u => w.write(&[0x80u8 | (n as u8)]),
diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs
index 8610621d30a..8aa9a2fc8fb 100644
--- a/src/libregex_macros/lib.rs
+++ b/src/libregex_macros/lib.rs
@@ -77,7 +77,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
 /// strategy is identical and vm.rs has comments and will be easier to follow.
 #[allow(experimental)]
 fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
-          -> Box<MacResult> {
+          -> Box<MacResult+'static> {
     let regex = match parse(cx, tts) {
         Some(r) => r,
         // error is logged in 'parse' with cx.span_err
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 261d4be86b4..14642a3708a 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -958,11 +958,11 @@ pub fn pretty_print_input(sess: Session,
     let mut rdr = MemReader::new(src);
 
     let out = match ofile {
-        None => box io::stdout() as Box<Writer>,
+        None => box io::stdout() as Box<Writer+'static>,
         Some(p) => {
             let r = io::File::create(&p);
             match r {
-                Ok(w) => box w as Box<Writer>,
+                Ok(w) => box w as Box<Writer+'static>,
                 Err(e) => fail!("print-print failed to open {} due to {}",
                                 p.display(), e),
             }
diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs
index 7c19b25e01c..18f4b79de6e 100644
--- a/src/librustc/front/feature_gate.rs
+++ b/src/librustc/front/feature_gate.rs
@@ -74,7 +74,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
 
     // A temporary feature gate used to enable parser extensions needed
     // to bootstrap fix for #5723.
-    ("issue_5723_bootstrap", Active),
+    ("issue_5723_bootstrap", Accepted),
 
     // These are used to test this portion of the compiler, they don't actually
     // mean anything
@@ -97,7 +97,6 @@ enum Status {
 /// A set of features to be used by later passes.
 pub struct Features {
     pub default_type_params: Cell<bool>,
-    pub issue_5723_bootstrap: Cell<bool>,
     pub overloaded_calls: Cell<bool>,
     pub rustc_diagnostic_macros: Cell<bool>,
     pub import_shadowing: Cell<bool>,
@@ -107,7 +106,6 @@ impl Features {
     pub fn new() -> Features {
         Features {
             default_type_params: Cell::new(false),
-            issue_5723_bootstrap: Cell::new(false),
             overloaded_calls: Cell::new(false),
             rustc_diagnostic_macros: Cell::new(false),
             import_shadowing: Cell::new(false),
@@ -310,7 +308,7 @@ impl<'a> Visitor<()> for Context<'a> {
 
     fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
         match t.node {
-            ast::TyClosure(closure, _) if closure.onceness == ast::Once => {
+            ast::TyClosure(closure) if closure.onceness == ast::Once => {
                 self.gate_feature("once_fns", t.span,
                                   "once functions are \
                                    experimental and likely to be removed");
@@ -439,7 +437,6 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
     sess.abort_if_errors();
 
     sess.features.default_type_params.set(cx.has_feature("default_type_params"));
-    sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
     sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
     sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
     sess.features.import_shadowing.set(cx.has_feature("import_shadowing"));
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 239e858eeeb..9b3cc2b6a0a 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -31,6 +31,7 @@ This API is completely unstable and subject to change.
 #![allow(deprecated)]
 #![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
 #![feature(default_type_params, phase, unsafe_destructor)]
+#![feature(issue_5723_bootstrap)]
 
 #![allow(unknown_features)] // NOTE: Remove after next snapshot
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 6a1c7c6c951..ca2f47328db 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -27,8 +27,6 @@ pub static tag_items_data_item: uint = 0x04;
 
 pub static tag_items_data_item_family: uint = 0x05;
 
-pub static tag_items_data_item_ty_param_bounds: uint = 0x06;
-
 pub static tag_items_data_item_type: uint = 0x07;
 
 pub static tag_items_data_item_symbol: uint = 0x08;
@@ -179,7 +177,6 @@ pub static tag_lang_items_missing: uint = 0x74;
 
 pub static tag_item_unnamed_field: uint = 0x75;
 pub static tag_items_data_item_visibility: uint = 0x76;
-pub static tag_items_data_item_sized: uint = 0x77;
 
 pub static tag_item_method_tps: uint = 0x79;
 pub static tag_item_method_fty: uint = 0x7a;
@@ -222,12 +219,6 @@ pub struct LinkMeta {
     pub crate_hash: Svh,
 }
 
-pub static tag_region_param_def: uint = 0x90;
-pub static tag_region_param_def_ident: uint = 0x91;
-pub static tag_region_param_def_def_id: uint = 0x92;
-pub static tag_region_param_def_space: uint = 0x93;
-pub static tag_region_param_def_index: uint = 0x94;
-
 pub static tag_unboxed_closures: uint = 0x95;
 pub static tag_unboxed_closure: uint = 0x96;
 pub static tag_unboxed_closure_type: uint = 0x97;
@@ -239,3 +230,18 @@ pub static tag_struct_field_id: uint = 0x9b;
 
 pub static tag_attribute_is_sugared_doc: uint = 0x9c;
 
+pub static tag_trait_def_bounds: uint = 0x9d;
+
+pub static tag_items_data_region: uint = 0x9e;
+
+pub static tag_region_param_def: uint = 0xa0;
+pub static tag_region_param_def_ident: uint = 0xa1;
+pub static tag_region_param_def_def_id: uint = 0xa2;
+pub static tag_region_param_def_space: uint = 0xa3;
+pub static tag_region_param_def_index: uint = 0xa4;
+
+pub static tag_type_param_def: uint = 0xa5;
+
+pub static tag_item_generics: uint = 0xa6;
+pub static tag_method_ty_generics: uint = 0xa7;
+
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 74810261d4a..904ca2416e0 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -18,9 +18,9 @@ use metadata::common::*;
 use metadata::csearch::StaticMethodInfo;
 use metadata::csearch;
 use metadata::cstore;
-use metadata::tydecode::{parse_ty_data, parse_def_id};
-use metadata::tydecode::{parse_type_param_def_data, parse_bare_fn_ty_data};
-use metadata::tydecode::{parse_trait_ref_data};
+use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
+                         parse_type_param_def_data, parse_bounds_data,
+                         parse_bare_fn_ty_data, parse_trait_ref_data};
 use middle::def;
 use middle::lang_items;
 use middle::resolve::TraitItemKind;
@@ -242,48 +242,14 @@ fn item_trait_ref(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef {
     doc_trait_ref(tp, tcx, cdata)
 }
 
-fn item_ty_param_defs(item: rbml::Doc,
-                      tcx: &ty::ctxt,
-                      cdata: Cmd,
-                      tag: uint)
-                      -> subst::VecPerParamSpace<ty::TypeParameterDef> {
-    let mut bounds = subst::VecPerParamSpace::empty();
-    reader::tagged_docs(item, tag, |p| {
-        let bd = parse_type_param_def_data(
-            p.data, p.start, cdata.cnum, tcx,
-            |_, did| translate_def_id(cdata, did));
-        bounds.push(bd.space, bd);
-        true
-    });
-    bounds
+fn doc_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
+    parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
+                      |_, did| translate_def_id(cdata, did))
 }
 
-fn item_region_param_defs(item_doc: rbml::Doc, cdata: Cmd)
-                          -> subst::VecPerParamSpace<ty::RegionParameterDef>
-{
-    let mut v = subst::VecPerParamSpace::empty();
-    reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| {
-        let ident_str_doc = reader::get_doc(rp_doc,
-                                            tag_region_param_def_ident);
-        let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
-        let def_id_doc = reader::get_doc(rp_doc,
-                                         tag_region_param_def_def_id);
-        let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
-        let def_id = translate_def_id(cdata, def_id);
-
-        let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
-        let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
-
-        let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
-        let index = reader::doc_as_u64(doc) as uint;
-
-        v.push(space, ty::RegionParameterDef { name: ident.name,
-                                               def_id: def_id,
-                                               space: space,
-                                               index: index });
-        true
-    });
-    v
+fn trait_def_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
+    let d = reader::get_doc(doc, tag_trait_def_bounds);
+    doc_bounds(d, tcx, cdata)
 }
 
 fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
@@ -382,24 +348,11 @@ pub fn get_trait_def(cdata: Cmd,
                      tcx: &ty::ctxt) -> ty::TraitDef
 {
     let item_doc = lookup_item(item_id, cdata.data());
-    let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
-                                     tag_items_data_item_ty_param_bounds);
-    let rp_defs = item_region_param_defs(item_doc, cdata);
-    let mut bounds = ty::empty_builtin_bounds();
-    // Collect the builtin bounds from the encoded supertraits.
-    // FIXME(#8559): They should be encoded directly.
-    reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
-        // NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
-        let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
-        tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| {
-            bounds.add(bound);
-        });
-        true
-    });
+    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
+    let bounds = trait_def_bounds(item_doc, tcx, cdata);
 
     ty::TraitDef {
-        generics: ty::Generics {types: tp_defs,
-                                regions: rp_defs},
+        generics: generics,
         bounds: bounds,
         trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
     }
@@ -413,12 +366,10 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
     let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx,
                       cdata);
 
-    let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
-    let rp_defs = item_region_param_defs(item, cdata);
+    let generics = doc_generics(item, tcx, cdata, tag_item_generics);
 
     ty::Polytype {
-        generics: ty::Generics {types: tp_defs,
-                                regions: rp_defs},
+        generics: generics,
         ty: t
     }
 }
@@ -794,6 +745,7 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
                               tcx: &ty::ctxt)
                               -> ty::ImplOrTraitItem {
     let method_doc = lookup_item(id, cdata.data());
+
     let def_id = item_def_id(method_doc, cdata);
 
     let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
@@ -808,18 +760,13 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
 
     match item_sort(method_doc) {
         'r' | 'p' => {
-            let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
-                                                     tag_item_method_tps);
-            let rp_defs = item_region_param_defs(method_doc, cdata);
+            let generics = doc_generics(method_doc, tcx, cdata,
+                                        tag_method_ty_generics);
             let fty = doc_method_fty(method_doc, tcx, cdata);
             let vis = item_visibility(method_doc);
             let explicit_self = get_explicit_self(method_doc);
             let provided_source = get_provided_source(method_doc, cdata);
 
-            let generics = ty::Generics {
-                types: type_param_defs,
-                regions: rp_defs,
-            };
             ty::MethodTraitItem(Rc::new(ty::Method::new(name,
                                                         generics,
                                                         fty,
@@ -1392,3 +1339,57 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
         _ => false,
     }
 }
+
+fn doc_generics(base_doc: rbml::Doc,
+                tcx: &ty::ctxt,
+                cdata: Cmd,
+                tag: uint)
+                -> ty::Generics
+{
+    let doc = reader::get_doc(base_doc, tag);
+
+    let mut types = subst::VecPerParamSpace::empty();
+    reader::tagged_docs(doc, tag_type_param_def, |p| {
+        let bd = parse_type_param_def_data(
+            p.data, p.start, cdata.cnum, tcx,
+            |_, did| translate_def_id(cdata, did));
+        types.push(bd.space, bd);
+        true
+    });
+
+    let mut regions = subst::VecPerParamSpace::empty();
+    reader::tagged_docs(doc, tag_region_param_def, |rp_doc| {
+        let ident_str_doc = reader::get_doc(rp_doc,
+                                            tag_region_param_def_ident);
+        let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
+        let def_id_doc = reader::get_doc(rp_doc,
+                                         tag_region_param_def_def_id);
+        let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
+        let def_id = translate_def_id(cdata, def_id);
+
+        let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
+        let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
+
+        let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
+        let index = reader::doc_as_u64(doc) as uint;
+
+        let mut bounds = Vec::new();
+        reader::tagged_docs(rp_doc, tag_items_data_region, |p| {
+            bounds.push(
+                parse_region_data(
+                    p.data, cdata.cnum, p.start, tcx,
+                    |_, did| translate_def_id(cdata, did)));
+            true
+        });
+
+        regions.push(space, ty::RegionParameterDef { name: ident.name,
+                                                     def_id: def_id,
+                                                     space: space,
+                                                     index: index,
+                                                     bounds: bounds });
+
+        true
+    });
+
+    ty::Generics { types: types, regions: regions }
+}
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index ffa4a1b5bf0..1386e23b77d 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -19,8 +19,7 @@ use metadata::common::*;
 use metadata::cstore;
 use metadata::decoder;
 use metadata::tyencode;
-use middle::subst::VecPerParamSpace;
-use middle::ty::{node_id_to_type, lookup_item_type};
+use middle::ty::{lookup_item_type};
 use middle::astencode;
 use middle::ty;
 use middle::typeck;
@@ -150,45 +149,6 @@ pub fn def_to_string(did: DefId) -> String {
     format!("{}:{}", did.krate, did.node)
 }
 
-fn encode_ty_type_param_defs(rbml_w: &mut Encoder,
-                             ecx: &EncodeContext,
-                             params: &VecPerParamSpace<ty::TypeParameterDef>,
-                             tag: uint) {
-    let ty_str_ctxt = &tyencode::ctxt {
-        diag: ecx.diag,
-        ds: def_to_string,
-        tcx: ecx.tcx,
-        abbrevs: &ecx.type_abbrevs
-    };
-    for param in params.iter() {
-        rbml_w.start_tag(tag);
-        tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
-        rbml_w.end_tag();
-    }
-}
-
-fn encode_region_param_defs(rbml_w: &mut Encoder,
-                            params: &VecPerParamSpace<ty::RegionParameterDef>) {
-    for param in params.iter() {
-        rbml_w.start_tag(tag_region_param_def);
-
-        rbml_w.start_tag(tag_region_param_def_ident);
-        encode_name(rbml_w, param.name);
-        rbml_w.end_tag();
-
-        rbml_w.wr_tagged_str(tag_region_param_def_def_id,
-                             def_to_string(param.def_id).as_slice());
-
-        rbml_w.wr_tagged_u64(tag_region_param_def_space,
-                             param.space.to_uint() as u64);
-
-        rbml_w.wr_tagged_u64(tag_region_param_def_index,
-                             param.index as u64);
-
-        rbml_w.end_tag();
-    }
-}
-
 fn encode_item_variances(rbml_w: &mut Encoder,
                          ecx: &EncodeContext,
                          id: ast::NodeId) {
@@ -201,9 +161,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
 fn encode_bounds_and_type(rbml_w: &mut Encoder,
                           ecx: &EncodeContext,
                           pty: &ty::Polytype) {
-    encode_ty_type_param_defs(rbml_w, ecx, &pty.generics.types,
-                              tag_items_data_item_ty_param_bounds);
-    encode_region_param_defs(rbml_w, &pty.generics.regions);
+    encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics);
     encode_type(ecx, rbml_w, pty.ty);
 }
 
@@ -238,6 +196,33 @@ pub fn write_type(ecx: &EncodeContext,
     tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ);
 }
 
+pub fn write_region(ecx: &EncodeContext,
+                    rbml_w: &mut Encoder,
+                    r: ty::Region) {
+    let ty_str_ctxt = &tyencode::ctxt {
+        diag: ecx.diag,
+        ds: def_to_string,
+        tcx: ecx.tcx,
+        abbrevs: &ecx.type_abbrevs
+    };
+    tyencode::enc_region(rbml_w.writer, ty_str_ctxt, r);
+}
+
+fn encode_bounds(rbml_w: &mut Encoder,
+                 ecx: &EncodeContext,
+                 bounds: &ty::ParamBounds,
+                 tag: uint) {
+    rbml_w.start_tag(tag);
+
+    let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag,
+                                        ds: def_to_string,
+                                        tcx: ecx.tcx,
+                                        abbrevs: &ecx.type_abbrevs };
+    tyencode::enc_bounds(rbml_w.writer, ty_str_ctxt, bounds);
+
+    rbml_w.end_tag();
+}
+
 fn encode_type(ecx: &EncodeContext,
                rbml_w: &mut Encoder,
                typ: ty::t) {
@@ -246,6 +231,14 @@ fn encode_type(ecx: &EncodeContext,
     rbml_w.end_tag();
 }
 
+fn encode_region(ecx: &EncodeContext,
+                 rbml_w: &mut Encoder,
+                 r: ty::Region) {
+    rbml_w.start_tag(tag_items_data_region);
+    write_region(ecx, rbml_w, r);
+    rbml_w.end_tag();
+}
+
 fn encode_method_fty(ecx: &EncodeContext,
                      rbml_w: &mut Encoder,
                      typ: &ty::BareFnTy) {
@@ -728,7 +721,6 @@ fn encode_info_for_struct(ecx: &EncodeContext,
     /* Each class has its own index, since different classes
        may have fields with the same name */
     let mut index = Vec::new();
-    let tcx = ecx.tcx;
      /* We encode both private and public fields -- need to include
         private fields to get the offsets right */
     for field in fields.iter() {
@@ -745,7 +737,8 @@ fn encode_info_for_struct(ecx: &EncodeContext,
                token::get_name(nm), id);
         encode_struct_field_family(rbml_w, field.vis);
         encode_name(rbml_w, nm);
-        encode_type(ecx, rbml_w, node_id_to_type(tcx, id));
+        encode_bounds_and_type(rbml_w, ecx,
+                               &lookup_item_type(ecx.tcx, local_def(id)));
         encode_def_id(rbml_w, local_def(id));
 
         let stab = stability::lookup(ecx.tcx, field.id);
@@ -773,7 +766,6 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
     encode_bounds_and_type(rbml_w, ecx,
                            &lookup_item_type(ecx.tcx, local_def(ctor_id)));
     encode_name(rbml_w, name.name);
-    encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, ctor_id));
     ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
     encode_parent_item(rbml_w, local_def(struct_id));
 
@@ -793,13 +785,60 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
     rbml_w.end_tag();
 }
 
+fn encode_generics(rbml_w: &mut Encoder,
+                   ecx: &EncodeContext,
+                   generics: &ty::Generics,
+                   tag: uint)
+{
+    rbml_w.start_tag(tag);
+
+    // Type parameters
+    let ty_str_ctxt = &tyencode::ctxt {
+        diag: ecx.diag,
+        ds: def_to_string,
+        tcx: ecx.tcx,
+        abbrevs: &ecx.type_abbrevs
+    };
+    for param in generics.types.iter() {
+        rbml_w.start_tag(tag_type_param_def);
+        tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
+        rbml_w.end_tag();
+    }
+
+    // Region parameters
+    for param in generics.regions.iter() {
+        rbml_w.start_tag(tag_region_param_def);
+
+        rbml_w.start_tag(tag_region_param_def_ident);
+        encode_name(rbml_w, param.name);
+        rbml_w.end_tag();
+
+        rbml_w.wr_tagged_str(tag_region_param_def_def_id,
+                             def_to_string(param.def_id).as_slice());
+
+        rbml_w.wr_tagged_u64(tag_region_param_def_space,
+                             param.space.to_uint() as u64);
+
+        rbml_w.wr_tagged_u64(tag_region_param_def_index,
+                             param.index as u64);
+
+        for &bound_region in param.bounds.iter() {
+            encode_region(ecx, rbml_w, bound_region);
+        }
+
+        rbml_w.end_tag();
+    }
+
+    rbml_w.end_tag();
+}
+
 fn encode_method_ty_fields(ecx: &EncodeContext,
                            rbml_w: &mut Encoder,
                            method_ty: &ty::Method) {
     encode_def_id(rbml_w, method_ty.def_id);
     encode_name(rbml_w, method_ty.ident.name);
-    encode_ty_type_param_defs(rbml_w, ecx, &method_ty.generics.types,
-                              tag_item_method_tps);
+    encode_generics(rbml_w, ecx, &method_ty.generics,
+                    tag_method_ty_generics);
     encode_method_fty(ecx, rbml_w, &method_ty.fty);
     encode_visibility(rbml_w, method_ty.vis);
     encode_explicit_self(rbml_w, &method_ty.explicit_self);
@@ -982,7 +1021,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         } else {
             encode_family(rbml_w, 'c');
         }
-        encode_type(ecx, rbml_w, node_id_to_type(tcx, item.id));
+        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
         encode_symbol(ecx, rbml_w, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_path(rbml_w, path);
@@ -1222,17 +1261,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
             }
         }
       }
-      ItemTrait(_, _, ref super_traits, ref ms) => {
+      ItemTrait(_, _, _, ref ms) => {
         add_to_index(item, rbml_w, index);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, 'I');
         encode_item_variances(rbml_w, ecx, item.id);
         let trait_def = ty::lookup_trait_def(tcx, def_id);
-        encode_ty_type_param_defs(rbml_w, ecx,
-                                  &trait_def.generics.types,
-                                  tag_items_data_item_ty_param_bounds);
-        encode_region_param_defs(rbml_w, &trait_def.generics.regions);
+        encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
         encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
         encode_name(rbml_w, item.ident.name);
         encode_attributes(rbml_w, item.attrs.as_slice());
@@ -1253,13 +1289,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
             rbml_w.end_tag();
         }
         encode_path(rbml_w, path.clone());
-        // FIXME(#8559): This should use the tcx's supertrait cache instead of
-        // reading the AST's list, because the former has already filtered out
-        // the builtin-kinds-as-supertraits. See corresponding fixme in decoder.
-        for ast_trait_ref in super_traits.iter() {
-            let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
-            encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_super_trait_ref);
-        }
+
+        encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds);
 
         // Encode the implementations of this trait.
         encode_extension_implementations(ecx, rbml_w, def_id);
@@ -1390,7 +1421,8 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
         } else {
             encode_family(rbml_w, 'c');
         }
-        encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, nitem.id));
+        encode_bounds_and_type(rbml_w, ecx,
+                               &lookup_item_type(ecx.tcx,local_def(nitem.id)));
         encode_symbol(ecx, rbml_w, nitem.id);
         encode_name(rbml_w, nitem.ident.name);
       }
@@ -1434,7 +1466,7 @@ fn my_visit_foreign_item(ni: &ForeignItem,
     });
 }
 
-struct EncodeVisitor<'a,'b> {
+struct EncodeVisitor<'a,'b:'a> {
     rbml_w_for_visit_item: &'a mut Encoder<'b>,
     ecx_ptr:*const int,
     index: &'a mut Vec<entry<i64>>,
@@ -1738,7 +1770,7 @@ fn encode_unboxed_closures<'a>(
 }
 
 fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) {
-    struct StructFieldVisitor<'a, 'b> {
+    struct StructFieldVisitor<'a, 'b:'a> {
         rbml_w: &'a mut Encoder<'b>,
     }
 
@@ -1760,7 +1792,7 @@ fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) {
 
 
 
-struct ImplVisitor<'a,'b,'c> {
+struct ImplVisitor<'a,'b:'a,'c:'a> {
     ecx: &'a EncodeContext<'b>,
     rbml_w: &'a mut Encoder<'c>,
 }
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 2ef5675caa1..c18d2a7ebf4 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -147,6 +147,13 @@ pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty:
     parse_ty(&mut st, conv)
 }
 
+pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
+                         conv: conv_did) -> ty::Region {
+    debug!("parse_region_data {}", data_log_string(data, pos));
+    let mut st = parse_state_from_data(data, crate_num, pos, tcx);
+    parse_region(&mut st, conv)
+}
+
 pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
                              conv: conv_did) -> ty::BareFnTy {
     debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos));
@@ -168,6 +175,27 @@ pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx:
     parse_substs(&mut st, conv)
 }
 
+pub fn parse_bounds_data(data: &[u8], crate_num: ast::CrateNum,
+                         pos: uint, tcx: &ty::ctxt, conv: conv_did)
+                         -> ty::ParamBounds {
+    let mut st = parse_state_from_data(data, crate_num, pos, tcx);
+    parse_bounds(&mut st, conv)
+}
+
+pub fn parse_existential_bounds_data(data: &[u8], crate_num: ast::CrateNum,
+                                     pos: uint, tcx: &ty::ctxt, conv: conv_did)
+                                     -> ty::ExistentialBounds {
+    let mut st = parse_state_from_data(data, crate_num, pos, tcx);
+    parse_existential_bounds(&mut st, conv)
+}
+
+pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum,
+                                 pos: uint, tcx: &ty::ctxt, conv: conv_did)
+                                 -> ty::BuiltinBounds {
+    let mut st = parse_state_from_data(data, crate_num, pos, tcx);
+    parse_builtin_bounds(&mut st, conv)
+}
+
 fn parse_size(st: &mut PState) -> Option<uint> {
     assert_eq!(next(st), '/');
 
@@ -355,9 +383,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
         assert_eq!(next(st), '[');
         let def = parse_def(st, NominalType, |x,y| conv(x,y));
         let substs = parse_substs(st, |x,y| conv(x,y));
-        let bounds = parse_bounds(st, |x,y| conv(x,y));
+        let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
         assert_eq!(next(st), ']');
-        return ty::mk_trait(st.tcx, def, substs, bounds.builtin_bounds);
+        return ty::mk_trait(st.tcx, def, substs, bounds);
       }
       'p' => {
         let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
@@ -515,14 +543,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
     let fn_style = parse_fn_style(next(st));
     let onceness = parse_onceness(next(st));
     let store = parse_trait_store(st, |x,y| conv(x,y));
-    let bounds = parse_bounds(st, |x,y| conv(x,y));
+    let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
     let sig = parse_sig(st, |x,y| conv(x,y));
     let abi = parse_abi_set(st);
     ty::ClosureTy {
         fn_style: fn_style,
         onceness: onceness,
         store: store,
-        bounds: bounds.builtin_bounds,
+        bounds: bounds,
         sig: sig,
         abi: abi,
     }
@@ -601,7 +629,7 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
     assert_eq!(next(st), '|');
     let index = parse_uint(st);
     assert_eq!(next(st), '|');
-    let bounds = Rc::new(parse_bounds(st, |x,y| conv(x,y)));
+    let bounds = parse_bounds(st, |x,y| conv(x,y));
     let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
 
     ty::TypeParameterDef {
@@ -614,27 +642,51 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
     }
 }
 
-fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
-    let mut param_bounds = ty::ParamBounds {
-        builtin_bounds: ty::empty_builtin_bounds(),
-        trait_bounds: Vec::new()
-    };
+fn parse_existential_bounds(st: &mut PState, conv: conv_did) -> ty::ExistentialBounds {
+    let r = parse_region(st, |x,y| conv(x,y));
+    let bb = parse_builtin_bounds(st, conv);
+    return ty::ExistentialBounds { region_bound: r, builtin_bounds: bb };
+}
+
+fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds {
+    let mut builtin_bounds = ty::empty_builtin_bounds();
+
     loop {
         match next(st) {
             'S' => {
-                param_bounds.builtin_bounds.add(ty::BoundSend);
-            }
-            'O' => {
-                param_bounds.builtin_bounds.add(ty::BoundStatic);
+                builtin_bounds.add(ty::BoundSend);
             }
             'Z' => {
-                param_bounds.builtin_bounds.add(ty::BoundSized);
+                builtin_bounds.add(ty::BoundSized);
             }
             'P' => {
-                param_bounds.builtin_bounds.add(ty::BoundCopy);
+                builtin_bounds.add(ty::BoundCopy);
             }
             'T' => {
-                param_bounds.builtin_bounds.add(ty::BoundSync);
+                builtin_bounds.add(ty::BoundSync);
+            }
+            '.' => {
+                return builtin_bounds;
+            }
+            c => {
+                fail!("parse_bounds: bad builtin bounds ('{}')", c)
+            }
+        }
+    }
+}
+
+fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
+    let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y));
+
+    let mut param_bounds = ty::ParamBounds {
+        opt_region_bound: None,
+        builtin_bounds: builtin_bounds,
+        trait_bounds: Vec::new()
+    };
+    loop {
+        match next(st) {
+            'R' => {
+                param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y)));
             }
             'I' => {
                 param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))));
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 84ee49c207b..09be5094dc5 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -127,7 +127,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio
     }
 }
 
-fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
+pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
     match r {
         ty::ReLateBound(id, br) => {
             mywrite!(w, "b[{}|", id);
@@ -232,13 +232,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
         ty::ty_trait(box ty::TyTrait {
                 def_id,
                 ref substs,
-                bounds
+                ref bounds
             }) => {
             mywrite!(w, "x[{}|", (cx.ds)(def_id));
             enc_substs(w, cx, substs);
-            let bounds = ty::ParamBounds {builtin_bounds: bounds,
-                                          trait_bounds: Vec::new()};
-            enc_bounds(w, cx, &bounds);
+            enc_existential_bounds(w, cx, bounds);
             mywrite!(w, "]");
         }
         ty::ty_tup(ref ts) => {
@@ -328,9 +326,7 @@ pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy)
     enc_fn_style(w, ft.fn_style);
     enc_onceness(w, ft.onceness);
     enc_trait_store(w, cx, ft.store);
-    let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
-                                  trait_bounds: Vec::new()};
-    enc_bounds(w, cx, &bounds);
+    enc_existential_bounds(w, cx, &ft.bounds);
     enc_fn_sig(w, cx, &ft.sig);
     enc_abi(w, ft.abi);
 }
@@ -349,17 +345,32 @@ fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
     enc_ty(w, cx, fsig.output);
 }
 
-fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
-    for bound in bs.builtin_bounds.iter() {
+pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) {
+    for bound in bs.iter() {
         match bound {
             ty::BoundSend => mywrite!(w, "S"),
-            ty::BoundStatic => mywrite!(w, "O"),
             ty::BoundSized => mywrite!(w, "Z"),
             ty::BoundCopy => mywrite!(w, "P"),
             ty::BoundSync => mywrite!(w, "T"),
         }
     }
 
+    mywrite!(w, ".");
+}
+
+pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ExistentialBounds) {
+    enc_region(w, cx, bs.region_bound);
+    enc_builtin_bounds(w, cx, &bs.builtin_bounds);
+}
+
+pub fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
+    enc_builtin_bounds(w, cx, &bs.builtin_bounds);
+
+    for &r in bs.opt_region_bound.iter() {
+        mywrite!(w, "R");
+        enc_region(w, cx, r);
+    }
+
     for tp in bs.trait_bounds.iter() {
         mywrite!(w, "I");
         enc_trait_ref(w, cx, &**tp);
@@ -372,6 +383,6 @@ pub fn enc_type_param_def(w: &mut SeekableMemWriter, cx: &ctxt, v: &ty::TypePara
     mywrite!(w, "{}:{}|{}|{}|",
              token::get_ident(v.ident), (cx.ds)(v.def_id),
              v.space.to_uint(), v.index);
-    enc_bounds(w, cx, &*v.bounds);
+    enc_bounds(w, cx, &v.bounds);
     enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
 }
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 6a8ee267542..6acd79f2976 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -942,6 +942,8 @@ trait rbml_writer_helpers {
                      ecx: &e::EncodeContext,
                      pty: ty::Polytype);
     fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs);
+    fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds);
+    fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
     fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment);
     fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef);
     fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef);
@@ -1001,6 +1003,18 @@ impl<'a> rbml_writer_helpers for Encoder<'a> {
         });
     }
 
+    fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds) {
+        self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this.writer,
+                                                                    &ecx.ty_str_ctxt(),
+                                                                    bounds)));
+    }
+
+    fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) {
+        self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this.writer,
+                                                                &ecx.ty_str_ctxt(),
+                                                                bounds)));
+    }
+
     fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs) {
         self.emit_opaque(|this| Ok(tyencode::enc_substs(this.writer,
                                                            &ecx.ty_str_ctxt(),
@@ -1100,9 +1114,10 @@ impl<'a> rbml_writer_helpers for Encoder<'a> {
                         this.emit_enum_variant_arg(1, |this| idx.encode(this))
                     })
                 }
-                ty::UnsizeVtable(b, def_id, ref substs) => {
+                ty::UnsizeVtable(ref b, def_id, ref substs) => {
                     this.emit_enum_variant("UnsizeVtable", 2, 3, |this| {
-                        this.emit_enum_variant_arg(0, |this| b.encode(this));
+                        this.emit_enum_variant_arg(
+                            0, |this| Ok(this.emit_existential_bounds(ecx, b)));
                         this.emit_enum_variant_arg(1, |this| def_id.encode(this));
                         this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs)))
                     })
@@ -1131,7 +1146,7 @@ impl<'a> write_tag_and_id for Encoder<'a> {
     }
 }
 
-struct SideTableEncodingIdVisitor<'a,'b> {
+struct SideTableEncodingIdVisitor<'a,'b:'a> {
     ecx_ptr: *const libc::c_void,
     new_rbml_w: &'a mut Encoder<'b>,
 }
@@ -1380,6 +1395,7 @@ trait rbml_decoder_decoder_helpers {
                            -> ty::TypeParameterDef;
     fn read_polytype(&mut self, xcx: &ExtendedDecodeContext)
                      -> ty::Polytype;
+    fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds;
     fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
     fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
     fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
@@ -1514,6 +1530,17 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
         }).unwrap()
     }
 
+    fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds
+    {
+        self.read_opaque(|this, doc| {
+            Ok(tydecode::parse_existential_bounds_data(doc.data,
+                                                       xcx.dcx.cdata.cnum,
+                                                       doc.start,
+                                                       xcx.dcx.tcx,
+                                                       |s, a| this.convert_def_id(xcx, s, a)))
+        }).unwrap()
+    }
+
     fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs {
         self.read_opaque(|this, doc| {
             Ok(tydecode::parse_substs_data(doc.data,
@@ -1638,8 +1665,9 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
                         ty::UnsizeStruct(box uk, idx)
                     }
                     2 => {
-                        let b: ty::BuiltinBounds =
-                            this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
+                        let b =
+                            this.read_enum_variant_arg(
+                                0, |this| Ok(this.read_existential_bounds(xcx))).unwrap();
                         let def_id: ast::DefId =
                             this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
                         let substs = this.read_enum_variant_arg(2,
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 0d77b01d970..2acc92cd227 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -79,12 +79,14 @@ impl<'a> CFGBuilder<'a> {
 
     fn stmt(&mut self, stmt: Gc<ast::Stmt>, pred: CFGIndex) -> CFGIndex {
         match stmt.node {
-            ast::StmtDecl(ref decl, _) => {
-                self.decl(&**decl, pred)
+            ast::StmtDecl(ref decl, id) => {
+                let exit = self.decl(&**decl, pred);
+                self.add_node(id, [exit])
             }
 
-            ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => {
-                self.expr(expr.clone(), pred)
+            ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
+                let exit = self.expr(expr.clone(), pred);
+                self.add_node(id, [exit])
             }
 
             ast::StmtMac(..) => {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 230668e7066..5cb7651e99a 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -1018,7 +1018,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) {
     visitor.visit_pat(pat, true);
 }
 
-struct AtBindingPatternVisitor<'a,'b> {
+struct AtBindingPatternVisitor<'a,'b:'a> {
     cx: &'a MatchCheckCtxt<'b>,
 }
 
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 7c5b001354d..91c227cd5bc 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -80,11 +80,18 @@ pub trait DataFlowOperator : BitwiseOperator {
     fn initial_value(&self) -> bool;
 }
 
+#[cfg(stage0)]
 struct PropagationContext<'a, 'b, O> {
     dfcx: &'a mut DataFlowContext<'b, O>,
     changed: bool
 }
 
+#[cfg(not(stage0))]
+struct PropagationContext<'a, 'b:'a, O:'a> {
+    dfcx: &'a mut DataFlowContext<'b, O>,
+    changed: bool
+}
+
 fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
     let opt_cfgindex = index.find(&id).map(|&i|i);
     opt_cfgindex.unwrap_or_else(|| {
@@ -458,7 +465,7 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> {
         });
     }
 
-    fn pretty_print_to(&self, wr: Box<io::Writer>,
+    fn pretty_print_to(&self, wr: Box<io::Writer+'static>,
                        blk: &ast::Block) -> io::IoResult<()> {
         let mut ps = pprust::rust_printer_annotated(wr, self);
         try!(ps.cbox(pprust::indent_unit));
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index d72eeaef841..ae9a3fa6a67 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -192,10 +192,18 @@ impl OverloadedCallType {
 // supplies types from the tree. After type checking is complete, you
 // can just use the tcx as the typer.
 
+#[cfg(stage0)]
 pub struct ExprUseVisitor<'d,'t,TYPER> {
     typer: &'t TYPER,
     mc: mc::MemCategorizationContext<'t,TYPER>,
-    delegate: &'d mut Delegate,
+    delegate: &'d mut Delegate+'d,
+}
+
+#[cfg(not(stage0))]
+pub struct ExprUseVisitor<'d,'t,TYPER:'t> {
+    typer: &'t TYPER,
+    mc: mc::MemCategorizationContext<'t,TYPER>,
+    delegate: &'d mut Delegate+'d,
 }
 
 // If the TYPER results in an error, it's because the type check
diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs
index 78eeb26997d..2c79c655a99 100644
--- a/src/librustc/middle/graph.rs
+++ b/src/librustc/middle/graph.rs
@@ -64,6 +64,7 @@ pub struct EdgeIndex(pub uint);
 pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);
 
 // Use a private field here to guarantee no more instances are created:
+#[deriving(Show)]
 pub struct Direction { repr: uint }
 pub static Outgoing: Direction = Direction { repr: 0 };
 pub static Incoming: Direction = Direction { repr: 1 };
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index b96a75cba94..08dde0c0607 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -144,14 +144,17 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t
     // If this trait has builtin-kind supertraits, meet them.
     let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
     debug!("checking impl with self type {}", ty::get(self_ty).sty);
-    check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
-        span_err!(cx.tcx.sess, self_type.span, E0142,
-                  "the type `{}', which does not fulfill `{}`, cannot implement this trait",
-                  ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
-        span_note!(cx.tcx.sess, self_type.span,
-                   "types implementing this trait must fulfill `{}`",
-                   trait_def.bounds.user_string(cx.tcx));
-    });
+    check_builtin_bounds(
+        cx, self_ty, trait_def.bounds.builtin_bounds,
+        |missing| {
+            span_err!(cx.tcx.sess, self_type.span, E0142,
+                      "the type `{}', which does not fulfill `{}`, \
+                       cannot implement this trait",
+                      ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
+            span_note!(cx.tcx.sess, self_type.span,
+                       "types implementing this trait must fulfill `{}`",
+                       trait_def.bounds.user_string(cx.tcx));
+        });
 
     // If this is a destructor, check kinds.
     if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
@@ -297,17 +300,15 @@ fn with_appropriate_checker(cx: &Context,
     match ty::get(fty).sty {
         ty::ty_closure(box ty::ClosureTy {
             store: ty::UniqTraitStore,
-            bounds: mut bounds, ..
+            bounds: bounds,
+            ..
         }) => {
-            // Procs can't close over non-static references!
-            bounds.add(ty::BoundStatic);
-
-            b(|cx, fv| check_for_uniq(cx, fv, bounds))
+            b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds))
         }
 
         ty::ty_closure(box ty::ClosureTy {
             store: ty::RegionTraitStore(region, _), bounds, ..
-        }) => b(|cx, fv| check_for_block(cx, fv, bounds, region)),
+        }) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)),
 
         ty::ty_bare_fn(_) => {
             b(check_for_bare)
@@ -377,13 +378,6 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
                                                          expression_type);
 
     match e.node {
-        ExprBox(ref loc, ref interior) => {
-            let def = ty::resolve_expr(cx.tcx, &**loc);
-            if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() {
-                let interior_type = ty::expr_ty(cx.tcx, &**interior);
-                let _ = check_static(cx.tcx, interior_type, interior.span);
-            }
-        }
         ExprCast(ref source, _) => {
             let source_ty = ty::expr_ty(cx.tcx, &**source);
             let target_ty = ty::expr_ty(cx.tcx, e);
@@ -562,7 +556,6 @@ fn check_trait_cast(cx: &mut Context,
                     target_ty: ty::t,
                     span: Span,
                     method_call: MethodCall) {
-    check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
     match ty::get(target_ty).sty {
         ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
             match ty::get(ty).sty {
@@ -580,7 +573,8 @@ fn check_trait_cast(cx: &mut Context,
                                 vtable_res)
                         }
                     };
-                    check_trait_cast_bounds(cx, span, source_ty, bounds);
+                    check_trait_cast_bounds(cx, span, source_ty,
+                                            bounds.builtin_bounds);
                 }
                 _ => {}
             }
@@ -620,7 +614,7 @@ pub fn check_builtin_bounds(cx: &Context,
     let kind = ty::type_contents(cx.tcx, ty);
     let mut missing = ty::empty_builtin_bounds();
     for bound in bounds.iter() {
-        if !kind.meets_bound(cx.tcx, bound) {
+        if !kind.meets_builtin_bound(cx.tcx, bound) {
             missing.add(bound);
         }
     }
@@ -764,132 +758,6 @@ fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
     }
 }
 
-pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
-    if !ty::type_is_static(tcx, ty) {
-        match ty::get(ty).sty {
-            ty::ty_param(..) => {
-                span_err!(tcx.sess, sp, E0149,
-                    "value may contain references; \
-                     add `'static` bound to `{}`",
-                     ty_to_string(tcx, ty));
-            }
-            _ => {
-                span_err!(tcx.sess, sp, E0150,
-                    "value may contain references");
-            }
-        }
-        false
-    } else {
-        true
-    }
-}
-
-/// This is rather subtle.  When we are casting a value to an instantiated
-/// trait like `a as trait<'r>`, regionck already ensures that any references
-/// that appear in the type of `a` are bounded by `'r` (ed.: rem
-/// FIXME(#5723)).  However, it is possible that there are *type parameters*
-/// in the type of `a`, and those *type parameters* may have references
-/// within them.  We have to guarantee that the regions which appear in those
-/// type parameters are not obscured.
-///
-/// Therefore, we ensure that one of three conditions holds:
-///
-/// (1) The trait instance cannot escape the current fn.  This is
-/// guaranteed if the region bound `&r` is some scope within the fn
-/// itself.  This case is safe because whatever references are
-/// found within the type parameter, they must enclose the fn body
-/// itself.
-///
-/// (2) The type parameter appears in the type of the trait.  For
-/// example, if the type parameter is `T` and the trait type is
-/// `deque<T>`, then whatever references may appear in `T` also
-/// appear in `deque<T>`.
-///
-/// (3) The type parameter is sendable (and therefore does not contain
-/// references).
-///
-/// FIXME(#5723)---This code should probably move into regionck.
-pub fn check_cast_for_escaping_regions(
-    cx: &Context,
-    source_ty: ty::t,
-    target_ty: ty::t,
-    source_span: Span)
-{
-    // Determine what type we are casting to; if it is not a trait, then no
-    // worries.
-    if !ty::type_is_trait(target_ty) {
-        return;
-    }
-
-    // Collect up the regions that appear in the target type.  We want to
-    // ensure that these lifetimes are shorter than all lifetimes that are in
-    // the source type.  See test `src/test/compile-fail/regions-trait-2.rs`
-    let mut target_regions = Vec::new();
-    ty::walk_regions_and_ty(
-        cx.tcx,
-        target_ty,
-        |r| {
-            if !r.is_bound() {
-                target_regions.push(r);
-            }
-        },
-        |_| ());
-
-    // Check, based on the region associated with the trait, whether it can
-    // possibly escape the enclosing fn item (note that all type parameters
-    // must have been declared on the enclosing fn item).
-    if target_regions.iter().any(|r| is_ReScope(*r)) {
-        return; /* case (1) */
-    }
-
-    // Assuming the trait instance can escape, then ensure that each parameter
-    // either appears in the trait type or is sendable.
-    let target_params = ty::param_tys_in_type(target_ty);
-    ty::walk_regions_and_ty(
-        cx.tcx,
-        source_ty,
-
-        |_r| {
-            // FIXME(#5723) --- turn this check on once &Objects are usable
-            //
-            // if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
-            //     cx.tcx.sess.span_err(
-            //         source_span,
-            //         format!("source contains reference with lifetime \
-            //               not found in the target type `{}`",
-            //              ty_to_string(cx.tcx, target_ty)));
-            //     note_and_explain_region(
-            //         cx.tcx, "source data is only valid for ", r, "");
-            // }
-        },
-
-        |ty| {
-            match ty::get(ty).sty {
-                ty::ty_param(source_param) => {
-                    if source_param.space == subst::SelfSpace {
-                        // FIXME (#5723) -- there is no reason that
-                        // Self should be exempt from this check,
-                        // except for historical accident. Bottom
-                        // line, we need proper region bounding.
-                    } else if target_params.iter().any(|x| x == &source_param) {
-                        /* case (2) */
-                    } else {
-                        check_static(cx.tcx, ty, source_span); /* case (3) */
-                    }
-                }
-                _ => {}
-            }
-        });
-
-    #[allow(non_snake_case_functions)]
-    fn is_ReScope(r: ty::Region) -> bool {
-        match r {
-            ty::ReScope(..) => true,
-            _ => false
-        }
-    }
-}
-
 // Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
 fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
     if !ty::type_is_sized(tcx, ty) {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 2d052feb672..662b55ba361 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -240,10 +240,16 @@ impl ast_node for ast::Pat {
     fn span(&self) -> Span { self.span }
 }
 
+#[cfg(stage0)]
 pub struct MemCategorizationContext<'t,TYPER> {
     typer: &'t TYPER
 }
 
+#[cfg(not(stage0))]
+pub struct MemCategorizationContext<'t,TYPER:'t> {
+    typer: &'t TYPER
+}
+
 pub type McResult<T> = Result<T, ()>;
 
 /**
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 61e6debb086..42d6cee9654 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -1221,8 +1221,8 @@ struct VisiblePrivateTypesVisitor<'a> {
     public_items: &'a PublicItems,
 }
 
-struct CheckTypeForPrivatenessVisitor<'a, 'b> {
-    inner: &'b VisiblePrivateTypesVisitor<'a>,
+struct CheckTypeForPrivatenessVisitor<'a, 'b:'a> {
+    inner: &'a VisiblePrivateTypesVisitor<'b>,
     /// whether the type refers to private types.
     contains_private: bool,
     /// whether we've recurred at all (i.e. if we're pointing at the
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 1a884eaea21..11dd3eee88e 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -25,6 +25,7 @@ use driver::session::Session;
 use middle::ty::{FreeRegion};
 use middle::ty;
 use util::nodemap::NodeMap;
+use util::common::can_reach;
 
 use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
@@ -78,7 +79,7 @@ The region maps encode information about region relationships.
 pub struct RegionMaps {
     scope_map: RefCell<NodeMap<ast::NodeId>>,
     var_map: RefCell<NodeMap<ast::NodeId>>,
-    free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion> >>,
+    free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion>>>,
     rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
     terminating_scopes: RefCell<HashSet<ast::NodeId>>,
 }
@@ -255,34 +256,7 @@ impl RegionMaps {
          * (that is, the user can give two different names to the same lifetime).
          */
 
-        if sub == sup {
-            return true;
-        }
-
-        // Do a little breadth-first-search here.  The `queue` list
-        // doubles as a way to detect if we've seen a particular FR
-        // before.  Note that we expect this graph to be an *extremely
-        // shallow* tree.
-        let mut queue = vec!(sub);
-        let mut i = 0;
-        while i < queue.len() {
-            match self.free_region_map.borrow().find(queue.get(i)) {
-                Some(parents) => {
-                    for parent in parents.iter() {
-                        if *parent == sup {
-                            return true;
-                        }
-
-                        if !queue.iter().any(|x| x == parent) {
-                            queue.push(*parent);
-                        }
-                    }
-                }
-                None => {}
-            }
-            i += 1;
-        }
-        return false;
+        can_reach(&*self.free_region_map.borrow(), sub, sup)
     }
 
     pub fn is_subregion_of(&self,
@@ -300,6 +274,7 @@ impl RegionMaps {
 
         sub_region == super_region || {
             match (sub_region, super_region) {
+                (ty::ReEmpty, _) |
                 (_, ty::ReStatic) => {
                     true
                 }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index bd779b865d6..58be2c73bd9 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -30,10 +30,10 @@ use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
 use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
 use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, Method};
 use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
-use syntax::ast::{OtherRegionTyParamBound, P, Pat, PatEnum, PatIdent, PatLit};
+use syntax::ast::{P, Pat, PatEnum, PatIdent, PatLit};
 use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
 use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic};
-use syntax::ast::{StaticRegionTyParamBound, StmtDecl, StructField};
+use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
 use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
 use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
 use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
@@ -901,7 +901,7 @@ struct Resolver<'a> {
     used_imports: HashSet<(NodeId, Namespace)>,
 }
 
-struct BuildReducedGraphVisitor<'a, 'b> {
+struct BuildReducedGraphVisitor<'a, 'b:'a> {
     resolver: &'a mut Resolver<'b>,
 }
 
@@ -933,7 +933,9 @@ impl<'a, 'b> Visitor<ReducedGraphParent> for BuildReducedGraphVisitor<'a, 'b> {
 
 }
 
-struct UnusedImportCheckVisitor<'a, 'b> { resolver: &'a mut Resolver<'b> }
+struct UnusedImportCheckVisitor<'a, 'b:'a> {
+    resolver: &'a mut Resolver<'b>
+}
 
 impl<'a, 'b> Visitor<()> for UnusedImportCheckVisitor<'a, 'b> {
     fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
@@ -3946,7 +3948,7 @@ impl<'a> Resolver<'a> {
                                             impl_items.as_slice());
             }
 
-            ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
+            ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
                 // Create a new rib for the self type.
                 let self_type_rib = Rib::new(ItemRibKind);
 
@@ -3965,10 +3967,9 @@ impl<'a> Resolver<'a> {
                     this.resolve_type_parameters(&generics.ty_params);
                     this.resolve_where_clause(&generics.where_clause);
 
-                    // Resolve derived traits.
-                    for trt in traits.iter() {
-                        this.resolve_trait_reference(item.id, trt, TraitDerivation);
-                    }
+                    this.resolve_type_parameter_bounds(item.id, bounds,
+                                                       TraitDerivation);
+
                     match unbound {
                         &Some(ast::TraitTyParamBound(ref tpb)) => {
                             this.resolve_trait_reference(item.id, tpb, TraitDerivation);
@@ -4199,10 +4200,13 @@ impl<'a> Resolver<'a> {
                                type_parameters: &OwnedSlice<TyParam>) {
         for type_parameter in type_parameters.iter() {
             for bound in type_parameter.bounds.iter() {
-                self.resolve_type_parameter_bound(type_parameter.id, bound);
+                self.resolve_type_parameter_bound(type_parameter.id, bound,
+                                                  TraitBoundingTypeParameter);
             }
             match &type_parameter.unbound {
-                &Some(ref unbound) => self.resolve_type_parameter_bound(type_parameter.id, unbound),
+                &Some(ref unbound) =>
+                    self.resolve_type_parameter_bound(
+                        type_parameter.id, unbound, TraitBoundingTypeParameter),
                 &None => {}
             }
             match type_parameter.default {
@@ -4212,12 +4216,23 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    fn resolve_type_parameter_bounds(&mut self,
+                                     id: NodeId,
+                                     type_parameter_bounds: &OwnedSlice<TyParamBound>,
+                                     reference_type: TraitReferenceType) {
+        for type_parameter_bound in type_parameter_bounds.iter() {
+            self.resolve_type_parameter_bound(id, type_parameter_bound,
+                                              reference_type);
+        }
+    }
+
     fn resolve_type_parameter_bound(&mut self,
                                     id: NodeId,
-                                    type_parameter_bound: &TyParamBound) {
+                                    type_parameter_bound: &TyParamBound,
+                                    reference_type: TraitReferenceType) {
         match *type_parameter_bound {
             TraitTyParamBound(ref tref) => {
-                self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
+                self.resolve_trait_reference(id, tref, reference_type)
             }
             UnboxedFnTyParamBound(ref unboxed_function) => {
                 for argument in unboxed_function.decl.inputs.iter() {
@@ -4226,7 +4241,7 @@ impl<'a> Resolver<'a> {
 
                 self.resolve_type(&*unboxed_function.decl.output);
             }
-            StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
+            RegionTyParamBound(..) => {}
         }
     }
 
@@ -4240,7 +4255,7 @@ impl<'a> Resolver<'a> {
                 let usage_str = match reference_type {
                     TraitBoundingTypeParameter => "bound type parameter with",
                     TraitImplementation        => "implement",
-                    TraitDerivation            => "derive"
+                    TraitDerivation            => "derive",
                 };
 
                 let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@@ -4295,7 +4310,8 @@ impl<'a> Resolver<'a> {
             }
 
             for bound in predicate.bounds.iter() {
-                self.resolve_type_parameter_bound(predicate.id, bound);
+                self.resolve_type_parameter_bound(predicate.id, bound,
+                                                  TraitBoundingTypeParameter);
             }
         }
     }
@@ -4679,18 +4695,14 @@ impl<'a> Resolver<'a> {
                 }
 
                 bounds.as_ref().map(|bound_vec| {
-                    for bound in bound_vec.iter() {
-                        self.resolve_type_parameter_bound(ty.id, bound);
-                    }
+                    self.resolve_type_parameter_bounds(ty.id, bound_vec,
+                                                       TraitBoundingTypeParameter);
                 });
             }
 
-            TyClosure(c, _) | TyProc(c) => {
-                c.bounds.as_ref().map(|bounds| {
-                    for bound in bounds.iter() {
-                        self.resolve_type_parameter_bound(ty.id, bound);
-                    }
-                });
+            TyClosure(c) | TyProc(c) => {
+                self.resolve_type_parameter_bounds(ty.id, &c.bounds,
+                                                   TraitBoundingTypeParameter);
                 visit::walk_ty(self, ty, ());
             }
 
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index abb67a6503e..1bc37e2f1e4 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -21,7 +21,6 @@ use driver::session::Session;
 use middle::subst;
 use syntax::ast;
 use syntax::codemap::Span;
-use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token::special_idents;
 use syntax::parse::token;
 use syntax::print::pprust::{lifetime_to_string};
@@ -99,8 +98,10 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
             ast::ItemStruct(_, ref generics) |
             ast::ItemImpl(ref generics, _, _, _) |
             ast::ItemTrait(ref generics, _, _, _) => {
-                self.check_lifetime_names(&generics.lifetimes);
-                EarlyScope(subst::TypeSpace, &generics.lifetimes, &root)
+                let scope: ScopeChain =
+                    EarlyScope(subst::TypeSpace, &generics.lifetimes, &root);
+                self.check_lifetime_defs(&generics.lifetimes, &scope);
+                scope
             }
         };
         debug!("entering scope {:?}", scope);
@@ -126,7 +127,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
 
     fn visit_ty(&mut self, ty: &ast::Ty, scope: Scope<'a>) {
         match ty.node {
-            ast::TyClosure(c, _) | ast::TyProc(c) => {
+            ast::TyClosure(c) | ast::TyProc(c) => {
                 push_fn_scope(self, ty, scope, &c.lifetimes);
             }
             ast::TyBareFn(c) => push_fn_scope(self, ty, scope, &c.lifetimes),
@@ -137,8 +138,8 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
                          ty: &ast::Ty,
                          scope: Scope,
                          lifetimes: &Vec<ast::LifetimeDef>) {
-            let scope1 = LateScope(ty.id, lifetimes, scope);
-            this.check_lifetime_names(lifetimes);
+            let scope1: ScopeChain = LateScope(ty.id, lifetimes, scope);
+            this.check_lifetime_defs(lifetimes, &scope1);
             debug!("pushing fn scope id={} due to type", ty.id);
             visit::walk_ty(this, ty, &scope1);
             debug!("popping fn scope id={} due to type", ty.id);
@@ -204,24 +205,22 @@ impl<'a> LifetimeContext<'a> {
          * the ordering is not important there.
          */
 
-        self.check_lifetime_names(&generics.lifetimes);
-
-        let referenced_idents = free_lifetimes(&generics.ty_params,
-                                               &generics.where_clause);
+        let referenced_idents = early_bound_lifetime_names(generics);
         debug!("pushing fn scope id={} due to fn item/method\
                referenced_idents={:?}",
                n,
                referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
         if referenced_idents.is_empty() {
-            let scope1 = LateScope(n, &generics.lifetimes, scope);
-            walk(self, &scope1)
+            let scope1: ScopeChain = LateScope(n, &generics.lifetimes, scope);
+            self.check_lifetime_defs(&generics.lifetimes, &scope1);
+            walk(self, &scope1);
         } else {
             let (early, late) = generics.lifetimes.clone().partition(
                 |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
 
             let scope1 = EarlyScope(subst::FnSpace, &early, scope);
-            let scope2 = LateScope(n, &late, &scope1);
-
+            let scope2: ScopeChain = LateScope(n, &late, &scope1);
+            self.check_lifetime_defs(&generics.lifetimes, &scope2);
             walk(self, &scope2);
         }
         debug!("popping fn scope id={} due to fn item/method", n);
@@ -335,7 +334,9 @@ impl<'a> LifetimeContext<'a> {
                     token::get_name(lifetime_ref.name)).as_slice());
     }
 
-    fn check_lifetime_names(&self, lifetimes: &Vec<ast::LifetimeDef>) {
+    fn check_lifetime_defs<'b>(&mut self,
+                               lifetimes: &Vec<ast::LifetimeDef>,
+                               scope: Scope<'b>) {
         for i in range(0, lifetimes.len()) {
             let lifetime_i = lifetimes.get(i);
 
@@ -364,11 +365,7 @@ impl<'a> LifetimeContext<'a> {
             }
 
             for bound in lifetime_i.bounds.iter() {
-                if !self.sess.features.issue_5723_bootstrap.get() {
-                    self.sess.span_err(
-                        bound.span,
-                        "region bounds require `issue_5723_bootstrap`");
-                }
+                self.resolve_lifetime_ref(bound, scope);
             }
         }
     }
@@ -404,8 +401,7 @@ fn search_lifetimes(lifetimes: &Vec<ast::LifetimeDef>,
 ///////////////////////////////////////////////////////////////////////////
 
 pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
-    let referenced_idents = free_lifetimes(&generics.ty_params,
-                                           &generics.where_clause);
+    let referenced_idents = early_bound_lifetime_names(generics);
     if referenced_idents.is_empty() {
         return Vec::new();
     }
@@ -416,34 +412,72 @@ pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::Lifeti
         .collect()
 }
 
-pub fn free_lifetimes(ty_params: &OwnedSlice<ast::TyParam>,
-                      where_clause: &ast::WhereClause)
-                      -> Vec<ast::Name> {
+fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
     /*!
-     * Gathers up and returns the names of any lifetimes that appear
-     * free in `ty_params`. Of course, right now, all lifetimes appear
-     * free, since we don't currently have any binders in type parameter
-     * declarations; just being forwards compatible with future extensions.
+     * Given a set of generic declarations, returns a list of names
+     * containing all early bound lifetime names for those
+     * generics. (In fact, this list may also contain other names.)
      */
 
-    let mut collector = FreeLifetimeCollector { names: vec!() };
-    for ty_param in ty_params.iter() {
-        visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
+    // Create two lists, dividing the lifetimes into early/late bound.
+    // Initially, all of them are considered late, but we will move
+    // things from late into early as we go if we find references to
+    // them.
+    let mut early_bound = Vec::new();
+    let mut late_bound = generics.lifetimes.iter()
+                                           .map(|l| l.lifetime.name)
+                                           .collect();
+
+    // Any lifetime that appears in a type bound is early.
+    {
+        let mut collector =
+            FreeLifetimeCollector { early_bound: &mut early_bound,
+                                    late_bound: &mut late_bound };
+        for ty_param in generics.ty_params.iter() {
+            visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
+        }
+        for predicate in generics.where_clause.predicates.iter() {
+            visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
+        }
     }
-    for predicate in where_clause.predicates.iter() {
-        visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
+
+    // Any lifetime that either has a bound or is referenced by a
+    // bound is early.
+    for lifetime_def in generics.lifetimes.iter() {
+        if !lifetime_def.bounds.is_empty() {
+            shuffle(&mut early_bound, &mut late_bound,
+                    lifetime_def.lifetime.name);
+            for bound in lifetime_def.bounds.iter() {
+                shuffle(&mut early_bound, &mut late_bound,
+                        bound.name);
+            }
+        }
     }
-    return collector.names;
+    return early_bound;
 
-    struct FreeLifetimeCollector {
-        names: Vec<ast::Name>,
+    struct FreeLifetimeCollector<'a> {
+        early_bound: &'a mut Vec<ast::Name>,
+        late_bound: &'a mut Vec<ast::Name>,
     }
 
-    impl Visitor<()> for FreeLifetimeCollector {
+    impl<'a> Visitor<()> for FreeLifetimeCollector<'a> {
         fn visit_lifetime_ref(&mut self,
                               lifetime_ref: &ast::Lifetime,
                               _: ()) {
-            self.names.push(lifetime_ref.name);
+            shuffle(self.early_bound, self.late_bound,
+                    lifetime_ref.name);
+        }
+    }
+
+    fn shuffle(early_bound: &mut Vec<ast::Name>,
+               late_bound: &mut Vec<ast::Name>,
+               name: ast::Name) {
+        match late_bound.iter().position(|n| *n == name) {
+            Some(index) => {
+                late_bound.swap_remove(index);
+                early_bound.push(name);
+            }
+            None => { }
         }
     }
 }
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index 11b16f18533..cd3f47e8b2f 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -50,6 +50,7 @@ use syntax::attr;
 use syntax::codemap::*;
 use syntax::parse::token;
 use syntax::parse::token::{get_ident,keywords};
+use syntax::owned_slice::OwnedSlice;
 use syntax::visit;
 use syntax::visit::Visitor;
 use syntax::print::pprust::{path_to_string,ty_to_string};
@@ -653,7 +654,7 @@ impl <'l> DxrVisitor<'l> {
                      item: &ast::Item,
                      e: DxrVisitorEnv,
                      generics: &ast::Generics,
-                     trait_refs: &Vec<ast::TraitRef>,
+                     trait_refs: &OwnedSlice<ast::TyParamBound>,
                      methods: &Vec<ast::TraitItem>) {
         let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
 
@@ -665,7 +666,16 @@ impl <'l> DxrVisitor<'l> {
                            e.cur_scope);
 
         // super-traits
-        for trait_ref in trait_refs.iter() {
+        for super_bound in trait_refs.iter() {
+            let trait_ref = match *super_bound {
+                ast::TraitTyParamBound(ref trait_ref) => {
+                    trait_ref
+                }
+                ast::UnboxedFnTyParamBound(..) | ast::RegionTyParamBound(..) => {
+                    continue;
+                }
+            };
+
             match self.lookup_type_ref(trait_ref.ref_id) {
                 Some(id) => {
                     let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
@@ -1499,7 +1509,7 @@ pub fn process_crate(sess: &Session,
                                   collected_paths: vec!(),
                                   collecting: false,
                                   fmt: FmtStrs::new(box Recorder {
-                                                        out: output_file as Box<Writer>,
+                                                        out: output_file as Box<Writer+'static>,
                                                         dump_spans: false,
                                                     },
                                                     SpanUtils {
diff --git a/src/librustc/middle/save/recorder.rs b/src/librustc/middle/save/recorder.rs
index 1af6fde02af..0695b6b360c 100644
--- a/src/librustc/middle/save/recorder.rs
+++ b/src/librustc/middle/save/recorder.rs
@@ -19,7 +19,7 @@ use syntax::codemap::*;
 
 pub struct Recorder {
     // output file
-    pub out: Box<Writer>,
+    pub out: Box<Writer+'static>,
     pub dump_spans: bool,
 }
 
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index ccc4dbb21e0..d992e840b46 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -611,7 +611,7 @@ impl<'a> TypeFolder for SubstFolder<'a> {
 
         let t1 = match ty::get(t).sty {
             ty::ty_param(p) => {
-                check(self, t, self.substs.types.opt_get(p.space, p.idx))
+                check(self, p, t, self.substs.types.opt_get(p.space, p.idx))
             }
             _ => {
                 ty_fold::super_fold_ty(self, t)
@@ -627,6 +627,7 @@ impl<'a> TypeFolder for SubstFolder<'a> {
         return t1;
 
         fn check(this: &SubstFolder,
+                 p: ty::ParamTy,
                  source_ty: ty::t,
                  opt_ty: Option<&ty::t>)
                  -> ty::t {
@@ -636,8 +637,9 @@ impl<'a> TypeFolder for SubstFolder<'a> {
                     let span = this.span.unwrap_or(DUMMY_SP);
                     this.tcx().sess.span_bug(
                         span,
-                        format!("Type parameter {} out of range \
+                        format!("Type parameter `{}` ({}) out of range \
                                  when substituting (root type={})",
+                                p.repr(this.tcx()),
                                 source_ty.repr(this.tcx()),
                                 this.root_ty.repr(this.tcx())).as_slice());
                 }
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 28f396c8bf7..bbd6c252849 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -340,6 +340,15 @@ struct ArmData<'a, 'b> {
  * As we proceed `bound_ptrs` are filled with pointers to values to be bound,
  * these pointers are stored in llmatch variables just before executing `data` arm.
  */
+#[cfg(not(stage0))]
+struct Match<'a, 'b:'a> {
+    pats: Vec<Gc<ast::Pat>>,
+    data: &'a ArmData<'a, 'b>,
+    bound_ptrs: Vec<(Ident, ValueRef)>
+}
+
+///Dox
+#[cfg(stage0)]
 struct Match<'a, 'b> {
     pats: Vec<Gc<ast::Pat>>,
     data: &'a ArmData<'a, 'b>,
diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs
index cf2410f6571..b36887c80e9 100644
--- a/src/librustc/middle/trans/cleanup.rs
+++ b/src/librustc/middle/trans/cleanup.rs
@@ -25,7 +25,6 @@ use middle::ty;
 use syntax::ast;
 use util::ppaux::Repr;
 
-
 pub struct CleanupScope<'a> {
     // The id of this cleanup scope. If the id is None,
     // this is a *temporary scope* that is pushed during trans to
@@ -35,7 +34,7 @@ pub struct CleanupScope<'a> {
     kind: CleanupScopeKind<'a>,
 
     // Cleanups to run upon scope exit.
-    cleanups: Vec<Box<Cleanup>>,
+    cleanups: Vec<CleanupObj>,
 
     cached_early_exits: Vec<CachedEarlyExit>,
     cached_landing_pad: Option<BasicBlockRef>,
@@ -73,6 +72,8 @@ pub trait Cleanup {
     fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a>;
 }
 
+pub type CleanupObj = Box<Cleanup+'static>;
+
 pub enum ScopeId {
     AstScope(ast::NodeId),
     CustomScope(CustomScopeIndex)
@@ -238,7 +239,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
                cleanup_scope,
                self.ccx.tn.val_to_string(val));
 
-        self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
+        self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
 
     fn schedule_drop_mem(&self,
@@ -264,7 +265,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
                self.ccx.tn.val_to_string(val),
                ty.repr(self.ccx.tcx()));
 
-        self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
+        self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
 
     fn schedule_drop_and_zero_mem(&self,
@@ -291,7 +292,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
                ty.repr(self.ccx.tcx()),
                true);
 
-        self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
+        self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
 
     fn schedule_drop_immediate(&self,
@@ -316,7 +317,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
                self.ccx.tn.val_to_string(val),
                ty.repr(self.ccx.tcx()));
 
-        self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
+        self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
 
     fn schedule_free_value(&self,
@@ -336,12 +337,12 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
                self.ccx.tn.val_to_string(val),
                heap);
 
-        self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
+        self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
 
     fn schedule_clean(&self,
                       cleanup_scope: ScopeId,
-                      cleanup: Box<Cleanup>) {
+                      cleanup: CleanupObj) {
         match cleanup_scope {
             AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup),
             CustomScope(id) => self.schedule_clean_in_custom_scope(id, cleanup),
@@ -350,7 +351,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
 
     fn schedule_clean_in_ast_scope(&self,
                                    cleanup_scope: ast::NodeId,
-                                   cleanup: Box<Cleanup>) {
+                                   cleanup: CleanupObj) {
         /*!
          * Schedules a cleanup to occur upon exit from `cleanup_scope`.
          * If `cleanup_scope` is not provided, then the cleanup is scheduled
@@ -378,7 +379,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
 
     fn schedule_clean_in_custom_scope(&self,
                                       custom_scope: CustomScopeIndex,
-                                      cleanup: Box<Cleanup>) {
+                                      cleanup: CleanupObj) {
         /*!
          * Schedules a cleanup to occur in the top-most scope,
          * which must be a temporary scope.
@@ -1021,13 +1022,13 @@ pub trait CleanupMethods<'a> {
                            content_ty: ty::t);
     fn schedule_clean(&self,
                       cleanup_scope: ScopeId,
-                      cleanup: Box<Cleanup>);
+                      cleanup: CleanupObj);
     fn schedule_clean_in_ast_scope(&self,
                                    cleanup_scope: ast::NodeId,
-                                   cleanup: Box<Cleanup>);
+                                   cleanup: CleanupObj);
     fn schedule_clean_in_custom_scope(&self,
                                     custom_scope: CustomScopeIndex,
-                                    cleanup: Box<Cleanup>);
+                                    cleanup: CleanupObj);
     fn needs_invoke(&self) -> bool;
     fn get_landing_pad(&'a self) -> BasicBlockRef;
 }
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 566f71220b0..26973910400 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -498,9 +498,8 @@ impl TypeMap {
 
                 unique_type_id.push_char(':');
 
-                for bound in bounds.iter() {
+                for bound in bounds.builtin_bounds.iter() {
                     match bound {
-                        ty::BoundStatic => unique_type_id.push_str("'static"),
                         ty::BoundSend => unique_type_id.push_str("Send"),
                         ty::BoundSized => unique_type_id.push_str("Sized"),
                         ty::BoundCopy => unique_type_id.push_str("Copy"),
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 56841cd4044..24c939dc3be 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -35,7 +35,7 @@ use middle::trans::tvec;
 use middle::trans::type_::Type;
 use middle::trans::type_of::{type_of, sizing_type_of, align_of};
 use middle::ty;
-use util::ppaux::ty_to_short_str;
+use util::ppaux::{ty_to_short_str, Repr};
 use util::ppaux;
 
 use arena::TypedArena;
@@ -131,6 +131,7 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
 pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
                -> &'a Block<'a> {
     // NB: v is an *alias* of type t here, not a direct value.
+    debug!("drop_ty(t={})", t.repr(bcx.tcx()));
     let _icx = push_ctxt("drop_ty");
     if ty::type_needs_drop(bcx.tcx(), t) {
         let ccx = bcx.ccx();
@@ -213,6 +214,7 @@ fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
     let _icx = push_ctxt("make_visit_glue");
     let mut bcx = bcx;
     let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
+                                                                 ty::ReStatic,
                                                                  ty::ReStatic) {
         Ok(pair) => pair,
         Err(s) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 2d3096d13ea..c2d0d27be6d 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -273,7 +273,7 @@ pub enum UnsizeKind {
     // An unsize coercion applied to the tail field of a struct.
     // The uint is the index of the type parameter which is unsized.
     UnsizeStruct(Box<UnsizeKind>, uint),
-    UnsizeVtable(ty::BuiltinBounds,
+    UnsizeVtable(ty::ExistentialBounds,
                  ast::DefId, /* Trait ID */
                  subst::Substs /* Trait substitutions */)
 }
@@ -464,7 +464,6 @@ pub struct ctxt {
     pub lang_items: middle::lang_items::LanguageItems,
     /// A mapping of fake provided method def_ids to the default implementation
     pub provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
-    pub supertraits: RefCell<DefIdMap<Rc<Vec<Rc<TraitRef>>>>>,
     pub superstructs: RefCell<DefIdMap<Option<ast::DefId>>>,
     pub struct_fields: RefCell<DefIdMap<Rc<Vec<field_ty>>>>,
 
@@ -620,7 +619,7 @@ pub struct ClosureTy {
     pub fn_style: ast::FnStyle,
     pub onceness: ast::Onceness,
     pub store: TraitStore,
-    pub bounds: BuiltinBounds,
+    pub bounds: ExistentialBounds,
     pub sig: FnSig,
     pub abi: abi::Abi,
 }
@@ -932,7 +931,7 @@ pub enum sty {
 pub struct TyTrait {
     pub def_id: DefId,
     pub substs: Substs,
-    pub bounds: BuiltinBounds
+    pub bounds: ExistentialBounds
 }
 
 #[deriving(PartialEq, Eq, Hash, Show)]
@@ -995,18 +994,30 @@ pub enum type_err {
     terr_variadic_mismatch(expected_found<bool>)
 }
 
-#[deriving(PartialEq, Eq, Hash, Show)]
+/// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
+/// as well as the existential type parameter in an object type.
+#[deriving(PartialEq, Eq, Hash, Clone, Show)]
 pub struct ParamBounds {
+    pub opt_region_bound: Option<ty::Region>,
     pub builtin_bounds: BuiltinBounds,
     pub trait_bounds: Vec<Rc<TraitRef>>
 }
 
+/// Bounds suitable for an existentially quantified type parameter
+/// such as those that appear in object types or closure types. The
+/// major difference between this case and `ParamBounds` is that
+/// general purpose trait bounds are omitted.
+#[deriving(PartialEq, Eq, Hash, Clone, Show)]
+pub struct ExistentialBounds {
+    pub region_bound: ty::Region,
+    pub builtin_bounds: BuiltinBounds
+}
+
 pub type BuiltinBounds = EnumSet<BuiltinBound>;
 
 #[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)]
 #[repr(uint)]
 pub enum BuiltinBound {
-    BoundStatic,
     BoundSend,
     BoundSized,
     BoundCopy,
@@ -1019,13 +1030,21 @@ pub fn empty_builtin_bounds() -> BuiltinBounds {
 
 pub fn all_builtin_bounds() -> BuiltinBounds {
     let mut set = EnumSet::empty();
-    set.add(BoundStatic);
     set.add(BoundSend);
     set.add(BoundSized);
     set.add(BoundSync);
     set
 }
 
+pub fn region_existential_bound(r: ty::Region) -> ExistentialBounds {
+    /*!
+     * An existential bound that does not implement any traits.
+     */
+
+    ty::ExistentialBounds { region_bound: r,
+                            builtin_bounds: empty_builtin_bounds() }
+}
+
 impl CLike for BuiltinBound {
     fn to_uint(&self) -> uint {
         *self as uint
@@ -1141,8 +1160,8 @@ pub struct TypeParameterDef {
     pub def_id: ast::DefId,
     pub space: subst::ParamSpace,
     pub index: uint,
-    pub bounds: Rc<ParamBounds>,
-    pub default: Option<ty::t>
+    pub bounds: ParamBounds,
+    pub default: Option<ty::t>,
 }
 
 #[deriving(Encodable, Decodable, Clone, Show)]
@@ -1151,6 +1170,7 @@ pub struct RegionParameterDef {
     pub def_id: ast::DefId,
     pub space: subst::ParamSpace,
     pub index: uint,
+    pub bounds: Vec<ty::Region>,
 }
 
 /// Information about the type/lifetime parameters associated with an
@@ -1198,6 +1218,12 @@ pub struct ParameterEnvironment {
 
     /// Bounds on the various type parameters
     pub bounds: VecPerParamSpace<ParamBounds>,
+
+    /// Each type parameter has an implicit region bound that
+    /// indicates it must outlive at least the function body (the user
+    /// may specify stronger requirements). This field indicates the
+    /// region of the callee.
+    pub implicit_region_bound: ty::Region,
 }
 
 impl ParameterEnvironment {
@@ -1292,7 +1318,7 @@ pub struct Polytype {
 /// As `Polytype` but for a trait ref.
 pub struct TraitDef {
     pub generics: Generics,
-    pub bounds: BuiltinBounds,
+    pub bounds: ParamBounds,
     pub trait_ref: Rc<ty::TraitRef>,
 }
 
@@ -1382,7 +1408,6 @@ pub fn mk_ctxt(s: Session,
         normalized_cache: RefCell::new(HashMap::new()),
         lang_items: lang_items,
         provided_method_sources: RefCell::new(DefIdMap::new()),
-        supertraits: RefCell::new(DefIdMap::new()),
         superstructs: RefCell::new(DefIdMap::new()),
         struct_fields: RefCell::new(DefIdMap::new()),
         destructor_for_type: RefCell::new(DefIdMap::new()),
@@ -1459,6 +1484,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
         }
         return f;
     }
+    fn flags_for_bounds(bounds: &ExistentialBounds) -> uint {
+        rflags(bounds.region_bound)
+    }
     match &st {
       &ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
       &ty_str => {}
@@ -1483,8 +1511,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
       &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
           flags |= sflags(substs);
       }
-      &ty_trait(box ty::TyTrait { ref substs, .. }) => {
+      &ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => {
           flags |= sflags(substs);
+          flags |= flags_for_bounds(bounds);
       }
       &ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
         flags |= get(tt).flags
@@ -1514,6 +1543,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
         flags |= get(f.sig.output).flags;
         // T -> _|_ is *not* _|_ !
         flags &= !(has_ty_bot as uint);
+        flags |= flags_for_bounds(&f.bounds);
       }
     }
 
@@ -1711,8 +1741,8 @@ pub fn mk_ctor_fn(cx: &ctxt,
 pub fn mk_trait(cx: &ctxt,
                 did: ast::DefId,
                 substs: Substs,
-                bounds: BuiltinBounds)
-             -> t {
+                bounds: ExistentialBounds)
+                -> t {
     // take a copy of substs so that we own the vectors inside
     let inner = box TyTrait {
         def_id: did,
@@ -1800,6 +1830,27 @@ pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|)
                                    |t| { fldt(t); t }).fold_ty(ty)
 }
 
+impl ParamTy {
+    pub fn new(space: subst::ParamSpace,
+               index: uint,
+               def_id: ast::DefId)
+               -> ParamTy {
+        ParamTy { space: space, idx: index, def_id: def_id }
+    }
+
+    pub fn for_self(trait_def_id: ast::DefId) -> ParamTy {
+        ParamTy::new(subst::SelfSpace, 0, trait_def_id)
+    }
+
+    pub fn for_def(def: &TypeParameterDef) -> ParamTy {
+        ParamTy::new(def.space, def.index, def.def_id)
+    }
+
+    pub fn to_ty(self, tcx: &ty::ctxt) -> ty::t {
+        ty::mk_param(tcx, self.space, self.idx, self.def_id)
+    }
+}
+
 impl ItemSubsts {
     pub fn empty() -> ItemSubsts {
         ItemSubsts { substs: Substs::empty() }
@@ -2115,9 +2166,6 @@ def_type_content_sets!(
         //       that it neither reaches nor owns a managed pointer.
         Nonsendable                         = 0b0000_0111__0000_0100__0000,
 
-        // Things that prevent values from being considered 'static
-        Nonstatic                           = 0b0000_0010__0000_0000__0000,
-
         // Things that prevent values from being considered sized
         Nonsized                            = 0b0000_0000__0000_0000__0001,
 
@@ -2142,9 +2190,8 @@ def_type_content_sets!(
 )
 
 impl TypeContents {
-    pub fn meets_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
+    pub fn meets_builtin_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
         match bb {
-            BoundStatic => self.is_static(cx),
             BoundSend => self.is_sendable(cx),
             BoundSized => self.is_sized(cx),
             BoundCopy => self.is_copy(cx),
@@ -2160,10 +2207,6 @@ impl TypeContents {
         (self.bits & tc.bits) != 0
     }
 
-    pub fn is_static(&self, _: &ctxt) -> bool {
-        !self.intersects(TC::Nonstatic)
-    }
-
     pub fn is_sendable(&self, _: &ctxt) -> bool {
         !self.intersects(TC::Nonsendable)
     }
@@ -2272,10 +2315,6 @@ impl fmt::Show for TypeContents {
     }
 }
 
-pub fn type_is_static(cx: &ctxt, t: ty::t) -> bool {
-    type_contents(cx, t).is_static(cx)
-}
-
 pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool {
     type_contents(cx, t).is_sendable(cx)
 }
@@ -2482,10 +2521,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
 
                 let ty_param_defs = cx.ty_param_defs.borrow();
                 let tp_def = ty_param_defs.get(&p.def_id.node);
-                kind_bounds_to_contents(cx,
-                                        tp_def.bounds.builtin_bounds,
-                                        tp_def.bounds.trait_bounds.as_slice())
-           }
+                kind_bounds_to_contents(
+                    cx,
+                    tp_def.bounds.builtin_bounds,
+                    tp_def.bounds.trait_bounds.as_slice())
+            }
 
             ty_infer(_) => {
                 // This occurs during coherence, but shouldn't occur at other
@@ -2577,10 +2617,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
     }
 
     fn object_contents(cx: &ctxt,
-                       bounds: BuiltinBounds)
+                       bounds: ExistentialBounds)
                        -> TypeContents {
         // These are the type contents of the (opaque) interior
-        kind_bounds_to_contents(cx, bounds, [])
+        kind_bounds_to_contents(cx, bounds.builtin_bounds, [])
     }
 
     fn kind_bounds_to_contents(cx: &ctxt,
@@ -2591,7 +2631,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
         let mut tc = TC::All;
         each_inherited_builtin_bound(cx, bounds, traits, |bound| {
             tc = tc - match bound {
-                BoundStatic => TC::Nonstatic,
                 BoundSend => TC::Nonsendable,
                 BoundSized => TC::Nonsized,
                 BoundCopy => TC::Noncopy,
@@ -2612,7 +2651,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
 
             each_bound_trait_and_supertraits(cx, traits, |trait_ref| {
                 let trait_def = lookup_trait_def(cx, trait_ref.def_id);
-                for bound in trait_def.bounds.iter() {
+                for bound in trait_def.bounds.builtin_bounds.iter() {
                     f(bound);
                 }
                 true
@@ -3272,16 +3311,19 @@ pub fn adjust_ty(cx: &ctxt,
                 AutoAddEnv(store) => {
                     match ty::get(unadjusted_ty).sty {
                         ty::ty_bare_fn(ref b) => {
+                            let bounds = ty::ExistentialBounds {
+                                region_bound: ReStatic,
+                                builtin_bounds: all_builtin_bounds(),
+                            };
+
                             ty::mk_closure(
                                 cx,
-                                ty::ClosureTy {
-                                    fn_style: b.fn_style,
-                                    onceness: ast::Many,
-                                    store: store,
-                                    bounds: ty::all_builtin_bounds(),
-                                    sig: b.sig.clone(),
-                                    abi: b.abi,
-                                })
+                                ty::ClosureTy {fn_style: b.fn_style,
+                                               onceness: ast::Many,
+                                               store: store,
+                                               bounds: bounds,
+                                               sig: b.sig.clone(),
+                                               abi: b.abi})
                         }
                         ref b => {
                             cx.sess.bug(
@@ -3920,30 +3962,6 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
     }
 }
 
-pub fn trait_supertraits(cx: &ctxt, id: ast::DefId) -> Rc<Vec<Rc<TraitRef>>> {
-    // Check the cache.
-    match cx.supertraits.borrow().find(&id) {
-        Some(trait_refs) => { return trait_refs.clone(); }
-        None => {}  // Continue.
-    }
-
-    // Not in the cache. It had better be in the metadata, which means it
-    // shouldn't be local.
-    assert!(!is_local(id));
-
-    // Get the supertraits out of the metadata and create the
-    // TraitRef for each.
-    let result = Rc::new(csearch::get_supertraits(cx, id));
-    cx.supertraits.borrow_mut().insert(id, result.clone());
-    result
-}
-
-pub fn trait_ref_supertraits(cx: &ctxt, trait_ref: &ty::TraitRef) -> Vec<Rc<TraitRef>> {
-    let supertrait_refs = trait_supertraits(cx, trait_ref.def_id);
-    supertrait_refs.iter().map(
-        |supertrait_ref| supertrait_ref.subst(cx, &trait_ref.substs)).collect()
-}
-
 fn lookup_locally_or_in_crate_store<V:Clone>(
                                     descr: &str,
                                     def_id: ast::DefId,
@@ -4055,9 +4073,12 @@ pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId {
     def.def_id()
 }
 
-pub fn try_add_builtin_trait(tcx: &ctxt,
-                             trait_def_id: ast::DefId,
-                             builtin_bounds: &mut BuiltinBounds) -> bool {
+pub fn try_add_builtin_trait(
+    tcx: &ctxt,
+    trait_def_id: ast::DefId,
+    builtin_bounds: &mut EnumSet<BuiltinBound>)
+    -> bool
+{
     //! Checks whether `trait_ref` refers to one of the builtin
     //! traits, like `Send`, and adds the corresponding
     //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
@@ -4343,6 +4364,18 @@ pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc<ty::TraitDef> {
     }
 }
 
+/// Given a reference to a trait, returns the bounds declared on the
+/// trait, with appropriate substitutions applied.
+pub fn bounds_for_trait_ref(tcx: &ctxt,
+                            trait_ref: &TraitRef)
+                            -> ty::ParamBounds
+{
+    let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
+    debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})",
+           trait_def.repr(tcx), trait_ref.repr(tcx));
+    trait_def.bounds.subst(tcx, &trait_ref.substs)
+}
+
 /// Iterate over attributes of a definition.
 // (This should really be an iterator, but that would require csearch and
 // decoder to use iterators instead of higher-order functions.)
@@ -4410,14 +4443,10 @@ pub fn lookup_field_type(tcx: &ctxt,
         node_id_to_type(tcx, id.node)
     } else {
         let mut tcache = tcx.tcache.borrow_mut();
-        match tcache.find(&id) {
-           Some(&Polytype {ty, ..}) => ty,
-           None => {
-               let tpt = csearch::get_field_type(tcx, struct_id, id);
-               tcache.insert(id, tpt.clone());
-               tpt.ty
-           }
-        }
+        let pty = tcache.find_or_insert_with(id, |_| {
+            csearch::get_field_type(tcx, struct_id, id)
+        });
+        pty.ty
     };
     t.subst(tcx, substs)
 }
@@ -4745,9 +4774,10 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
             }
 
             // Add supertraits to supertrait_set
-            let supertrait_refs = trait_ref_supertraits(tcx,
-                                                        &**trait_refs.get(i));
-            for supertrait_ref in supertrait_refs.iter() {
+            let trait_ref = trait_refs.get(i).clone();
+            let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
+            for supertrait_ref in trait_def.bounds.trait_bounds.iter() {
+                let supertrait_ref = supertrait_ref.subst(tcx, &trait_ref.substs);
                 debug!("each_bound_trait_and_supertraits(supertrait_ref={})",
                        supertrait_ref.repr(tcx));
 
@@ -4765,6 +4795,61 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
     return true;
 }
 
+pub fn required_region_bounds(tcx: &ctxt,
+                              region_bounds: &[ty::Region],
+                              builtin_bounds: BuiltinBounds,
+                              trait_bounds: &[Rc<TraitRef>])
+                              -> Vec<ty::Region>
+{
+    /*!
+     * Given a type which must meet the builtin bounds and trait
+     * bounds, returns a set of lifetimes which the type must outlive.
+     *
+     * Requires that trait definitions have been processed.
+     */
+
+    let mut all_bounds = Vec::new();
+
+    debug!("required_region_bounds(builtin_bounds={}, trait_bounds={})",
+           builtin_bounds.repr(tcx),
+           trait_bounds.repr(tcx));
+
+    all_bounds.push_all(region_bounds);
+
+    push_region_bounds([],
+                       builtin_bounds,
+                       &mut all_bounds);
+
+    debug!("from builtin bounds: all_bounds={}", all_bounds.repr(tcx));
+
+    each_bound_trait_and_supertraits(
+        tcx,
+        trait_bounds,
+        |trait_ref| {
+            let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref);
+            push_region_bounds(bounds.opt_region_bound.as_slice(),
+                               bounds.builtin_bounds,
+                               &mut all_bounds);
+            debug!("from {}: bounds={} all_bounds={}",
+                   trait_ref.repr(tcx),
+                   bounds.repr(tcx),
+                   all_bounds.repr(tcx));
+            true
+        });
+
+    return all_bounds;
+
+    fn push_region_bounds(region_bounds: &[ty::Region],
+                          builtin_bounds: ty::BuiltinBounds,
+                          all_bounds: &mut Vec<ty::Region>) {
+        all_bounds.push_all(region_bounds.as_slice());
+
+        if builtin_bounds.contains_elem(ty::BoundSend) {
+            all_bounds.push(ty::ReStatic);
+        }
+    }
+}
+
 pub fn get_tydesc_ty(tcx: &ctxt) -> Result<t, String> {
     tcx.lang_items.require(TyDescStructLangItem).map(|tydesc_lang_item| {
         tcx.intrinsic_defs.borrow().find_copy(&tydesc_lang_item)
@@ -4780,7 +4865,10 @@ pub fn get_opaque_ty(tcx: &ctxt) -> Result<t, String> {
 }
 
 pub fn visitor_object_ty(tcx: &ctxt,
-                         region: ty::Region) -> Result<(Rc<TraitRef>, t), String> {
+                         ptr_region: ty::Region,
+                         trait_region: ty::Region)
+                         -> Result<(Rc<TraitRef>, t), String>
+{
     let trait_lang_item = match tcx.lang_items.require(TyVisitorTraitLangItem) {
         Ok(id) => id,
         Err(s) => { return Err(s); }
@@ -4788,11 +4876,12 @@ pub fn visitor_object_ty(tcx: &ctxt,
     let substs = Substs::empty();
     let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
     Ok((trait_ref.clone(),
-        mk_rptr(tcx, region, mt {mutbl: ast::MutMutable,
-                                 ty: mk_trait(tcx,
-                                              trait_ref.def_id,
-                                              trait_ref.substs.clone(),
-                                              empty_builtin_bounds()) })))
+        mk_rptr(tcx, ptr_region,
+                mt {mutbl: ast::MutMutable,
+                    ty: mk_trait(tcx,
+                                 trait_ref.def_id,
+                                 trait_ref.substs.clone(),
+                                 ty::region_existential_bound(trait_region))})))
 }
 
 pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
@@ -5184,6 +5273,18 @@ pub fn construct_parameter_environment(
                               generics.types.get_slice(space));
     }
 
+    //
+    // Compute region bounds. For now, these relations are stored in a
+    // global table on the tcx, so just enter them there. I'm not
+    // crazy about this scheme, but it's convenient, at least.
+    //
+
+    for &space in subst::ParamSpace::all().iter() {
+        record_region_bounds_from_defs(tcx, space, &free_substs,
+                                       generics.regions.get_slice(space));
+    }
+
+
     debug!("construct_parameter_environment: free_id={} \
            free_subst={} \
            bounds={}",
@@ -5193,7 +5294,8 @@ pub fn construct_parameter_environment(
 
     return ty::ParameterEnvironment {
         free_substs: free_substs,
-        bounds: bounds
+        bounds: bounds,
+        implicit_region_bound: ty::ReScope(free_id),
     };
 
     fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
@@ -5222,10 +5324,41 @@ pub fn construct_parameter_environment(
                              free_substs: &subst::Substs,
                              defs: &[TypeParameterDef]) {
         for def in defs.iter() {
-            let b = (*def.bounds).subst(tcx, free_substs);
+            let b = def.bounds.subst(tcx, free_substs);
             bounds.push(space, b);
         }
     }
+
+    fn record_region_bounds_from_defs(tcx: &ty::ctxt,
+                                      space: subst::ParamSpace,
+                                      free_substs: &subst::Substs,
+                                      defs: &[RegionParameterDef]) {
+        for (subst_region, def) in
+            free_substs.regions().get_slice(space).iter().zip(
+                defs.iter())
+        {
+            // For each region parameter 'subst...
+            let bounds = def.bounds.subst(tcx, free_substs);
+            for bound_region in bounds.iter() {
+                // Which is declared with a bound like 'subst:'bound...
+                match (subst_region, bound_region) {
+                    (&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => {
+                        // Record that 'subst outlives 'bound. Or, put
+                        // another way, 'bound <= 'subst.
+                        tcx.region_maps.relate_free_regions(bound_fr, subst_fr);
+                    },
+                    _ => {
+                        // All named regions are instantiated with free regions.
+                        tcx.sess.bug(
+                            format!("push_region_bounds_from_defs: \
+                                     non free region: {} / {}",
+                                    subst_region.repr(tcx),
+                                    bound_region.repr(tcx)).as_slice());
+                    }
+                }
+            }
+        }
+    }
 }
 
 impl BorrowKind {
@@ -5346,4 +5479,3 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
         }
     })
 }
-
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 2bfbc67bbeb..435c591f881 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -85,6 +85,11 @@ pub trait TypeFolder {
         super_fold_trait_store(self, s)
     }
 
+    fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds)
+                               -> ty::ExistentialBounds {
+        super_fold_existential_bounds(self, s)
+    }
+
     fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef {
         super_fold_autoref(self, ar)
     }
@@ -236,9 +241,16 @@ impl TypeFoldable for ty::BuiltinBounds {
     }
 }
 
+impl TypeFoldable for ty::ExistentialBounds {
+    fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ExistentialBounds {
+        folder.fold_existential_bounds(*self)
+    }
+}
+
 impl TypeFoldable for ty::ParamBounds {
     fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ParamBounds {
         ty::ParamBounds {
+            opt_region_bound: self.opt_region_bound.fold_with(folder),
             builtin_bounds: self.builtin_bounds.fold_with(folder),
             trait_bounds: self.trait_bounds.fold_with(folder),
         }
@@ -259,8 +271,14 @@ impl TypeFoldable for ty::TypeParameterDef {
 }
 
 impl TypeFoldable for ty::RegionParameterDef {
-    fn fold_with<F:TypeFolder>(&self, _folder: &mut F) -> ty::RegionParameterDef {
-        *self
+    fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::RegionParameterDef {
+        ty::RegionParameterDef {
+            name: self.name,
+            def_id: self.def_id,
+            space: self.space,
+            index: self.index,
+            bounds: self.bounds.fold_with(folder)
+        }
     }
 }
 
@@ -340,7 +358,7 @@ pub fn super_fold_closure_ty<T:TypeFolder>(this: &mut T,
         sig: fty.sig.fold_with(this),
         fn_style: fty.fn_style,
         onceness: fty.onceness,
-        bounds: fty.bounds,
+        bounds: fty.bounds.fold_with(this),
         abi: fty.abi,
     }
 }
@@ -389,7 +407,7 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
             ty::ty_trait(box ty::TyTrait {
                 def_id: def_id,
                 substs: substs.fold_with(this),
-                bounds: bounds
+                bounds: this.fold_existential_bounds(bounds),
             })
         }
         ty::ty_tup(ref ts) => {
@@ -430,6 +448,15 @@ pub fn super_fold_trait_store<T:TypeFolder>(this: &mut T,
     }
 }
 
+pub fn super_fold_existential_bounds<T:TypeFolder>(this: &mut T,
+                                                   bounds: ty::ExistentialBounds)
+                                                   -> ty::ExistentialBounds {
+    ty::ExistentialBounds {
+        region_bound: bounds.region_bound.fold_with(this),
+        builtin_bounds: bounds.builtin_bounds,
+    }
+}
+
 pub fn super_fold_autoref<T:TypeFolder>(this: &mut T,
                                         autoref: &ty::AutoRef)
                                         -> ty::AutoRef
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 08e78b35e4d..6cd61a8c3f8 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -57,19 +57,19 @@ use middle::resolve_lifetime as rl;
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
 use middle::subst::{VecPerParamSpace};
 use middle::ty;
-use middle::ty_fold::TypeFolder;
-use middle::typeck::rscope::RegionScope;
-use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope};
-use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope};
+use middle::typeck::lookup_def_tcx;
+use middle::typeck::infer;
+use middle::typeck::rscope::{ExplicitRscope, RegionScope, SpecificRscope};
+use middle::typeck::rscope;
+use middle::typeck::TypeAndSubsts;
 use middle::typeck;
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
 
+use std::collections::HashMap;
 use std::rc::Rc;
 use syntax::abi;
 use syntax::{ast, ast_util};
 use syntax::codemap::Span;
-use syntax::owned_slice::OwnedSlice;
-use syntax::print::pprust::{lifetime_to_string, path_to_string};
 
 pub trait AstConv {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt;
@@ -111,8 +111,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
     };
 
     debug!("ast_region_to_region(lifetime={} id={}) yields {}",
-            lifetime_to_string(lifetime),
-            lifetime.id, r.repr(tcx));
+           lifetime.repr(tcx),
+           lifetime.id,
+           r.repr(tcx));
 
     r
 }
@@ -145,7 +146,7 @@ pub fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
     };
 
     debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}",
-            opt_lifetime.as_ref().map(|e| lifetime_to_string(e)),
+            opt_lifetime.repr(this.tcx()),
             r.repr(this.tcx()));
 
     r
@@ -284,11 +285,11 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
 }
 
 pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
-        this: &AC,
-        rscope: &RS,
-        did: ast::DefId,
-        path: &ast::Path)
-     -> TypeAndSubsts
+    this: &AC,
+    rscope: &RS,
+    did: ast::DefId,
+    path: &ast::Path)
+    -> TypeAndSubsts
 {
     let tcx = this.tcx();
     let ty::Polytype {
@@ -370,7 +371,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
                 None => {
                     tcx.sess.span_bug(ast_ty.span,
                                       format!("unbound path {}",
-                                              path_to_string(path)).as_slice())
+                                              path.repr(tcx)).as_slice())
                 }
                 Some(&d) => d
             };
@@ -430,7 +431,7 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
                         .sess
                         .span_bug(ast_ty.span,
                                   format!("unbound path {}",
-                                          path_to_string(path)).as_slice())
+                                          path.repr(this.tcx())).as_slice())
                 }
                 Some(&d) => d
             };
@@ -520,6 +521,16 @@ enum PointerTy {
     Uniq
 }
 
+impl PointerTy {
+    fn default_region(&self) -> ty::Region {
+        match *self {
+            Box => ty::ReStatic,
+            Uniq => ty::ReStatic,
+            RPtr(r) => r,
+        }
+    }
+}
+
 pub fn trait_ref_for_unboxed_function<AC:AstConv,
                                       RS:RegionScope>(
                                       this: &AC,
@@ -589,10 +600,11 @@ fn mk_pointer<AC:AstConv,
                                                rscope,
                                                &**unboxed_function,
                                                None);
+            let r = ptr_ty.default_region();
             let tr = ty::mk_trait(this.tcx(),
                                   def_id,
                                   substs,
-                                  ty::empty_builtin_bounds());
+                                  ty::region_existential_bound(r));
             match ptr_ty {
                 Uniq => {
                     return ty::mk_uniq(this.tcx(), tr);
@@ -612,7 +624,7 @@ fn mk_pointer<AC:AstConv,
 
             }
         }
-        ast::TyPath(ref path, ref bounds, id) => {
+        ast::TyPath(ref path, ref opt_bounds, id) => {
             // Note that the "bounds must be empty if path is not a trait"
             // restriction is enforced in the below case for ty_path, which
             // will run after this as long as the path isn't a trait.
@@ -636,14 +648,22 @@ fn mk_pointer<AC:AstConv,
                 Some(&def::DefTrait(trait_def_id)) => {
                     let result = ast_path_to_trait_ref(
                         this, rscope, trait_def_id, None, path);
-                    let static_region = match ptr_ty {
-                        RPtr(r) if r == ty::ReStatic => true,
-                        _ => false
+                    let bounds = match *opt_bounds {
+                        None => {
+                            conv_existential_bounds(this,
+                                                    rscope,
+                                                    path.span,
+                                                    [result.clone()].as_slice(),
+                                                    [].as_slice())
+                        }
+                        Some(ref bounds) => {
+                            conv_existential_bounds(this,
+                                                    rscope,
+                                                    path.span,
+                                                    [result.clone()].as_slice(),
+                                                    bounds.as_slice())
+                        }
                     };
-                    let bounds = conv_builtin_bounds(this.tcx(),
-                                                     path.span,
-                                                     bounds,
-                                                     static_region);
                     let tr = ty::mk_trait(tcx,
                                           result.def_id,
                                           result.substs.clone(),
@@ -737,27 +757,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                 ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style,
                                                   bf.abi, &*bf.decl))
             }
-            ast::TyClosure(ref f, ref region) => {
-
-                // resolve the function bound region in the original region
-                // scope `rscope`, not the scope of the function parameters
-                let bound_region = opt_ast_region_to_region(this, rscope,
-                                                            ast_ty.span, region);
-
+            ast::TyClosure(ref f) => {
                 // Use corresponding trait store to figure out default bounds
                 // if none were specified.
-                let bounds = conv_builtin_bounds(this.tcx(),
-                                                 ast_ty.span,
-                                                 &f.bounds,
-                                                 bound_region == ty::ReStatic);
-
-                let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
+                let bounds = conv_existential_bounds(this,
+                                                     rscope,
+                                                     ast_ty.span,
+                                                     [].as_slice(),
+                                                     f.bounds.as_slice());
                 let fn_decl = ty_of_closure(this,
                                             ast_ty.id,
                                             f.fn_style,
                                             f.onceness,
                                             bounds,
-                                            store,
+                                            ty::RegionTraitStore(
+                                                bounds.region_bound,
+                                                ast::MutMutable),
                                             &*f.decl,
                                             abi::Rust,
                                             None);
@@ -766,10 +781,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
             ast::TyProc(ref f) => {
                 // Use corresponding trait store to figure out default bounds
                 // if none were specified.
-                let bounds = conv_builtin_bounds(this.tcx(),
-                                                 ast_ty.span,
-                                                 &f.bounds,
-                                                 false);
+                let bounds = conv_existential_bounds(this, rscope,
+                                                     ast_ty.span,
+                                                     [].as_slice(),
+                                                     f.bounds.as_slice());
 
                 let fn_decl = ty_of_closure(this,
                                             ast_ty.id,
@@ -780,6 +795,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                                             &*f.decl,
                                             abi::Rust,
                                             None);
+
                 ty::mk_closure(tcx, fn_decl)
             }
             ast::TyUnboxedFn(..) => {
@@ -793,7 +809,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                         tcx.sess
                            .span_bug(ast_ty.span,
                                      format!("unbound path {}",
-                                             path_to_string(path)).as_slice())
+                                             path.repr(tcx)).as_slice())
                     }
                     Some(&d) => d
                 };
@@ -808,16 +824,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                 }
                 match a_def {
                     def::DefTrait(trait_def_id) => {
-                    let result = ast_path_to_trait_ref(
-                        this, rscope, trait_def_id, None, path);
-                    let bounds = conv_builtin_bounds(this.tcx(),
-                                                     path.span,
-                                                     bounds,
-                                                     false);
-                    ty::mk_trait(tcx,
-                                 result.def_id,
-                                 result.substs.clone(),
-                                 bounds)
+                        let result = ast_path_to_trait_ref(
+                            this, rscope, trait_def_id, None, path);
+                        let empty_bounds: &[ast::TyParamBound] = &[];
+                        let ast_bounds = match *bounds {
+                            Some(ref b) => b.as_slice(),
+                            None => empty_bounds
+                        };
+                        let bounds = conv_existential_bounds(this,
+                                                             rscope,
+                                                             ast_ty.span,
+                                                             &[result.clone()],
+                                                             ast_bounds);
+                        ty::mk_trait(tcx,
+                                     result.def_id,
+                                     result.substs.clone(),
+                                     bounds)
                     }
                     def::DefTy(did) | def::DefStruct(did) => {
                         ast_path_to_ty(this, rscope, did, path).ty
@@ -1022,9 +1044,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv>(
         _ => {
             match implied_output_region {
                 Some(implied_output_region) => {
-                    let rb = ImpliedSingleRscope {
-                        region: implied_output_region,
-                    };
+                    let rb = SpecificRscope::new(implied_output_region);
                     ast_ty_to_ty(this, &rb, &*decl.output)
                 }
                 None => {
@@ -1130,7 +1150,7 @@ pub fn ty_of_closure<AC:AstConv>(
     id: ast::NodeId,
     fn_style: ast::FnStyle,
     onceness: ast::Onceness,
-    bounds: ty::BuiltinBounds,
+    bounds: ty::ExistentialBounds,
     store: ty::TraitStore,
     decl: &ast::FnDecl,
     abi: abi::Abi,
@@ -1176,67 +1196,250 @@ pub fn ty_of_closure<AC:AstConv>(
     }
 }
 
-fn conv_builtin_bounds(tcx: &ty::ctxt,
-                       span: Span,
-                       ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
-                       static_region: bool)
-                       -> ty::BuiltinBounds {
-    //! Converts a list of bounds from the AST into a `BuiltinBounds`
-    //! struct. Reports an error if any of the bounds that appear
-    //! in the AST refer to general traits and not the built-in traits
-    //! like `Send`. Used to translate the bounds that
-    //! appear in closure and trait types, where only builtin bounds are
-    //! legal.
-    //! If no bounds were specified, we choose a "default" bound based on
-    //! the allocation type of the fn/trait, as per issue #7264. The user can
-    //! override this with an empty bounds list, e.g. "Box<fn:()>" or
-    //! "Box<Trait:>".
-
-    match ast_bounds {
-        &Some(ref bound_vec) => {
-            let mut builtin_bounds = ty::empty_builtin_bounds();
-            for ast_bound in bound_vec.iter() {
-                match *ast_bound {
-                    ast::TraitTyParamBound(ref b) => {
-                        match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
-                            def::DefTrait(trait_did) => {
-                                if ty::try_add_builtin_trait(tcx, trait_did,
-                                                             &mut builtin_bounds) {
-                                    continue; // success
-                                }
+pub fn conv_existential_bounds<AC:AstConv, RS:RegionScope>(
+    this: &AC,
+    rscope: &RS,
+    span: Span,
+    main_trait_refs: &[Rc<ty::TraitRef>],
+    ast_bounds: &[ast::TyParamBound])
+    -> ty::ExistentialBounds
+{
+    /*!
+     * Given an existential type like `Foo+'a+Bar`, this routine
+     * converts the `'a` and `Bar` intos an `ExistentialBounds`
+     * struct. The `main_trait_refs` argument specifies the `Foo` --
+     * it is absent for closures. Eventually this should all be
+     * normalized, I think, so that there is no "main trait ref" and
+     * instead we just have a flat list of bounds as the existential
+     * type.
+     */
+
+    let ast_bound_refs: Vec<&ast::TyParamBound> =
+        ast_bounds.iter().collect();
+
+    let PartitionedBounds { builtin_bounds,
+                            trait_bounds,
+                            region_bounds,
+                            unboxed_fn_ty_bounds } =
+        partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
+
+    if !trait_bounds.is_empty() {
+        let b = trait_bounds.get(0);
+        this.tcx().sess.span_err(
+            b.path.span,
+            format!("only the builtin traits can be used \
+                     as closure or object bounds").as_slice());
+    }
+
+    if !unboxed_fn_ty_bounds.is_empty() {
+        this.tcx().sess.span_err(
+            span,
+            format!("only the builtin traits can be used \
+                     as closure or object bounds").as_slice());
+    }
+
+    // The "main trait refs", rather annoyingly, have no type
+    // specified for the `Self` parameter of the trait. The reason for
+    // this is that they are, after all, *existential* types, and
+    // hence that type is unknown. However, leaving this type missing
+    // causes the substitution code to go all awry when walking the
+    // bounds, so here we clone those trait refs and insert ty::err as
+    // the self type. Perhaps we should do this more generally, it'd
+    // be convenient (or perhaps something else, i.e., ty::erased).
+    let main_trait_refs: Vec<Rc<ty::TraitRef>> =
+        main_trait_refs.iter()
+        .map(|t|
+             Rc::new(ty::TraitRef {
+                 def_id: t.def_id,
+                 substs: t.substs.with_self_ty(ty::mk_err()) }))
+        .collect();
+
+    let region_bound = compute_region_bound(this,
+                                            rscope,
+                                            span,
+                                            builtin_bounds,
+                                            region_bounds.as_slice(),
+                                            main_trait_refs.as_slice());
+
+    ty::ExistentialBounds {
+        region_bound: region_bound,
+        builtin_bounds: builtin_bounds,
+    }
+}
+
+pub fn compute_opt_region_bound(tcx: &ty::ctxt,
+                                span: Span,
+                                builtin_bounds: ty::BuiltinBounds,
+                                region_bounds: &[&ast::Lifetime],
+                                trait_bounds: &[Rc<ty::TraitRef>])
+                                -> Option<ty::Region>
+{
+    /*!
+     * Given the bounds on a type parameter / existential type,
+     * determines what single region bound (if any) we can use to
+     * summarize this type. The basic idea is that we will use the
+     * bound the user provided, if they provided one, and otherwise
+     * search the supertypes of trait bounds for region bounds. It may
+     * be that we can derive no bound at all, in which case we return
+     * `None`.
+     */
+
+    if region_bounds.len() > 1 {
+        tcx.sess.span_err(
+            region_bounds[1].span,
+            format!("only a single explicit lifetime bound is permitted").as_slice());
+    }
+
+    if region_bounds.len() != 0 {
+        // Explicitly specified region bound. Use that.
+        let r = region_bounds[0];
+        return Some(ast_region_to_region(tcx, r));
+    }
+
+    // No explicit region bound specified. Therefore, examine trait
+    // bounds and see if we can derive region bounds from those.
+    let derived_region_bounds =
+        ty::required_region_bounds(
+            tcx,
+            [],
+            builtin_bounds,
+            trait_bounds);
+
+    // If there are no derived region bounds, then report back that we
+    // can find no region bound.
+    if derived_region_bounds.len() == 0 {
+        return None;
+    }
+
+    // If any of the derived region bounds are 'static, that is always
+    // the best choice.
+    if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
+        return Some(ty::ReStatic);
+    }
+
+    // Determine whether there is exactly one unique region in the set
+    // of derived region bounds. If so, use that. Otherwise, report an
+    // error.
+    let r = *derived_region_bounds.get(0);
+    if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) {
+        tcx.sess.span_err(
+            span,
+            format!("ambiguous lifetime bound, \
+                     explicit lifetime bound required").as_slice());
+    }
+    return Some(r);
+}
+
+fn compute_region_bound<AC:AstConv, RS:RegionScope>(
+    this: &AC,
+    rscope: &RS,
+    span: Span,
+    builtin_bounds: ty::BuiltinBounds,
+    region_bounds: &[&ast::Lifetime],
+    trait_bounds: &[Rc<ty::TraitRef>])
+    -> ty::Region
+{
+    /*!
+     * A version of `compute_opt_region_bound` for use where some
+     * region bound is required (existential types,
+     * basically). Reports an error if no region bound can be derived
+     * and we are in an `rscope` that does not provide a default.
+     */
+
+    match compute_opt_region_bound(this.tcx(), span, builtin_bounds,
+                                   region_bounds, trait_bounds) {
+        Some(r) => r,
+        None => {
+            match rscope.default_region_bound(span) {
+                Some(r) => { r }
+                None => {
+                    this.tcx().sess.span_err(
+                        span,
+                        format!("explicit lifetime bound required").as_slice());
+                    ty::ReStatic
+                }
+            }
+        }
+    }
+}
+
+pub struct PartitionedBounds<'a> {
+    pub builtin_bounds: ty::BuiltinBounds,
+    pub trait_bounds: Vec<&'a ast::TraitRef>,
+    pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnTy>,
+    pub region_bounds: Vec<&'a ast::Lifetime>,
+}
+
+pub fn partition_bounds<'a>(tcx: &ty::ctxt,
+                            _span: Span,
+                            ast_bounds: &'a [&ast::TyParamBound])
+                            -> PartitionedBounds<'a>
+{
+    /*!
+     * Divides a list of bounds from the AST into three groups:
+     * builtin bounds (Copy, Sized etc), general trait bounds,
+     * and region bounds.
+     */
+
+    let mut builtin_bounds = ty::empty_builtin_bounds();
+    let mut region_bounds = Vec::new();
+    let mut trait_bounds = Vec::new();
+    let mut unboxed_fn_ty_bounds = Vec::new();
+    let mut trait_def_ids = HashMap::new();
+    for &ast_bound in ast_bounds.iter() {
+        match *ast_bound {
+            ast::TraitTyParamBound(ref b) => {
+                match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
+                    def::DefTrait(trait_did) => {
+                        match trait_def_ids.find(&trait_did) {
+                            // Already seen this trait. We forbid
+                            // duplicates in the list (for some
+                            // reason).
+                            Some(span) => {
+                                span_err!(
+                                    tcx.sess, b.path.span, E0127,
+                                    "trait `{}` already appears in the \
+                                     list of bounds",
+                                    b.path.user_string(tcx));
+                                tcx.sess.span_note(
+                                    *span,
+                                    "previous appearance is here");
+
+                                continue;
                             }
-                            _ => { }
+
+                            None => { }
                         }
-                        tcx.sess.span_fatal(
-                            b.path.span,
-                            "only the builtin traits can be used as closure \
-                             or object bounds");
-                    }
-                    ast::StaticRegionTyParamBound => {
-                        builtin_bounds.add(ty::BoundStatic);
-                    }
-                    ast::UnboxedFnTyParamBound(_) => {
-                        tcx.sess.span_err(span,
-                                          "unboxed functions are not allowed \
-                                           here");
-                    }
-                    ast::OtherRegionTyParamBound(span) => {
-                        if !tcx.sess.features.issue_5723_bootstrap.get() {
-                            tcx.sess.span_err(
-                                span,
-                                "only the 'static lifetime is accepted \
-                                 here.");
+
+                        trait_def_ids.insert(trait_did, b.path.span);
+
+                        if ty::try_add_builtin_trait(tcx,
+                                                     trait_did,
+                                                     &mut builtin_bounds) {
+                            continue; // success
                         }
                     }
+                    _ => {
+                        // Not a trait? that's an error, but it'll get
+                        // reported later.
+                    }
                 }
+                trait_bounds.push(b);
+            }
+            ast::RegionTyParamBound(ref l) => {
+                region_bounds.push(l);
+            }
+            ast::UnboxedFnTyParamBound(ref unboxed_function) => {
+                unboxed_fn_ty_bounds.push(unboxed_function);
             }
-            builtin_bounds
-        },
-        // &'static Trait is sugar for &'static Trait:'static.
-        &None if static_region => {
-            let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set
         }
-        &None => ty::empty_builtin_bounds(),
+    }
+
+    PartitionedBounds {
+        builtin_bounds: builtin_bounds,
+        trait_bounds: trait_bounds,
+        region_bounds: region_bounds,
+        unboxed_fn_ty_bounds: unboxed_fn_ty_bounds
     }
 }
 
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 6bb17c90da2..3c15135807b 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -87,7 +87,6 @@ use middle::ty;
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
 use middle::typeck::check;
-use middle::typeck::infer::MiscVariable;
 use middle::typeck::infer;
 use middle::typeck::MethodCallee;
 use middle::typeck::{MethodOrigin, MethodParam};
@@ -240,6 +239,7 @@ fn construct_transformed_self_ty_for_object(
     span: Span,
     trait_def_id: ast::DefId,
     rcvr_substs: &subst::Substs,
+    rcvr_bounds: ty::ExistentialBounds,
     method_ty: &ty::Method)
     -> ty::t
 {
@@ -276,8 +276,7 @@ fn construct_transformed_self_ty_for_object(
             tcx.sess.span_bug(span, "static method for object type receiver");
         }
         ByValueExplicitSelfCategory => {
-            let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                  ty::empty_builtin_bounds());
+            let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds);
             ty::mk_uniq(tcx, tr)
         }
         ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => {
@@ -286,12 +285,12 @@ fn construct_transformed_self_ty_for_object(
                 ty::ty_rptr(r, mt) => { // must be SelfRegion
                     let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
                     let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                          ty::empty_builtin_bounds());
+                                          rcvr_bounds);
                     ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
                 }
                 ty::ty_uniq(_) => { // must be SelfUniq
                     let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                          ty::empty_builtin_bounds());
+                                          rcvr_bounds);
                     ty::mk_uniq(tcx, tr)
                 }
                 _ => {
@@ -442,8 +441,9 @@ impl<'a> LookupContext<'a> {
         let span = self.self_expr.map_or(self.span, |e| e.span);
         check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
             match get(self_ty).sty {
-                ty_trait(box TyTrait { def_id, ref substs, .. }) => {
-                    self.push_inherent_candidates_from_object(def_id, substs);
+                ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
+                    self.push_inherent_candidates_from_object(
+                        def_id, substs, bounds);
                     self.push_inherent_impl_candidates_for_type(def_id);
                 }
                 ty_enum(did, _) |
@@ -538,15 +538,13 @@ impl<'a> LookupContext<'a> {
         }
 
         let vcx = self.fcx.vtable_context();
-        let region_params =
-            vec!(vcx.infcx.next_region_var(MiscVariable(self.span)));
 
         // Get the tupled type of the arguments.
         let arguments_type = *closure_function_type.sig.inputs.get(0);
         let return_type = closure_function_type.sig.output;
 
         let closure_region =
-            vcx.infcx.next_region_var(MiscVariable(self.span));
+            vcx.infcx.next_region_var(infer::MiscVariable(self.span));
         let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
                                                           closure_did,
                                                           closure_region);
@@ -555,7 +553,7 @@ impl<'a> LookupContext<'a> {
                 RcvrMatchesIfSubtype(unboxed_closure_type),
             rcvr_substs: subst::Substs::new_trait(
                 vec![arguments_type, return_type],
-                region_params,
+                vec![],
                 *vcx.infcx.next_ty_vars(1).get(0)),
             method_ty: method,
             origin: MethodStaticUnboxedClosure(closure_did),
@@ -595,11 +593,11 @@ impl<'a> LookupContext<'a> {
 
     fn push_inherent_candidates_from_object(&mut self,
                                             did: DefId,
-                                            substs: &subst::Substs) {
+                                            substs: &subst::Substs,
+                                            bounds: ty::ExistentialBounds) {
         debug!("push_inherent_candidates_from_object(did={}, substs={})",
                self.did_to_string(did),
                substs.repr(self.tcx()));
-        let _indenter = indenter();
         let tcx = self.tcx();
         let span = self.span;
 
@@ -617,28 +615,30 @@ impl<'a> LookupContext<'a> {
             substs: rcvr_substs.clone()
         });
 
-        self.push_inherent_candidates_from_bounds_inner(&[trait_ref.clone()],
-            |new_trait_ref, m, method_num, _bound_num| {
-            let vtable_index = get_method_index(tcx, &*new_trait_ref,
-                                                trait_ref.clone(), method_num);
-            let mut m = (*m).clone();
-            // We need to fix up the transformed self type.
-            *m.fty.sig.inputs.get_mut(0) =
-                construct_transformed_self_ty_for_object(
-                    tcx, span, did, &rcvr_substs, &m);
-
-            Some(Candidate {
-                rcvr_match_condition: RcvrMatchesIfObject(did),
-                rcvr_substs: new_trait_ref.substs.clone(),
-                method_ty: Rc::new(m),
-                origin: MethodObject(MethodObject {
+        self.push_inherent_candidates_from_bounds_inner(
+            &[trait_ref.clone()],
+            |_this, new_trait_ref, m, method_num, _bound_num| {
+                let vtable_index =
+                    get_method_index(tcx, &*new_trait_ref,
+                                     trait_ref.clone(), method_num);
+                let mut m = (*m).clone();
+                // We need to fix up the transformed self type.
+                *m.fty.sig.inputs.get_mut(0) =
+                    construct_transformed_self_ty_for_object(
+                        tcx, span, did, &rcvr_substs, bounds, &m);
+
+                Some(Candidate {
+                    rcvr_match_condition: RcvrMatchesIfObject(did),
+                    rcvr_substs: new_trait_ref.substs.clone(),
+                    method_ty: Rc::new(m),
+                    origin: MethodObject(MethodObject {
                         trait_id: new_trait_ref.def_id,
                         object_trait_id: did,
                         method_num: method_num,
                         real_index: vtable_index
                     })
-            })
-        });
+                })
+            });
     }
 
     fn push_inherent_candidates_from_param(&mut self,
@@ -666,7 +666,7 @@ impl<'a> LookupContext<'a> {
             self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
             .as_slice();
         self.push_inherent_candidates_from_bounds_inner(bounds,
-            |trait_ref, m, method_num, bound_num| {
+            |this, trait_ref, m, method_num, bound_num| {
                 match restrict_to {
                     Some(trait_did) => {
                         if trait_did != trait_ref.def_id {
@@ -675,6 +675,18 @@ impl<'a> LookupContext<'a> {
                     }
                     _ => {}
                 }
+                debug!("found match: trait_ref={} substs={} m={}",
+                       trait_ref.repr(this.tcx()),
+                       trait_ref.substs.repr(this.tcx()),
+                       m.repr(this.tcx()));
+                assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
+                           trait_ref.substs.types.get_slice(subst::TypeSpace).len());
+                assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
+                           trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
+                assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
+                           trait_ref.substs.types.get_slice(subst::SelfSpace).len());
+                assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
+                           trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
                 Some(Candidate {
                     rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
                     rcvr_substs: trait_ref.substs.clone(),
@@ -691,13 +703,15 @@ impl<'a> LookupContext<'a> {
 
     // Do a search through a list of bounds, using a callback to actually
     // create the candidates.
-    fn push_inherent_candidates_from_bounds_inner(&mut self,
-                                                  bounds: &[Rc<TraitRef>],
-                                                  mk_cand: |tr: Rc<TraitRef>,
-                                                            m: Rc<ty::Method>,
-                                                            method_num: uint,
-                                                            bound_num: uint|
-                                                            -> Option<Candidate>) {
+    fn push_inherent_candidates_from_bounds_inner(
+        &mut self,
+        bounds: &[Rc<TraitRef>],
+        mk_cand: |this: &mut LookupContext,
+                  tr: Rc<TraitRef>,
+                  m: Rc<ty::Method>,
+                  method_num: uint,
+                  bound_num: uint|
+                  -> Option<Candidate>) {
         let tcx = self.tcx();
         let mut next_bound_idx = 0; // count only trait bounds
 
@@ -719,7 +733,8 @@ impl<'a> LookupContext<'a> {
                         ty::MethodTraitItem(ref method) => (*method).clone(),
                     };
 
-                    match mk_cand(bound_trait_ref,
+                    match mk_cand(self,
+                                  bound_trait_ref,
                                   method,
                                   pos,
                                   this_bound_idx) {
@@ -1338,6 +1353,11 @@ impl<'a> LookupContext<'a> {
             }
         }
 
+        self.fcx.add_region_obligations_for_parameters(
+            self.span,
+            &all_substs,
+            &candidate.method_ty.generics);
+
         MethodCallee {
             origin: candidate.origin,
             ty: fty,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 02464e17bac..b9e96c78533 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -102,7 +102,6 @@ use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
 use middle::typeck::check::method::{DontAutoderefReceiver};
 use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
-use middle::typeck::check::regionmanip::relate_free_regions;
 use middle::typeck::check::vtable::VtableContext;
 use middle::typeck::CrateCtxt;
 use middle::typeck::infer::{resolve_type, force_tvar};
@@ -173,6 +172,43 @@ pub struct Inherited<'a> {
     vtable_map: vtable_map,
     upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
     unboxed_closures: RefCell<DefIdMap<ty::UnboxedClosure>>,
+
+    // A mapping from each fn's id to its signature, with all bound
+    // regions replaced with free ones. Unlike the other tables, this
+    // one is never copied into the tcx: it is only used by regionck.
+    fn_sig_map: RefCell<NodeMap<Vec<ty::t>>>,
+
+    // A set of constraints that regionck must validate. Each
+    // constraint has the form `T:'a`, meaning "some type `T` must
+    // outlive the lifetime 'a". These constraints derive from
+    // instantiated type parameters. So if you had a struct defined
+    // like
+    //
+    //     struct Foo<T:'static> { ... }
+    //
+    // then in some expression `let x = Foo { ... }` it will
+    // instantiate the type parameter `T` with a fresh type `$0`. At
+    // the same time, it will record a region obligation of
+    // `$0:'static`. This will get checked later by regionck.  (We
+    // can't generally check these things right away because we have
+    // to wait until types are resolved.)
+    //
+    // These are stored in a map keyed to the id of the innermost
+    // enclosing fn body / static initializer expression. This is
+    // because the location where the obligation was incurred can be
+    // relevant with respect to which sublifetime assumptions are in
+    // place. The reason that we store under the fn-id, and not
+    // something more fine-grained, is so that it is easier for
+    // regionck to be sure that it has found *all* the region
+    // obligations (otherwise, it's easy to fail to walk to a
+    // particular node-id).
+    region_obligations: RefCell<NodeMap<Vec<RegionObligation>>>,
+}
+
+struct RegionObligation {
+    sub_region: ty::Region,
+    sup_type: ty::t,
+    origin: infer::SubregionOrigin,
 }
 
 /// When type-checking an expression, we propagate downward
@@ -232,6 +268,8 @@ enum IsBinopAssignment{
 
 #[deriving(Clone)]
 pub struct FnCtxt<'a> {
+    body_id: ast::NodeId,
+
     // This flag is set to true if, during the writeback phase, we encounter
     // a type error in this function.
     writeback_errors: Cell<bool>,
@@ -243,22 +281,8 @@ pub struct FnCtxt<'a> {
     err_count_on_creation: uint,
 
     ret_ty: ty::t,
-    ps: RefCell<FnStyleState>,
 
-    // Sometimes we generate region pointers where the precise region
-    // to use is not known. For example, an expression like `&x.f`
-    // where `x` is of type `@T`: in this case, we will be rooting
-    // `x` onto the stack frame, and we could choose to root it until
-    // the end of (almost) any enclosing block or expression.  We
-    // want to pick the narrowest block that encompasses all uses.
-    //
-    // What we do in such cases is to generate a region variable with
-    // `region_lb` as a lower bound.  The regionck pass then adds
-    // other constraints based on how the variable is used and region
-    // inference selects the ultimate value.  Finally, borrowck is
-    // charged with guaranteeing that the value whose address was taken
-    // can actually be made to live as long as it needs to live.
-    region_lb: Cell<ast::NodeId>,
+    ps: RefCell<FnStyleState>,
 
     inh: &'a Inherited<'a>,
 
@@ -313,6 +337,8 @@ impl<'a> Inherited<'a> {
             vtable_map: RefCell::new(FnvHashMap::new()),
             upvar_borrow_map: RefCell::new(HashMap::new()),
             unboxed_closures: RefCell::new(DefIdMap::new()),
+            fn_sig_map: RefCell::new(NodeMap::new()),
+            region_obligations: RefCell::new(NodeMap::new()),
         }
     }
 }
@@ -322,25 +348,26 @@ pub fn blank_fn_ctxt<'a>(
                      ccx: &'a CrateCtxt<'a>,
                      inh: &'a Inherited<'a>,
                      rty: ty::t,
-                     region_bnd: ast::NodeId)
+                     body_id: ast::NodeId)
                      -> FnCtxt<'a> {
     FnCtxt {
+        body_id: body_id,
         writeback_errors: Cell::new(false),
         err_count_on_creation: ccx.tcx.sess.err_count(),
         ret_ty: rty,
         ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)),
-        region_lb: Cell::new(region_bnd),
         inh: inh,
         ccx: ccx
     }
 }
 
-fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
+fn static_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
     // It's kind of a kludge to manufacture a fake function context
     // and statement context, but we might as well do write the code only once
     let param_env = ty::ParameterEnvironment {
         free_substs: subst::Substs::empty(),
-        bounds: subst::VecPerParamSpace::empty()
+        bounds: subst::VecPerParamSpace::empty(),
+        implicit_region_bound: ty::ReStatic,
     };
     Inherited::new(ccx.tcx, param_env)
 }
@@ -355,6 +382,15 @@ impl<'a> ExprTyProvider for FnCtxt<'a> {
     }
 }
 
+struct CheckTypeWellFormedVisitor<'a> { ccx: &'a CrateCtxt<'a> }
+
+impl<'a> Visitor<()> for CheckTypeWellFormedVisitor<'a> {
+    fn visit_item(&mut self, i: &ast::Item, _: ()) {
+        check_type_well_formed(self.ccx, i);
+        visit::walk_item(self, i, ());
+    }
+}
+
 struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
 
 impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
@@ -374,6 +410,13 @@ impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
 }
 
 pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
+    let mut visit = CheckTypeWellFormedVisitor { ccx: ccx };
+    visit::walk_crate(&mut visit, krate, ());
+
+    // If types are not well-formed, it leads to all manner of errors
+    // downstream, so stop reporting errors at this point.
+    ccx.tcx.sess.abort_if_errors();
+
     let mut visit = CheckItemTypesVisitor { ccx: ccx };
     visit::walk_crate(&mut visit, krate, ());
 
@@ -396,11 +439,11 @@ fn check_bare_fn(ccx: &CrateCtxt,
     match ty::get(fty).sty {
         ty::ty_bare_fn(ref fn_ty) => {
             let inh = Inherited::new(ccx.tcx, param_env);
-            let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig,
+            let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig,
                                decl, id, body, &inh);
 
             vtable::resolve_in_block(&fcx, body);
-            regionck::regionck_fn(&fcx, body);
+            regionck::regionck_fn(&fcx, id, body);
             writeback::resolve_type_vars_in_fn(&fcx, decl, body);
         }
         _ => ccx.tcx.sess.impossible_case(body.span,
@@ -465,7 +508,7 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
         // non-obvious: the `blk` variable maps to region lb, so
         // we have to keep this up-to-date.  This
         // is... unfortunate.  It'd be nice to not need this.
-        self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
+        visit::walk_block(self, b, ());
     }
 
     // Since an expr occurs as part of the type fixed size arrays we
@@ -487,13 +530,16 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
 
 }
 
-fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
-                fn_style: ast::FnStyle,
-                fn_sig: &ty::FnSig,
-                decl: &ast::FnDecl,
-                id: ast::NodeId,
-                body: &ast::Block,
-                inherited: &'a Inherited<'a>) -> FnCtxt<'a>
+fn check_fn<'a>(
+    ccx: &'a CrateCtxt<'a>,
+    fn_style: ast::FnStyle,
+    fn_style_id: ast::NodeId,
+    fn_sig: &ty::FnSig,
+    decl: &ast::FnDecl,
+    fn_id: ast::NodeId,
+    body: &ast::Block,
+    inherited: &'a Inherited<'a>)
+    -> FnCtxt<'a>
 {
     /*!
      * Helper used by check_bare_fn and check_expr_fn.  Does the
@@ -514,30 +560,42 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
         ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
     });
 
-    relate_free_regions(tcx, &fn_sig);
-
     let arg_tys = fn_sig.inputs.as_slice();
     let ret_ty = fn_sig.output;
 
-    debug!("check_fn(arg_tys={}, ret_ty={})",
+    debug!("check_fn(arg_tys={}, ret_ty={}, fn_id={})",
            arg_tys.repr(tcx),
-           ret_ty.repr(tcx));
+           ret_ty.repr(tcx),
+           fn_id);
 
     // Create the function context.  This is either derived from scratch or,
     // in the case of function expressions, based on the outer context.
     let fcx = FnCtxt {
+        body_id: body.id,
         writeback_errors: Cell::new(false),
         err_count_on_creation: err_count_on_creation,
         ret_ty: ret_ty,
-        ps: RefCell::new(FnStyleState::function(fn_style, id)),
-        region_lb: Cell::new(body.id),
+        ps: RefCell::new(FnStyleState::function(fn_style, fn_style_id)),
         inh: inherited,
         ccx: ccx
     };
 
-    {
+    // Remember return type so that regionck can access it later.
+    let fn_sig_tys: Vec<ty::t> =
+        arg_tys.iter()
+        .chain([ret_ty].iter())
+        .map(|&ty| ty)
+        .collect();
+    debug!("fn-sig-map: fn_id={} fn_sig_tys={}",
+           fn_id,
+           fn_sig_tys.repr(tcx));
+    inherited.fn_sig_map
+        .borrow_mut()
+        .insert(fn_id, fn_sig_tys);
 
+    {
         let mut visit = GatherLocalsVisitor { fcx: &fcx, };
+
         // Add formal parameters.
         for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
             // Create type variables for each argument.
@@ -662,6 +720,71 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
     }
 }
 
+fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) {
+    /*!
+     * Checks that the field types (in a struct def'n) or
+     * argument types (in an enum def'n) are well-formed,
+     * meaning that they do not require any constraints not
+     * declared in the struct definition itself.
+     * For example, this definition would be illegal:
+     *
+     *     struct Ref<'a, T> { x: &'a T }
+     *
+     * because the type did not declare that `T:'a`.
+     *
+     * We do this check as a pre-pass before checking fn bodies
+     * because if these constraints are not included it frequently
+     * leads to confusing errors in fn bodies. So it's better to check
+     * the types first.
+     */
+
+    debug!("check_type_well_formed(it.id={}, it.ident={})",
+           item.id,
+           ty::item_path_str(ccx.tcx, local_def(item.id)));
+
+    match item.node {
+        ast::ItemStruct(..) => {
+            check_type_defn(ccx, item, |fcx| {
+                ty::struct_fields(ccx.tcx, local_def(item.id),
+                                  &fcx.inh.param_env.free_substs)
+                    .iter()
+                    .map(|f| f.mt.ty)
+                    .collect()
+            });
+        }
+        ast::ItemEnum(..) => {
+            check_type_defn(ccx, item, |fcx| {
+                ty::substd_enum_variants(ccx.tcx, local_def(item.id),
+                                         &fcx.inh.param_env.free_substs)
+                    .iter()
+                    .flat_map(|variant| {
+                        variant.args
+                            .iter()
+                            .map(|&arg_ty| arg_ty)
+                    })
+                    .collect()
+            });
+        }
+        _ => {}
+    }
+
+    fn check_type_defn(ccx: &CrateCtxt,
+                       item: &ast::Item,
+                       lookup_fields: |&FnCtxt| -> Vec<ty::t>)
+    {
+        let item_def_id = local_def(item.id);
+        let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
+        let param_env =
+            ty::construct_parameter_environment(ccx.tcx,
+                                                &polytype.generics,
+                                                item.id);
+        let inh = Inherited::new(ccx.tcx, param_env);
+        let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id);
+        let field_tys = lookup_fields(&fcx);
+        regionck::regionck_type_defn(&fcx, item.span, field_tys.as_slice());
+    }
+}
+
 pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
     debug!("check_item(it.id={}, it.ident={})",
            it.id,
@@ -977,9 +1100,6 @@ fn compare_impl_method(tcx: &ty::ctxt,
         return;
     }
 
-    let it = trait_m.generics.types.get_slice(subst::FnSpace).iter()
-        .zip(impl_m.generics.types.get_slice(subst::FnSpace).iter());
-
     // This code is best explained by example. Consider a trait:
     //
     //     trait Trait<T> {
@@ -1041,20 +1161,27 @@ fn compare_impl_method(tcx: &ty::ctxt,
     let impl_to_skol_substs =
         subst::Substs::new(skol_tps.clone(), skol_regions.clone());
 
-    // Compute skolemized form of impl method ty.
-    let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
-    let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
-
-    // Compute skolemized form of trait method ty.
+    // Create mapping from trait to skolemized.
     let trait_to_skol_substs =
         trait_to_impl_substs
         .subst(tcx, &impl_to_skol_substs)
         .with_method(Vec::from_slice(skol_tps.get_slice(subst::FnSpace)),
                      Vec::from_slice(skol_regions.get_slice(subst::FnSpace)));
-    let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
-    let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
+
+    // Check region bounds.
+    if !check_region_bounds_on_impl_method(tcx,
+                                           impl_m_span,
+                                           impl_m,
+                                           &trait_m.generics,
+                                           &impl_m.generics,
+                                           &trait_to_skol_substs,
+                                           &impl_to_skol_substs) {
+        return;
+    }
 
     // Check bounds.
+    let it = trait_m.generics.types.get_slice(subst::FnSpace).iter()
+        .zip(impl_m.generics.types.get_slice(subst::FnSpace).iter());
     for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
         // Check that the impl does not require any builtin-bounds
         // that the trait does not guarantee:
@@ -1110,6 +1237,12 @@ fn compare_impl_method(tcx: &ty::ctxt,
         }
     }
 
+    // Compute skolemized form of impl and trait method tys.
+    let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
+    let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
+    let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
+    let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
+
     // Check the impl method type IM is a subtype of the trait method
     // type TM. To see why this makes sense, think of a vtable. The
     // expected type of the function pointers in the vtable is the
@@ -1134,6 +1267,152 @@ fn compare_impl_method(tcx: &ty::ctxt,
     // Finally, resolve all regions. This catches wily misuses of lifetime
     // parameters.
     infcx.resolve_regions_and_report_errors();
+
+    fn check_region_bounds_on_impl_method(tcx: &ty::ctxt,
+                                          span: Span,
+                                          impl_m: &ty::Method,
+                                          trait_generics: &ty::Generics,
+                                          impl_generics: &ty::Generics,
+                                          trait_to_skol_substs: &Substs,
+                                          impl_to_skol_substs: &Substs)
+                                          -> bool
+    {
+        /*!
+
+        Check that region bounds on impl method are the same as those
+        on the trait. In principle, it could be ok for there to be
+        fewer region bounds on the impl method, but this leads to an
+        annoying corner case that is painful to handle (described
+        below), so for now we can just forbid it.
+
+        Example (see
+        `src/test/compile-fail/regions-bound-missing-bound-in-impl.rs`):
+
+            trait Foo<'a> {
+                fn method1<'b>();
+                fn method2<'b:'a>();
+            }
+
+            impl<'a> Foo<'a> for ... {
+                fn method1<'b:'a>() { .. case 1, definitely bad .. }
+                fn method2<'b>() { .. case 2, could be ok .. }
+            }
+
+        The "definitely bad" case is case #1. Here, the impl adds an
+        extra constraint not present in the trait.
+
+        The "maybe bad" case is case #2. Here, the impl adds an extra
+        constraint not present in the trait. We could in principle
+        allow this, but it interacts in a complex way with early/late
+        bound resolution of lifetimes. Basically the presence or
+        absence of a lifetime bound affects whether the lifetime is
+        early/late bound, and right now the code breaks if the trait
+        has an early bound lifetime parameter and the method does not.
+
+        */
+
+        let trait_params = trait_generics.regions.get_slice(subst::FnSpace);
+        let impl_params = impl_generics.regions.get_slice(subst::FnSpace);
+
+        debug!("check_region_bounds_on_impl_method: \
+               trait_generics={} \
+               impl_generics={}",
+               trait_generics.repr(tcx),
+               impl_generics.repr(tcx));
+
+        // Must have same number of early-bound lifetime parameters.
+        // Unfortunately, if the user screws up the bounds, then this
+        // will change classification between early and late.  E.g.,
+        // if in trait we have `<'a,'b:'a>`, and in impl we just have
+        // `<'a,'b>`, then we have 2 early-bound lifetime parameters
+        // in trait but 0 in the impl. But if we report "expected 2
+        // but found 0" it's confusing, because it looks like there
+        // are zero. Since I don't quite know how to phrase things at
+        // the moment, give a kind of vague error message.
+        if trait_params.len() != impl_params.len() {
+            tcx.sess.span_err(
+                span,
+                format!("lifetime parameters or bounds on method `{}` do \
+                         not match the trait declaration",
+                        token::get_ident(impl_m.ident)).as_slice());
+            return false;
+        }
+
+        // Each parameter `'a:'b+'c+'d` in trait should have the same
+        // set of bounds in the impl, after subst.
+        for (trait_param, impl_param) in
+            trait_params.iter().zip(
+                impl_params.iter())
+        {
+            let trait_bounds =
+                trait_param.bounds.subst(tcx, trait_to_skol_substs);
+            let impl_bounds =
+                impl_param.bounds.subst(tcx, impl_to_skol_substs);
+
+            debug!("check_region_bounds_on_impl_method: \
+                   trait_param={} \
+                   impl_param={} \
+                   trait_bounds={} \
+                   impl_bounds={}",
+                   trait_param.repr(tcx),
+                   impl_param.repr(tcx),
+                   trait_bounds.repr(tcx),
+                   impl_bounds.repr(tcx));
+
+            // Collect the set of bounds present in trait but not in
+            // impl.
+            let missing: Vec<ty::Region> =
+                trait_bounds.iter()
+                .filter(|&b| !impl_bounds.contains(b))
+                .map(|&b| b)
+                .collect();
+
+            // Collect set present in impl but not in trait.
+            let extra: Vec<ty::Region> =
+                impl_bounds.iter()
+                .filter(|&b| !trait_bounds.contains(b))
+                .map(|&b| b)
+                .collect();
+
+            debug!("missing={} extra={}",
+                   missing.repr(tcx), extra.repr(tcx));
+
+            let err = if missing.len() != 0 || extra.len() != 0 {
+                tcx.sess.span_err(
+                    span,
+                    format!(
+                        "the lifetime parameter `{}` declared in the impl \
+                         has a distinct set of bounds \
+                         from its counterpart `{}` \
+                         declared in the trait",
+                        impl_param.name.user_string(tcx),
+                        trait_param.name.user_string(tcx)).as_slice());
+                true
+            } else {
+                false
+            };
+
+            if missing.len() != 0 {
+                tcx.sess.span_note(
+                    span,
+                    format!("the impl is missing the following bounds: `{}`",
+                            missing.user_string(tcx)).as_slice());
+            }
+
+            if extra.len() != 0 {
+                tcx.sess.span_note(
+                    span,
+                    format!("the impl has the following extra bounds: `{}`",
+                            extra.user_string(tcx)).as_slice());
+            }
+
+            if err {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
 
 fn check_cast(fcx: &FnCtxt,
@@ -1163,6 +1442,7 @@ fn check_cast(fcx: &FnCtxt,
         fcx.write_error(id);
         return
     }
+
     if ty::type_is_bot(t_e) {
         fcx.write_bot(id);
         return
@@ -1301,6 +1581,8 @@ impl<'a> AstConv for FnCtxt<'a> {
 }
 
 impl<'a> FnCtxt<'a> {
+    fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
+
     pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
         &self.inh.infcx
     }
@@ -1319,6 +1601,10 @@ impl<'a> FnCtxt<'a> {
 }
 
 impl<'a> RegionScope for infer::InferCtxt<'a> {
+    fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
+        Some(self.next_region_var(infer::MiscVariable(span)))
+    }
+
     fn anon_regions(&self, span: Span, count: uint)
                     -> Result<Vec<ty::Region> , ()> {
         Ok(Vec::from_fn(count, |_| {
@@ -1494,19 +1780,10 @@ impl<'a> FnCtxt<'a> {
     }
 
     pub fn mk_subr(&self,
-                   a_is_expected: bool,
                    origin: infer::SubregionOrigin,
                    sub: ty::Region,
                    sup: ty::Region) {
-        infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
-    }
-
-    pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
-        let old_region_lb = self.region_lb.get();
-        self.region_lb.set(lb);
-        let v = f();
-        self.region_lb.set(old_region_lb);
-        v
+        infer::mk_subr(self.infcx(), origin, sub, sup)
     }
 
     pub fn type_error_message(&self,
@@ -1536,6 +1813,112 @@ impl<'a> FnCtxt<'a> {
                                    err: &ty::type_err) {
         self.infcx().report_mismatched_types(sp, e, a, err)
     }
+
+    pub fn register_region_obligation(&self,
+                                      origin: infer::SubregionOrigin,
+                                      ty: ty::t,
+                                      r: ty::Region)
+    {
+        /*!
+         * Registers an obligation for checking later, during
+         * regionck, that the type `ty` must outlive the region `r`.
+         */
+
+        let mut region_obligations = self.inh.region_obligations.borrow_mut();
+        let v = region_obligations.find_or_insert_with(self.body_id,
+                                                       |_| Vec::new());
+        v.push(RegionObligation { sub_region: r,
+                                  sup_type: ty,
+                                  origin: origin });
+    }
+
+    pub fn add_region_obligations_for_parameters(&self,
+                                                 span: Span,
+                                                 substs: &Substs,
+                                                 generics: &ty::Generics)
+    {
+        /*!
+         * Given a set of generic parameter definitions (`generics`)
+         * and the values provided for each of them (`substs`),
+         * creates and registers suitable region obligations.
+         *
+         * For example, if there is a function:
+         *
+         *    fn foo<'a,T:'a>(...)
+         *
+         * and a reference:
+         *
+         *    let f = foo;
+         *
+         * Then we will create a fresh region variable `'$0` and a
+         * fresh type variable `$1` for `'a` and `T`. This routine
+         * will add a region obligation `$1:'$0` and register it
+         * locally.
+         */
+
+        debug!("add_region_obligations_for_parameters(substs={}, generics={})",
+               substs.repr(self.tcx()),
+               generics.repr(self.tcx()));
+
+        assert_eq!(generics.types.iter().len(),
+                   substs.types.iter().len());
+        for (type_def, &type_param) in
+            generics.types.iter().zip(
+                substs.types.iter())
+        {
+            let param_ty = ty::ParamTy { space: type_def.space,
+                                         idx: type_def.index,
+                                         def_id: type_def.def_id };
+            let bounds = type_def.bounds.subst(self.tcx(), substs);
+            add_region_obligations_for_type_parameter(
+                self, span, param_ty, &bounds, type_param);
+        }
+
+        assert_eq!(generics.regions.iter().len(),
+                   substs.regions().iter().len());
+        for (region_def, &region_param) in
+            generics.regions.iter().zip(
+                substs.regions().iter())
+        {
+            let bounds = region_def.bounds.subst(self.tcx(), substs);
+            add_region_obligations_for_region_parameter(
+                self, span, bounds.as_slice(), region_param);
+        }
+
+        fn add_region_obligations_for_type_parameter(
+            fcx: &FnCtxt,
+            span: Span,
+            param_ty: ty::ParamTy,
+            param_bound: &ty::ParamBounds,
+            ty: ty::t)
+        {
+            // For each declared region bound `T:r`, `T` must outlive `r`.
+            let region_bounds =
+                ty::required_region_bounds(
+                    fcx.tcx(),
+                    param_bound.opt_region_bound.as_slice(),
+                    param_bound.builtin_bounds,
+                    param_bound.trait_bounds.as_slice());
+            for &r in region_bounds.iter() {
+                let origin = infer::RelateParamBound(span, param_ty, ty);
+                fcx.register_region_obligation(origin, ty, r);
+            }
+        }
+
+        fn add_region_obligations_for_region_parameter(
+            fcx: &FnCtxt,
+            span: Span,
+            region_bounds: &[ty::Region],
+            region_param: ty::Region)
+        {
+            for &b in region_bounds.iter() {
+                // For each bound `region:b`, `b <= region` must hold
+                // (i.e., `region` must outlive `b`).
+                let origin = infer::RelateRegionParamBound(span);
+                fcx.mk_subr(origin, b, region_param);
+            }
+        }
+    }
 }
 
 pub enum LvaluePreference {
@@ -2269,7 +2652,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                            lvalue_pref: LvaluePreference,
                            unifier: ||)
 {
-    debug!(">> typechecking");
+    debug!(">> typechecking: expr={} expected={}",
+           expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
 
     // A generic function for doing all of the checking for call expressions
     fn check_call(fcx: &FnCtxt,
@@ -2674,17 +3058,19 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                              kind: ast::UnboxedClosureKind,
                              decl: &ast::FnDecl,
                              body: ast::P<ast::Block>) {
-        // The `RegionTraitStore` is a lie, but we ignore it so it doesn't
-        // matter.
-        //
-        // FIXME(pcwalton): Refactor this API.
         let mut fn_ty = astconv::ty_of_closure(
             fcx,
             expr.id,
             ast::NormalFn,
             ast::Many,
-            ty::empty_builtin_bounds(),
+
+            // The `RegionTraitStore` and region_existential_bounds
+            // are lies, but we ignore them so it doesn't matter.
+            //
+            // FIXME(pcwalton): Refactor this API.
+            ty::region_existential_bound(ty::ReStatic),
             ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
+
             decl,
             abi::RustCall,
             None);
@@ -2703,6 +3089,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
 
         check_fn(fcx.ccx,
                  ast::NormalFn,
+                 expr.id,
                  &fn_ty.sig,
                  decl,
                  expr.id,
@@ -2776,13 +3163,17 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                 }
                 _ => {
                     // Not an error! Means we're inferring the closure type
-                    let mut bounds = ty::empty_builtin_bounds();
-                    let onceness = match expr.node {
+                    let (bounds, onceness) = match expr.node {
                         ast::ExprProc(..) => {
-                            bounds.add(ty::BoundSend);
-                            ast::Once
+                            let mut bounds = ty::region_existential_bound(ty::ReStatic);
+                            bounds.builtin_bounds.add(ty::BoundSend); // FIXME
+                            (bounds, ast::Once)
+                        }
+                        _ => {
+                            let region = fcx.infcx().next_region_var(
+                                infer::AddrOfRegion(expr.span));
+                            (ty::region_existential_bound(region), ast::Many)
                         }
-                        _ => ast::Many
                     };
                     (None, onceness, bounds)
                 }
@@ -2808,7 +3199,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
         // If the closure is a stack closure and hasn't had some non-standard
         // style inferred for it, then check it under its parent's style.
         // Otherwise, use its own
-        let (inherited_style, id) = match store {
+        let (inherited_style, inherited_style_id) = match store {
             ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
                                          fcx.ps.borrow().def),
             ty::UniqTraitStore => (ast::NormalFn, expr.id)
@@ -2816,9 +3207,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
 
         check_fn(fcx.ccx,
                  inherited_style,
+                 inherited_style_id,
                  &fty_sig,
-                 decl,
-                 id,
+                 &*decl,
+                 expr.id,
                  &*body,
                  fcx.inh);
     }
@@ -3080,13 +3472,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                   // places: the exchange heap and the managed heap.
                   let definition = lookup_def(fcx, path.span, place.id);
                   let def_id = definition.def_id();
+                  let referent_ty = fcx.expr_ty(&**subexpr);
                   if tcx.lang_items.exchange_heap() == Some(def_id) {
-                      fcx.write_ty(id, ty::mk_uniq(tcx,
-                                                   fcx.expr_ty(&**subexpr)));
+                      fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty));
                       checked = true
                   } else if tcx.lang_items.managed_heap() == Some(def_id) {
-                      fcx.write_ty(id, ty::mk_box(tcx,
-                                                  fcx.expr_ty(&**subexpr)));
+                      fcx.register_region_obligation(infer::Managed(expr.span),
+                                                     referent_ty,
+                                                     ty::ReStatic);
+                      fcx.write_ty(id, ty::mk_box(tcx, referent_ty));
                       checked = true
                   }
               }
@@ -3270,7 +3664,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                 //ast::ExprLit(lit) if ast_util::lit_is_str(lit) => fcx.expr_ty(oprnd),
                 // Empty slices live in static memory.
                 ast::ExprVec(ref elements) if elements.len() == 0 => {
-                    ty::mk_rptr(tcx, ty::ReStatic, tm)
+                    // Note: we do not assign a lifetime of
+                    // static. This is because the resulting type
+                    // `&'static [T]` would require that T outlives
+                    // `'static`!
+                    let region = fcx.infcx().next_region_var(
+                        infer::AddrOfSlice(expr.span));
+                    ty::mk_rptr(tcx, region, tm)
                 }
                 _ => {
                     let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span));
@@ -3281,9 +3681,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
         fcx.write_ty(id, oprnd_t);
       }
       ast::ExprPath(ref pth) => {
-        let defn = lookup_def(fcx, pth.span, id);
-        let pty = polytype_for_def(fcx, expr.span, defn);
-        instantiate_path(fcx, pth, pty, defn, expr.span, expr.id);
+          let defn = lookup_def(fcx, pth.span, id);
+          let pty = polytype_for_def(fcx, expr.span, defn);
+          instantiate_path(fcx, pth, pty, defn, expr.span, expr.id);
+
+          // We always require that the type provided as the value for
+          // a type parameter outlives the moment of instantiation.
+          constrain_path_type_parameters(fcx, expr);
       }
       ast::ExprInlineAsm(ref ia) => {
           for &(_, ref input) in ia.inputs.iter() {
@@ -3708,6 +4112,18 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
     unifier();
 }
 
+fn constrain_path_type_parameters(fcx: &FnCtxt,
+                                  expr: &ast::Expr)
+{
+    fcx.opt_node_ty_substs(expr.id, |item_substs| {
+        for &ty in item_substs.substs.types.iter() {
+            let default_bound = ty::ReScope(expr.id);
+            let origin = infer::RelateDefaultParamBound(expr.span, ty);
+            fcx.register_region_obligation(origin, ty, default_bound);
+        }
+    });
+}
+
 impl Expectation {
     fn only_has_type(self) -> Expectation {
         match self {
@@ -3889,80 +4305,78 @@ fn check_block_with_expected(fcx: &FnCtxt,
         replace(&mut *fcx_ps, fn_style_state)
     };
 
-    fcx.with_region_lb(blk.id, || {
-        let mut warned = false;
-        let mut last_was_bot = false;
-        let mut any_bot = false;
-        let mut any_err = false;
-        for s in blk.stmts.iter() {
-            check_stmt(fcx, &**s);
-            let s_id = ast_util::stmt_id(&**s);
-            let s_ty = fcx.node_ty(s_id);
-            if last_was_bot && !warned && match s.node {
-                  ast::StmtDecl(decl, _) => {
-                      match decl.node {
-                          ast::DeclLocal(_) => true,
-                          _ => false,
-                      }
-                  }
-                  ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
-                  _ => false
-                } {
-                fcx.ccx
-                   .tcx
-                   .sess
-                   .add_lint(lint::builtin::UNREACHABLE_CODE,
-                             s_id,
-                             s.span,
-                             "unreachable statement".to_string());
-                warned = true;
-            }
-            if ty::type_is_bot(s_ty) {
-                last_was_bot = true;
+    let mut warned = false;
+    let mut last_was_bot = false;
+    let mut any_bot = false;
+    let mut any_err = false;
+    for s in blk.stmts.iter() {
+        check_stmt(fcx, &**s);
+        let s_id = ast_util::stmt_id(&**s);
+        let s_ty = fcx.node_ty(s_id);
+        if last_was_bot && !warned && match s.node {
+            ast::StmtDecl(decl, _) => {
+                match decl.node {
+                    ast::DeclLocal(_) => true,
+                    _ => false,
+                }
             }
-            any_bot = any_bot || ty::type_is_bot(s_ty);
-            any_err = any_err || ty::type_is_error(s_ty);
+            ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
+            _ => false
+        } {
+            fcx.ccx
+                .tcx
+                .sess
+                .add_lint(lint::builtin::UNREACHABLE_CODE,
+                          s_id,
+                          s.span,
+                          "unreachable statement".to_string());
+            warned = true;
         }
-        match blk.expr {
-            None => if any_err {
-                    fcx.write_error(blk.id);
-                }
-                else if any_bot {
-                    fcx.write_bot(blk.id);
+        if ty::type_is_bot(s_ty) {
+            last_was_bot = true;
+        }
+        any_bot = any_bot || ty::type_is_bot(s_ty);
+        any_err = any_err || ty::type_is_error(s_ty);
+    }
+    match blk.expr {
+        None => if any_err {
+            fcx.write_error(blk.id);
+        }
+        else if any_bot {
+            fcx.write_bot(blk.id);
+        }
+        else  {
+            fcx.write_nil(blk.id);
+        },
+        Some(e) => {
+            if any_bot && !warned {
+                fcx.ccx
+                    .tcx
+                    .sess
+                    .add_lint(lint::builtin::UNREACHABLE_CODE,
+                              e.id,
+                              e.span,
+                              "unreachable expression".to_string());
+            }
+            let ety = match expected {
+                ExpectHasType(ety) => {
+                    check_expr_coercable_to_type(fcx, &*e, ety);
+                    ety
                 }
-                else  {
-                    fcx.write_nil(blk.id);
-                },
-            Some(e) => {
-                if any_bot && !warned {
-                    fcx.ccx
-                       .tcx
-                       .sess
-                       .add_lint(lint::builtin::UNREACHABLE_CODE,
-                                 e.id,
-                                 e.span,
-                                 "unreachable expression".to_string());
+                _ => {
+                    check_expr_with_expectation(fcx, &*e, expected);
+                    fcx.expr_ty(&*e)
                 }
-                let ety = match expected {
-                    ExpectHasType(ety) => {
-                        check_expr_coercable_to_type(fcx, &*e, ety);
-                        ety
-                    }
-                    _ => {
-                        check_expr_with_expectation(fcx, &*e, expected);
-                        fcx.expr_ty(&*e)
-                    }
-                };
+            };
 
-                fcx.write_ty(blk.id, ety);
-                if any_err {
-                    fcx.write_error(blk.id);
-                } else if any_bot {
-                    fcx.write_bot(blk.id);
-                }
+            fcx.write_ty(blk.id, ety);
+            if any_err {
+                fcx.write_error(blk.id);
+            } else if any_bot {
+                fcx.write_bot(blk.id);
             }
-        };
-    });
+        }
+    };
 
     *fcx.ps.borrow_mut() = prev;
 }
@@ -3980,7 +4394,7 @@ pub fn check_const_in_type(tcx: &ty::ctxt,
         trait_map: NodeMap::new(),
         tcx: tcx,
     };
-    let inh = blank_inherited_fields(&ccx);
+    let inh = static_inherited_fields(&ccx);
     let fcx = blank_fn_ctxt(&ccx, &inh, expected_type, expr.id);
     check_const_with_ty(&fcx, expr.span, expr, expected_type);
 }
@@ -3989,7 +4403,7 @@ pub fn check_const(ccx: &CrateCtxt,
                    sp: Span,
                    e: &ast::Expr,
                    id: ast::NodeId) {
-    let inh = blank_inherited_fields(ccx);
+    let inh = static_inherited_fields(ccx);
     let rty = ty::node_id_to_type(ccx.tcx, id);
     let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
     let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
@@ -4184,7 +4598,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
                 Some(e) => {
                     debug!("disr expr, checking {}", pprust::expr_to_string(&*e));
 
-                    let inh = blank_inherited_fields(ccx);
+                    let inh = static_inherited_fields(ccx);
                     let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
                     let declty = match hint {
                         attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(),
@@ -4495,6 +4909,9 @@ pub fn instantiate_path(fcx: &FnCtxt,
         assert_eq!(substs.regions().len(space), region_defs.len(space));
     }
 
+    fcx.add_region_obligations_for_parameters(
+        span, &substs, &polytype.generics);
+
     fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts {
         substs: substs,
     });
@@ -4888,11 +5305,13 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
                   Ok(t) => t,
                   Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); }
               };
-              let region = ty::ReLateBound(it.id, ty::BrAnon(0));
-              let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
-                  Ok((_, vot)) => vot,
-                  Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); }
-              };
+              let region0 = ty::ReLateBound(it.id, ty::BrAnon(0));
+              let region1 = ty::ReLateBound(it.id, ty::BrAnon(1));
+              let visitor_object_ty =
+                    match ty::visitor_object_ty(tcx, region0, region1) {
+                        Ok((_, vot)) => vot,
+                        Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); }
+                    };
 
               let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
                   ty: tydesc_ty,
@@ -5097,3 +5516,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
     }
 }
 
+impl Repr for RegionObligation {
+    fn repr(&self, tcx: &ty::ctxt) -> String {
+        format!("RegionObligation(sub_region={}, sup_type={}, origin={})",
+                self.sub_region.repr(tcx),
+                self.sup_type.repr(tcx),
+                self.origin.repr(tcx))
+    }
+}
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 4f77c89e86c..72f33a2f984 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -126,14 +126,14 @@ use middle::ty::{ReScope};
 use middle::ty;
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::FnCtxt;
-use middle::typeck::check::regionmanip::relate_nested_regions;
+use middle::typeck::check::regionmanip;
 use middle::typeck::infer::resolve_and_force_all_but_regions;
 use middle::typeck::infer::resolve_type;
 use middle::typeck::infer;
 use middle::typeck::MethodCall;
 use middle::pat_util;
 use util::nodemap::{DefIdMap, NodeMap};
-use util::ppaux::{ty_to_string, region_to_string, Repr};
+use util::ppaux::{ty_to_string, Repr};
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -143,6 +143,46 @@ use syntax::visit::Visitor;
 use std::cell::RefCell;
 use std::gc::Gc;
 
+///////////////////////////////////////////////////////////////////////////
+// PUBLIC ENTRY POINTS
+
+pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
+    let mut rcx = Rcx::new(fcx, e.id);
+    if fcx.err_count_since_creation() == 0 {
+        // regionck assumes typeck succeeded
+        rcx.visit_expr(e, ());
+        rcx.visit_region_obligations(e.id);
+    }
+    fcx.infcx().resolve_regions_and_report_errors();
+}
+
+pub fn regionck_type_defn(fcx: &FnCtxt,
+                          span: Span,
+                          component_tys: &[ty::t]) {
+    let mut rcx = Rcx::new(fcx, 0);
+    for &component_ty in component_tys.iter() {
+        // Check that each type outlives the empty region. Since the
+        // empty region is a subregion of all others, this can't fail
+        // unless the type does not meet the well-formedness
+        // requirements.
+        type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span),
+                          component_ty, ty::ReEmpty);
+    }
+    fcx.infcx().resolve_regions_and_report_errors();
+}
+
+pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
+    let mut rcx = Rcx::new(fcx, blk.id);
+    if fcx.err_count_since_creation() == 0 {
+        // regionck assumes typeck succeeded
+        rcx.visit_fn_body(id, blk);
+    }
+    fcx.infcx().resolve_regions_and_report_errors();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// INTERNALS
+
 // If mem categorization results in an error, it's because the type
 // check failed (or will fail, when the error is uncovered and
 // reported during writeback). In this case, we just ignore this part
@@ -159,10 +199,32 @@ macro_rules! ignore_err(
 pub struct Rcx<'a> {
     fcx: &'a FnCtxt<'a>,
 
+    region_param_pairs: Vec<(ty::Region, ty::ParamTy)>,
+
     // id of innermost fn or loop
     repeating_scope: ast::NodeId,
 }
 
+/// When entering a function, we can derive relationships from the
+/// signature between various regions and type parameters. Consider
+/// a function like:
+///
+///     fn foo<'a, A>(x: &'a A) { ... }
+///
+/// Here, we can derive that `A` must outlive `'a`, because otherwise
+/// the caller would be illegal. We record this by storing a series of
+/// pairs (in this case, `('a, A)`). These pairs will be consulted
+/// later during regionck.
+///
+/// In the case of nested fns, additional relationships may be
+/// derived.  The result is a link list walking up the stack (hence
+/// the `previous` field).
+#[deriving(Clone)]
+pub struct RegionSubParamConstraints<'a> {
+    pairs: Vec<(ty::Region, ty::ParamTy)>,
+    previous: Option<&'a RegionSubParamConstraints<'a>>,
+}
+
 fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
     /*!
      * Returns the validity region of `def` -- that is, how long
@@ -189,6 +251,13 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
 }
 
 impl<'a> Rcx<'a> {
+    pub fn new(fcx: &'a FnCtxt<'a>,
+               initial_repeating_scope: ast::NodeId) -> Rcx<'a> {
+        Rcx { fcx: fcx,
+              repeating_scope: initial_repeating_scope,
+              region_param_pairs: Vec::new() }
+    }
+
     pub fn tcx(&self) -> &'a ty::ctxt {
         self.fcx.ccx.tcx
     }
@@ -259,6 +328,114 @@ impl<'a> Rcx<'a> {
                           |method_call| self.resolve_method_type(method_call))
         }
     }
+
+    fn visit_fn_body(&mut self,
+                     id: ast::NodeId,
+                     body: &ast::Block)
+    {
+        // When we enter a function, we can derive
+
+        let fn_sig_map = self.fcx.inh.fn_sig_map.borrow();
+        let fn_sig = match fn_sig_map.find(&id) {
+            Some(f) => f,
+            None => {
+                self.tcx().sess.bug(
+                    format!("No fn-sig entry for id={}", id).as_slice());
+            }
+        };
+
+        let len = self.region_param_pairs.len();
+        self.relate_free_regions(fn_sig.as_slice(), body.id);
+        self.visit_block(body, ());
+        self.visit_region_obligations(body.id);
+        self.region_param_pairs.truncate(len);
+    }
+
+    fn visit_region_obligations(&mut self, node_id: ast::NodeId)
+    {
+        debug!("visit_region_obligations: node_id={}", node_id);
+        let region_obligations = self.fcx.inh.region_obligations.borrow();
+        match region_obligations.find(&node_id) {
+            None => { }
+            Some(vec) => {
+                for r_o in vec.iter() {
+                    debug!("visit_region_obligations: r_o={}",
+                           r_o.repr(self.tcx()));
+                    let sup_type = self.resolve_type(r_o.sup_type);
+                    type_must_outlive(self, r_o.origin.clone(),
+                                      sup_type, r_o.sub_region);
+                }
+            }
+        }
+    }
+
+    fn relate_free_regions(&mut self,
+                           fn_sig_tys: &[ty::t],
+                           body_id: ast::NodeId) {
+        /*!
+         * This method populates the region map's `free_region_map`.
+         * It walks over the transformed argument and return types for
+         * each function just before we check the body of that
+         * function, looking for types where you have a borrowed
+         * pointer to other borrowed data (e.g., `&'a &'b [uint]`.  We
+         * do not allow references to outlive the things they point
+         * at, so we can assume that `'a <= 'b`. This holds for both
+         * the argument and return types, basically because, on the caller
+         * side, the caller is responsible for checking that the type of
+         * every expression (including the actual values for the arguments,
+         * as well as the return type of the fn call) is well-formed.
+         *
+         * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
+         */
+
+        debug!("relate_free_regions >>");
+        let tcx = self.tcx();
+
+        for &ty in fn_sig_tys.iter() {
+            let ty = self.resolve_type(ty);
+            debug!("relate_free_regions(t={})", ty.repr(tcx));
+            let body_scope = ty::ReScope(body_id);
+            let constraints =
+                regionmanip::region_wf_constraints(
+                    tcx,
+                    ty,
+                    body_scope);
+            for constraint in constraints.iter() {
+                debug!("constraint: {}", constraint.repr(tcx));
+                match *constraint {
+                    regionmanip::RegionSubRegionConstraint(_,
+                                              ty::ReFree(free_a),
+                                              ty::ReFree(free_b)) => {
+                        tcx.region_maps.relate_free_regions(free_a, free_b);
+                    }
+                    regionmanip::RegionSubRegionConstraint(_,
+                                              ty::ReFree(free_a),
+                                              ty::ReInfer(ty::ReVar(vid_b))) => {
+                        self.fcx.inh.infcx.add_given(free_a, vid_b);
+                    }
+                    regionmanip::RegionSubRegionConstraint(..) => {
+                        // In principle, we could record (and take
+                        // advantage of) every relationship here, but
+                        // we are also free not to -- it simply means
+                        // strictly less that we can successfully type
+                        // check. (It may also be that we should
+                        // revise our inference system to be more
+                        // general and to make use of *every*
+                        // relationship that arises here, but
+                        // presently we do not.)
+                    }
+                    regionmanip::RegionSubParamConstraint(_, r_a, p_b) => {
+                        debug!("RegionSubParamConstraint: {} <= {}",
+                               r_a.repr(tcx), p_b.repr(tcx));
+
+                        self.region_param_pairs.push((r_a, p_b));
+                    }
+                }
+            }
+        }
+
+        debug!("<< relate_free_regions");
+    }
 }
 
 impl<'fcx> mc::Typer for Rcx<'fcx> {
@@ -302,26 +479,6 @@ impl<'fcx> mc::Typer for Rcx<'fcx> {
     }
 }
 
-pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
-    let mut rcx = Rcx { fcx: fcx, repeating_scope: e.id };
-    let rcx = &mut rcx;
-    if fcx.err_count_since_creation() == 0 {
-        // regionck assumes typeck succeeded
-        rcx.visit_expr(e, ());
-    }
-    fcx.infcx().resolve_regions_and_report_errors();
-}
-
-pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
-    let mut rcx = Rcx { fcx: fcx, repeating_scope: blk.id };
-    let rcx = &mut rcx;
-    if fcx.err_count_since_creation() == 0 {
-        // regionck assumes typeck succeeded
-        rcx.visit_block(blk, ());
-    }
-    fcx.infcx().resolve_regions_and_report_errors();
-}
-
 impl<'a> Visitor<()> for Rcx<'a> {
     // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
     // However, right now we run into an issue whereby some free
@@ -331,6 +488,11 @@ impl<'a> Visitor<()> for Rcx<'a> {
     // hierarchy, and in particular the relationships between free
     // regions, until regionck, as described in #3238.
 
+    fn visit_fn(&mut self, _fk: &visit::FnKind, _fd: &ast::FnDecl,
+                b: &ast::Block, _s: Span, id: ast::NodeId, _e: ()) {
+        self.visit_fn_body(id, b)
+    }
+
     fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
 
     fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
@@ -396,9 +558,9 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
         // variable's type enclose at least the variable's scope.
 
         let var_region = tcx.region_maps.var_region(id);
-        constrain_regions_in_type_of_node(
-            rcx, id, var_region,
-            infer::BindingTypeIsNotValidAtDecl(span));
+        type_of_node_must_outlive(
+            rcx, infer::BindingTypeIsNotValidAtDecl(span),
+            id, var_region);
     })
 }
 
@@ -406,6 +568,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
            expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
 
+    // No matter what, the type of each expression must outlive the
+    // scope of that expression. This also guarantees basic WF.
+    let expr_ty = rcx.resolve_node_type(expr.id);
+
+    type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span),
+                      expr_ty, ty::ReScope(expr.id));
+
     let method_call = MethodCall::expr(expr.id);
     let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
 
@@ -416,40 +585,28 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
                 let expr_ty = rcx.resolve_node_type(expr.id);
                 constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
-                match ty::adjusted_object_region(adjustment) {
-                    Some(trait_region) => {
-                        // Determine if we are casting `expr` to a trait
-                        // instance.  If so, we have to be sure that the type of
-                        // the source obeys the trait's region bound.
-                        //
-                        // Note: there is a subtle point here concerning type
-                        // parameters.  It is possible that the type of `source`
-                        // contains type parameters, which in turn may contain
-                        // regions that are not visible to us (only the caller
-                        // knows about them).  The kind checker is ultimately
-                        // responsible for guaranteeing region safety in that
-                        // particular case.  There is an extensive comment on the
-                        // function check_cast_for_escaping_regions() in kind.rs
-                        // explaining how it goes about doing that.
-
-                        constrain_regions_in_type(rcx, trait_region,
-                                                  infer::RelateObjectBound(expr.span), expr_ty);
-                    }
-                    None => {
-                        for autoref in opt_autoref.iter() {
-                            link_autoref(rcx, expr, autoderefs, autoref);
-
-                            // Require that the resulting region encompasses
-                            // the current node.
-                            //
-                            // FIXME(#6268) remove to support nested method calls
-                            constrain_regions_in_type_of_node(
-                                rcx, expr.id, ty::ReScope(expr.id),
-                                infer::AutoBorrow(expr.span));
-                        }
-                    }
+                for autoref in opt_autoref.iter() {
+                    link_autoref(rcx, expr, autoderefs, autoref);
+
+                    // Require that the resulting region encompasses
+                    // the current node.
+                    //
+                    // FIXME(#6268) remove to support nested method calls
+                    type_of_node_must_outlive(
+                        rcx, infer::AutoBorrow(expr.span),
+                        expr.id, ty::ReScope(expr.id));
                 }
             }
+            /*
+            ty::AutoObject(_, ref bounds, _, _) => {
+                // Determine if we are casting `expr` to a trait
+                // instance. If so, we have to be sure that the type
+                // of the source obeys the new region bound.
+                let source_ty = rcx.resolve_node_type(expr.id);
+                type_must_outlive(rcx, infer::RelateObjectBound(expr.span),
+                                  source_ty, bounds.region_bound);
+            }
+            */
             _ => {}
         }
     }
@@ -457,12 +614,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     match expr.node {
         ast::ExprCall(ref callee, ref args) => {
             if has_method_map {
-                constrain_call(rcx, None, expr, Some(*callee),
+                constrain_call(rcx, expr, Some(*callee),
                                args.as_slice(), false);
             } else {
                 constrain_callee(rcx, callee.id, expr, &**callee);
                 constrain_call(rcx,
-                               Some(callee.id),
                                expr,
                                None,
                                args.as_slice(),
@@ -473,7 +629,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
         }
 
         ast::ExprMethodCall(_, _, ref args) => {
-            constrain_call(rcx, None, expr, Some(*args.get(0)),
+            constrain_call(rcx, expr, Some(*args.get(0)),
                            args.slice_from(1), false);
 
             visit::walk_expr(rcx, expr, ());
@@ -486,7 +642,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
 
         ast::ExprAssignOp(_, ref lhs, ref rhs) => {
             if has_method_map {
-                constrain_call(rcx, None, expr, Some(lhs.clone()),
+                constrain_call(rcx, expr, Some(lhs.clone()),
                                [rhs.clone()], true);
             }
 
@@ -501,7 +657,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             // overloaded op.  Note that we (sadly) currently use an
             // implicit "by ref" sort of passing style here.  This
             // should be converted to an adjustment!
-            constrain_call(rcx, None, expr, Some(lhs.clone()),
+            constrain_call(rcx, expr, Some(lhs.clone()),
                            [rhs.clone()], true);
 
             visit::walk_expr(rcx, expr, ());
@@ -509,8 +665,16 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
 
         ast::ExprUnary(_, ref lhs) if has_method_map => {
             // As above.
-            constrain_call(rcx, None, expr, Some(lhs.clone()), [], true);
+            constrain_call(rcx, expr, Some(lhs.clone()), [], true);
+
+            visit::walk_expr(rcx, expr, ());
+        }
 
+        ast::ExprUnary(ast::UnBox, ref base) => {
+            // Managed data must not have borrowed pointers within it:
+            let base_ty = rcx.resolve_node_type(base.id);
+            type_must_outlive(rcx, infer::Managed(expr.span),
+                              base_ty, ty::ReStatic);
             visit::walk_expr(rcx, expr, ());
         }
 
@@ -519,7 +683,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             let method_call = MethodCall::expr(expr.id);
             let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
                 Some(method) => {
-                    constrain_call(rcx, None, expr, Some(base.clone()), [], true);
+                    constrain_call(rcx, expr, Some(base.clone()), [], true);
                     ty::ty_fn_ret(method.ty)
                 }
                 None => rcx.resolve_node_type(base.id)
@@ -547,34 +711,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             // Determine if we are casting `source` to a trait
             // instance.  If so, we have to be sure that the type of
             // the source obeys the trait's region bound.
-            //
-            // Note: there is a subtle point here concerning type
-            // parameters.  It is possible that the type of `source`
-            // contains type parameters, which in turn may contain
-            // regions that are not visible to us (only the caller
-            // knows about them).  The kind checker is ultimately
-            // responsible for guaranteeing region safety in that
-            // particular case.  There is an extensive comment on the
-            // function check_cast_for_escaping_regions() in kind.rs
-            // explaining how it goes about doing that.
-            let target_ty = rcx.resolve_node_type(expr.id);
-            match ty::get(target_ty).sty {
-                ty::ty_rptr(trait_region, ty::mt{ty, ..}) => {
-                    match ty::get(ty).sty {
-                        ty::ty_trait(..) => {
-                            let source_ty = rcx.resolve_expr_type_adjusted(&**source);
-                            constrain_regions_in_type(
-                                rcx,
-                                trait_region,
-                                infer::RelateObjectBound(expr.span),
-                                source_ty);
-                        }
-                        _ => {}
-                    }
-                }
-                _ => ()
-            }
-
+            constrain_cast(rcx, expr, &**source);
             visit::walk_expr(rcx, expr, ());
         }
 
@@ -589,8 +726,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             //
             // FIXME(#6268) nested method calls requires that this rule change
             let ty0 = rcx.resolve_node_type(expr.id);
-            constrain_regions_in_type(rcx, ty::ReScope(expr.id),
-                                      infer::AddrOf(expr.span), ty0);
+            type_must_outlive(rcx, infer::AddrOf(expr.span),
+                              ty0, ty::ReScope(expr.id));
             visit::walk_expr(rcx, expr, ());
         }
 
@@ -644,42 +781,108 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     }
 }
 
+fn constrain_cast(rcx: &mut Rcx,
+                  cast_expr: &ast::Expr,
+                  source_expr: &ast::Expr)
+{
+    debug!("constrain_cast(cast_expr={}, source_expr={})",
+           cast_expr.repr(rcx.tcx()),
+           source_expr.repr(rcx.tcx()));
+
+    let source_ty = rcx.resolve_node_type(source_expr.id);
+    let target_ty = rcx.resolve_node_type(cast_expr.id);
+
+    walk_cast(rcx, cast_expr, source_ty, target_ty);
+
+    fn walk_cast(rcx: &mut Rcx,
+                 cast_expr: &ast::Expr,
+                 from_ty: ty::t,
+                 to_ty: ty::t) {
+        debug!("walk_cast(from_ty={}, to_ty={})",
+               from_ty.repr(rcx.tcx()),
+               to_ty.repr(rcx.tcx()));
+        match (&ty::get(from_ty).sty, &ty::get(to_ty).sty) {
+            /*From:*/ (&ty::ty_rptr(from_r, ref from_mt),
+            /*To:  */  &ty::ty_rptr(to_r, ref to_mt)) => {
+                // Target cannot outlive source, naturally.
+                rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), to_r, from_r);
+                walk_cast(rcx, cast_expr, from_mt.ty, to_mt.ty);
+            }
+
+            /*From:*/ (_,
+            /*To:  */  &ty::ty_trait(box ty::TyTrait { bounds, .. })) => {
+                // When T is existentially quantified as a trait
+                // `Foo+'to`, it must outlive the region bound `'to`.
+                type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span),
+                                  from_ty, bounds.region_bound);
+            }
+
+            /*From:*/ (&ty::ty_uniq(from_referent_ty),
+            /*To:  */  &ty::ty_uniq(to_referent_ty)) => {
+                walk_cast(rcx, cast_expr, from_referent_ty, to_referent_ty);
+            }
+
+            _ => { }
+        }
+    }
+}
+
 fn check_expr_fn_block(rcx: &mut Rcx,
                        expr: &ast::Expr,
                        body: &ast::Block) {
     let tcx = rcx.fcx.tcx();
     let function_type = rcx.resolve_node_type(expr.id);
+
     match ty::get(function_type).sty {
-        ty::ty_closure(box ty::ClosureTy {
-                store: ty::RegionTraitStore(region, _), ..}) => {
+        ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..),
+                                         bounds: ref bounds,
+                                         ..}) => {
+            // For closure, ensure that the variables outlive region
+            // bound, since they are captured by reference.
             freevars::with_freevars(tcx, expr.id, |freevars| {
                 if freevars.is_empty() {
                     // No free variables means that the environment
                     // will be NULL at runtime and hence the closure
                     // has static lifetime.
                 } else {
-                    // Closure must not outlive the variables it closes over.
-                    constrain_free_variables(rcx, region, expr, freevars);
+                    // Variables being referenced must outlive closure.
+                    constrain_free_variables_in_stack_closure(
+                        rcx, bounds.region_bound, expr, freevars);
 
-                    // Closure cannot outlive the appropriate temporary scope.
+                    // Closure is stack allocated and hence cannot
+                    // outlive the appropriate temporary scope.
                     let s = rcx.repeating_scope;
-                    rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
-                                    region, ty::ReScope(s));
+                    rcx.fcx.mk_subr(infer::InfStackClosure(expr.span),
+                                    bounds.region_bound, ty::ReScope(s));
                 }
             });
         }
+        ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore,
+                                         bounds: ref bounds,
+                                         ..}) => {
+            // For proc, ensure that the *types* of the variables
+            // outlive region bound, since they are captured by value.
+            freevars::with_freevars(tcx, expr.id, |freevars| {
+                ensure_free_variable_types_outlive_closure_bound(
+                    rcx, bounds.region_bound, expr, freevars);
+            });
+        }
         ty::ty_unboxed_closure(_, region) => {
             freevars::with_freevars(tcx, expr.id, |freevars| {
                 // No free variables means that there is no environment and
                 // hence the closure has static lifetime. Otherwise, the
                 // closure must not outlive the variables it closes over
                 // by-reference.
+                //
+                // NDM -- this seems wrong, discuss with pcwalton, should
+                // be straightforward enough.
                 if !freevars.is_empty() {
-                    constrain_free_variables(rcx, region, expr, freevars);
+                    ensure_free_variable_types_outlive_closure_bound(
+                        rcx, region, expr, freevars);
                 }
             })
         }
-        _ => ()
+        _ => { }
     }
 
     let repeating_scope = rcx.set_repeating_scope(body.id);
@@ -698,36 +901,74 @@ fn check_expr_fn_block(rcx: &mut Rcx,
         _ => ()
     }
 
-    fn constrain_free_variables(rcx: &mut Rcx,
-                                region: ty::Region,
-                                expr: &ast::Expr,
-                                freevars: &[freevars::freevar_entry]) {
+    fn ensure_free_variable_types_outlive_closure_bound(
+        rcx: &mut Rcx,
+        region_bound: ty::Region,
+        expr: &ast::Expr,
+        freevars: &[freevars::freevar_entry])
+    {
         /*!
-         * Make sure that all free variables referenced inside the closure
-         * outlive the closure itself. Also, create an entry in the
-         * upvar_borrows map with a region.
+         * Make sure that the type of all free variables referenced
+         * inside a closure/proc outlive the closure/proc's lifetime
+         * bound. This is just a special case of the usual rules about
+         * closed over values outliving the object's lifetime bound.
+         */
+
+        let tcx = rcx.fcx.ccx.tcx;
+
+        debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
+               region_bound.repr(tcx), expr.repr(tcx));
+
+        for freevar in freevars.iter() {
+            let var_node_id = {
+                let def_id = freevar.def.def_id();
+                assert!(def_id.krate == ast::LOCAL_CRATE);
+                def_id.node
+            };
+
+            let var_ty = rcx.resolve_node_type(var_node_id);
+
+            type_must_outlive(
+                rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
+                var_ty, region_bound);
+        }
+    }
+
+    fn constrain_free_variables_in_stack_closure(
+        rcx: &mut Rcx,
+        region_bound: ty::Region,
+        expr: &ast::Expr,
+        freevars: &[freevars::freevar_entry])
+    {
+        /*!
+         * Make sure that all free variables referenced inside the
+         * closure outlive the closure's lifetime bound. Also, create
+         * an entry in the upvar_borrows map with a region.
          */
 
         let tcx = rcx.fcx.ccx.tcx;
         let infcx = rcx.fcx.infcx();
         debug!("constrain_free_variables({}, {})",
-               region.repr(tcx), expr.repr(tcx));
+               region_bound.repr(tcx), expr.repr(tcx));
         for freevar in freevars.iter() {
             debug!("freevar def is {:?}", freevar.def);
 
             // Identify the variable being closed over and its node-id.
             let def = freevar.def;
-            let def_id = def.def_id();
-            assert!(def_id.krate == ast::LOCAL_CRATE);
-            let upvar_id = ty::UpvarId { var_id: def_id.node,
+            let var_node_id = {
+                let def_id = def.def_id();
+                assert!(def_id.krate == ast::LOCAL_CRATE);
+                def_id.node
+            };
+            let upvar_id = ty::UpvarId { var_id: var_node_id,
                                          closure_expr_id: expr.id };
 
             // Create a region variable to represent this borrow. This borrow
             // must outlive the region on the closure.
             let origin = infer::UpvarRegion(upvar_id, expr.span);
             let freevar_region = infcx.next_region_var(origin);
-            rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
-                            region, freevar_region);
+            rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
+                            region_bound, freevar_region);
 
             // Create a UpvarBorrow entry. Note that we begin with a
             // const borrow_kind, but change it to either mut or
@@ -738,10 +979,10 @@ fn check_expr_fn_block(rcx: &mut Rcx,
                                                              upvar_borrow);
 
             // Guarantee that the closure does not outlive the variable itself.
-            let en_region = region_of_def(rcx.fcx, def);
-            debug!("en_region = {}", en_region.repr(tcx));
-            rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
-                            region, en_region);
+            let enclosing_region = region_of_def(rcx.fcx, def);
+            debug!("enclosing_region = {}", enclosing_region.repr(tcx));
+            rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
+                            region_bound, enclosing_region);
         }
     }
 
@@ -817,7 +1058,7 @@ fn constrain_callee(rcx: &mut Rcx,
                 }
                 ty::UniqTraitStore => ty::ReStatic
             };
-            rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
+            rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
                             call_region, region);
         }
         _ => {
@@ -832,9 +1073,6 @@ fn constrain_callee(rcx: &mut Rcx,
 }
 
 fn constrain_call(rcx: &mut Rcx,
-                  // might be expr_call, expr_method_call, or an overloaded
-                  // operator
-                  fn_expr_id: Option<ast::NodeId>,
                   call_expr: &ast::Expr,
                   receiver: Option<Gc<ast::Expr>>,
                   arg_exprs: &[Gc<ast::Expr>],
@@ -853,16 +1091,6 @@ fn constrain_call(rcx: &mut Rcx,
             receiver.repr(tcx),
             arg_exprs.repr(tcx),
             implicitly_ref_args);
-    let callee_ty = match fn_expr_id {
-        Some(id) => rcx.resolve_node_type(id),
-        None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
-                   .expect("call should have been to a method")
-    };
-    if ty::type_is_error(callee_ty) {
-        // Bail, as function type is unknown
-        return;
-    }
-    let fn_sig = ty::ty_fn_sig(callee_ty);
 
     // `callee_region` is the scope representing the time in which the
     // call occurs.
@@ -871,14 +1099,16 @@ fn constrain_call(rcx: &mut Rcx,
     let callee_scope = call_expr.id;
     let callee_region = ty::ReScope(callee_scope);
 
+    debug!("callee_region={}", callee_region.repr(tcx));
+
     for arg_expr in arg_exprs.iter() {
-        debug!("Argument");
+        debug!("Argument: {}", arg_expr.repr(tcx));
 
         // ensure that any regions appearing in the argument type are
         // valid for at least the lifetime of the function:
-        constrain_regions_in_type_of_node(
-            rcx, arg_expr.id, callee_region,
-            infer::CallArg(arg_expr.span));
+        type_of_node_must_outlive(
+            rcx, infer::CallArg(arg_expr.span),
+            arg_expr.id, callee_region);
 
         // unfortunately, there are two means of taking implicit
         // references, and we need to propagate constraints as a
@@ -891,19 +1121,14 @@ fn constrain_call(rcx: &mut Rcx,
 
     // as loop above, but for receiver
     for r in receiver.iter() {
-        debug!("Receiver");
-        constrain_regions_in_type_of_node(
-            rcx, r.id, callee_region, infer::CallRcvr(r.span));
+        debug!("receiver: {}", r.repr(tcx));
+        type_of_node_must_outlive(
+            rcx, infer::CallRcvr(r.span),
+            r.id, callee_region);
         if implicitly_ref_args {
             link_by_ref(rcx, &**r, callee_scope);
         }
     }
-
-    // constrain regions that may appear in the return type to be
-    // valid for the function call:
-    constrain_regions_in_type(
-        rcx, callee_region, infer::CallReturn(call_expr.span),
-        fn_sig.output);
 }
 
 fn constrain_autoderefs(rcx: &mut Rcx,
@@ -942,12 +1167,10 @@ fn constrain_autoderefs(rcx: &mut Rcx,
                 }
 
                 // Specialized version of constrain_call.
-                constrain_regions_in_type(rcx, r_deref_expr,
-                                          infer::CallRcvr(deref_expr.span),
-                                          self_ty);
-                constrain_regions_in_type(rcx, r_deref_expr,
-                                          infer::CallReturn(deref_expr.span),
-                                          fn_sig.output);
+                type_must_outlive(rcx, infer::CallRcvr(deref_expr.span),
+                                  self_ty, r_deref_expr);
+                type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
+                                  fn_sig.output, r_deref_expr);
                 fn_sig.output
             }
             None => derefd_ty
@@ -974,7 +1197,7 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
                                        deref_span: Span,
                                        minimum_lifetime: ty::Region,
                                        maximum_lifetime: ty::Region) {
-    rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
+    rcx.fcx.mk_subr(infer::DerefPointer(deref_span),
                     minimum_lifetime, maximum_lifetime)
 }
 
@@ -996,7 +1219,7 @@ fn constrain_index(rcx: &mut Rcx,
     match ty::get(indexed_ty).sty {
         ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
             ty::ty_vec(_, None) | ty::ty_str => {
-                rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
+                rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span),
                                 r_index_expr, r_ptr);
             }
             _ => {}
@@ -1006,14 +1229,17 @@ fn constrain_index(rcx: &mut Rcx,
     }
 }
 
-fn constrain_regions_in_type_of_node(
+fn type_of_node_must_outlive(
     rcx: &mut Rcx,
+    origin: infer::SubregionOrigin,
     id: ast::NodeId,
-    minimum_lifetime: ty::Region,
-    origin: infer::SubregionOrigin) {
-    //! Guarantees that any lifetimes which appear in the type of
-    //! the node `id` (after applying adjustments) are valid for at
-    //! least `minimum_lifetime`
+    minimum_lifetime: ty::Region)
+{
+    /*!
+     * Guarantees that any lifetimes which appear in the type of
+     * the node `id` (after applying adjustments) are valid for at
+     * least `minimum_lifetime`
+     */
 
     let tcx = rcx.fcx.tcx();
 
@@ -1028,54 +1254,7 @@ fn constrain_regions_in_type_of_node(
             ty={}, ty0={}, id={}, minimum_lifetime={:?})",
            ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
            id, minimum_lifetime);
-    constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
-}
-
-fn constrain_regions_in_type(
-    rcx: &mut Rcx,
-    minimum_lifetime: ty::Region,
-    origin: infer::SubregionOrigin,
-    ty: ty::t) {
-    /*!
-     * Requires that any regions which appear in `ty` must be
-     * superregions of `minimum_lifetime`.  Also enforces the constraint
-     * that given a pointer type `&'r T`, T must not contain regions
-     * that outlive 'r, as well as analogous constraints for other
-     * lifetime'd types.
-     *
-     * This check prevents regions from being used outside of the block in
-     * which they are valid.  Recall that regions represent blocks of
-     * code or expressions: this requirement basically says "any place
-     * that uses or may use a region R must be within the block of
-     * code that R corresponds to."
-     */
-
-    let tcx = rcx.fcx.ccx.tcx;
-
-    debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
-           region_to_string(tcx, "", false, minimum_lifetime),
-           ty_to_string(tcx, ty));
-
-    relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
-        debug!("relate_nested_regions(r_sub={}, r_sup={})",
-                r_sub.repr(tcx),
-                r_sup.repr(tcx));
-
-        if r_sup.is_bound() || r_sub.is_bound() {
-            // a bound region is one which appears inside an fn type.
-            // (e.g., the `&` in `fn(&T)`).  Such regions need not be
-            // constrained by `minimum_lifetime` as they are placeholders
-            // for regions that are as-yet-unknown.
-        } else if r_sub == minimum_lifetime {
-            rcx.fcx.mk_subr(
-                true, origin.clone(),
-                r_sub, r_sup);
-        } else {
-            rcx.fcx.mk_subr(
-                true, infer::ReferenceOutlivesReferent(ty, origin.span()),
-                r_sub, r_sup);
-        }
-    });
+    type_must_outlive(rcx, origin, ty, minimum_lifetime);
 }
 
 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
@@ -1290,7 +1469,7 @@ fn link_region(rcx: &Rcx,
                 debug!("link_region: {} <= {}",
                        region_min.repr(rcx.tcx()),
                        r_borrowed.repr(rcx.tcx()));
-                rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
+                rcx.fcx.mk_subr(cause, region_min, r_borrowed);
 
                 if kind != ty::ImmBorrow {
                     // If this is a mutable borrow, then the thing
@@ -1522,3 +1701,99 @@ fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
         }
     }
 }
+
+fn type_must_outlive(rcx: &mut Rcx,
+                     origin: infer::SubregionOrigin,
+                     ty: ty::t,
+                     region: ty::Region)
+{
+    /*!
+     * Ensures that all borrowed data reachable via `ty` outlives `region`.
+     */
+
+    debug!("type_must_outlive(ty={}, region={})",
+           ty.repr(rcx.tcx()),
+           region.repr(rcx.tcx()));
+
+    let constraints =
+        regionmanip::region_wf_constraints(
+            rcx.tcx(),
+            ty,
+            region);
+    for constraint in constraints.iter() {
+        debug!("constraint: {}", constraint.repr(rcx.tcx()));
+        match *constraint {
+            regionmanip::RegionSubRegionConstraint(None, r_a, r_b) => {
+                rcx.fcx.mk_subr(origin.clone(), r_a, r_b);
+            }
+            regionmanip::RegionSubRegionConstraint(Some(ty), r_a, r_b) => {
+                let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
+                rcx.fcx.mk_subr(o1, r_a, r_b);
+            }
+            regionmanip::RegionSubParamConstraint(None, r_a, param_b) => {
+                param_must_outlive(rcx, origin.clone(), r_a, param_b);
+            }
+            regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => {
+                let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
+                param_must_outlive(rcx, o1, r_a, param_b);
+            }
+        }
+    }
+}
+
+fn param_must_outlive(rcx: &Rcx,
+                      origin: infer::SubregionOrigin,
+                      region: ty::Region,
+                      param_ty: ty::ParamTy) {
+    let param_env = &rcx.fcx.inh.param_env;
+
+    debug!("param_must_outlive(region={}, param_ty={})",
+           region.repr(rcx.tcx()),
+           param_ty.repr(rcx.tcx()));
+
+    // Collect all regions that `param_ty` is known to outlive into
+    // this vector:
+    let mut param_bounds;
+
+    // To start, collect bounds from user:
+    let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx);
+    param_bounds =
+        ty::required_region_bounds(rcx.tcx(),
+                                   param_bound.opt_region_bound.as_slice(),
+                                   param_bound.builtin_bounds,
+                                   param_bound.trait_bounds.as_slice());
+
+    // Collect default bound of fn body that applies to all in scope
+    // type parameters:
+    param_bounds.push(param_env.implicit_region_bound);
+
+    // Finally, collect regions we scraped from the well-formedness
+    // constraints in the fn signature. To do that, we walk the list
+    // of known relations from the fn ctxt.
+    //
+    // This is crucial because otherwise code like this fails:
+    //
+    //     fn foo<'a, A>(x: &'a A) { x.bar() }
+    //
+    // The problem is that the type of `x` is `&'a A`. To be
+    // well-formed, then, A must be lower-bounded by `'a`, but we
+    // don't know that this holds from first principles.
+    for &(ref r, ref p) in rcx.region_param_pairs.iter() {
+        debug!("param_ty={}/{} p={}/{}",
+               param_ty.repr(rcx.tcx()),
+               param_ty.def_id,
+               p.repr(rcx.tcx()),
+               p.def_id);
+        if param_ty == *p {
+            param_bounds.push(*r);
+        }
+    }
+
+    // Inform region inference that this parameter type must be
+    // properly bounded.
+    infer::verify_param_bound(rcx.fcx.infcx(),
+                              origin,
+                              param_ty,
+                              region,
+                              param_bounds);
+}
diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs
index 53e26f8696f..577da159162 100644
--- a/src/librustc/middle/typeck/check/regionmanip.rs
+++ b/src/librustc/middle/typeck/check/regionmanip.rs
@@ -10,13 +10,15 @@
 
 // #![warn(deprecated_mode)]
 
+use middle::subst::{ParamSpace, Subst, Substs};
 use middle::ty;
 use middle::ty_fold;
 use middle::ty_fold::TypeFolder;
 
+use syntax::ast;
+
 use std::collections::HashMap;
 use util::ppaux::Repr;
-use util::ppaux;
 
 // Helper functions related to manipulating region types.
 
@@ -44,125 +46,363 @@ pub fn replace_late_bound_regions_in_fn_sig(
     (map, fn_sig)
 }
 
-pub fn relate_nested_regions(tcx: &ty::ctxt,
-                             opt_region: Option<ty::Region>,
-                             ty: ty::t,
-                             relate_op: |ty::Region, ty::Region|) {
+pub enum WfConstraint {
+    RegionSubRegionConstraint(Option<ty::t>, ty::Region, ty::Region),
+    RegionSubParamConstraint(Option<ty::t>, ty::Region, ty::ParamTy),
+}
+
+struct Wf<'a> {
+    tcx: &'a ty::ctxt,
+    stack: Vec<(ty::Region, Option<ty::t>)>,
+    out: Vec<WfConstraint>,
+}
+
+pub fn region_wf_constraints(
+    tcx: &ty::ctxt,
+    ty: ty::t,
+    outer_region: ty::Region)
+    -> Vec<WfConstraint>
+{
     /*!
-     * This rather specialized function walks each region `r` that appear
-     * in `ty` and invokes `relate_op(r_encl, r)` for each one.  `r_encl`
-     * here is the region of any enclosing `&'r T` pointer.  If there is
-     * no enclosing pointer, and `opt_region` is Some, then `opt_region.get()`
-     * is used instead.  Otherwise, no callback occurs at all).
-     *
-     * Here are some examples to give you an intution:
-     *
-     * - `relate_nested_regions(Some('r1), &'r2 uint)` invokes
-     *   - `relate_op('r1, 'r2)`
-     * - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes
-     *   - `relate_op('r1, 'r2)`
-     *   - `relate_op('r2, 'r3)`
-     * - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes
-     *   - `relate_op('r2, 'r3)`
-     * - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes
-     *   - `relate_op('r2, 'r3)`
-     *   - `relate_op('r2, 'r4)`
-     *   - `relate_op('r3, 'r4)`
-     *
-     * This function is used in various pieces of code because we enforce the
-     * constraint that a region pointer cannot outlive the things it points at.
-     * Hence, in the second example above, `'r2` must be a subregion of `'r3`.
+     * This routine computes the well-formedness constraints that must
+     * hold for the type `ty` to appear in a context with lifetime
+     * `outer_region`
      */
 
-    let mut rr = RegionRelator { tcx: tcx,
-                                 stack: Vec::new(),
-                                 relate_op: relate_op };
-    match opt_region {
-        Some(o_r) => { rr.stack.push(o_r); }
-        None => {}
-    }
-    rr.fold_ty(ty);
+    let mut stack = Vec::new();
+    stack.push((outer_region, None));
+    let mut wf = Wf { tcx: tcx,
+                      stack: stack,
+                      out: Vec::new() };
+    wf.accumulate_from_ty(ty);
+    wf.out
+}
 
-    struct RegionRelator<'a> {
-        tcx: &'a ty::ctxt,
-        stack: Vec<ty::Region>,
-        relate_op: |ty::Region, ty::Region|: 'a,
-    }
+impl<'a> Wf<'a> {
+    fn accumulate_from_ty(&mut self, ty: ty::t) {
+        debug!("Wf::accumulate_from_ty(ty={})",
+               ty.repr(self.tcx));
 
-    // FIXME(#10151) -- Define more precisely when a region is
-    // considered "nested". Consider taking variance into account as
-    // well.
+        match ty::get(ty).sty {
+            ty::ty_nil |
+            ty::ty_bot |
+            ty::ty_bool |
+            ty::ty_char |
+            ty::ty_int(..) |
+            ty::ty_uint(..) |
+            ty::ty_float(..) |
+            ty::ty_bare_fn(..) |
+            ty::ty_err |
+            ty::ty_str => {
+                // No borrowed content reachable here.
+            }
 
-    impl<'a> TypeFolder for RegionRelator<'a> {
-        fn tcx<'a>(&'a self) -> &'a ty::ctxt {
-            self.tcx
-        }
+            ty::ty_closure(box ref c) => {
+                self.accumulate_from_closure_ty(ty, c);
+            }
 
-        fn fold_ty(&mut self, ty: ty::t) -> ty::t {
-            match ty::get(ty).sty {
-                ty::ty_rptr(r, ty::mt {ty, ..}) => {
-                    self.relate(r);
-                    self.stack.push(r);
-                    ty_fold::super_fold_ty(self, ty);
-                    self.stack.pop().unwrap();
-                }
+            ty::ty_unboxed_closure(_, region) => {
+                // An "unboxed closure type" is basically
+                // modeled here as equivalent to a struct like
+                //
+                //     struct TheClosure<'b> {
+                //         ...
+                //     }
+                //
+                // where the `'b` is the lifetime bound of the
+                // contents (i.e., all contents must outlive 'b).
+                self.push_region_constraint_from_top(region);
+            }
 
-                _ => {
-                    ty_fold::super_fold_ty(self, ty);
-                }
+            ty::ty_trait(ref t) => {
+                self.accumulate_from_object_ty(ty, &t.bounds)
             }
 
-            ty
-        }
+            ty::ty_enum(def_id, ref substs) |
+            ty::ty_struct(def_id, ref substs) => {
+                self.accumulate_from_adt(ty, def_id, substs)
+            }
 
-        fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-            self.relate(r);
-            r
-        }
-    }
+            ty::ty_vec(t, _) |
+            ty::ty_ptr(ty::mt { ty: t, .. }) |
+            ty::ty_box(t) |
+            ty::ty_uniq(t) => {
+                self.accumulate_from_ty(t)
+            }
+
+            ty::ty_rptr(r_b, mt) => {
+                self.accumulate_from_rptr(ty, r_b, mt.ty);
+            }
+
+            ty::ty_param(p) => {
+                self.push_param_constraint_from_top(p);
+            }
 
-    impl<'a> RegionRelator<'a> {
-        fn relate(&mut self, r_sub: ty::Region) {
-            for &r in self.stack.iter() {
-                if !r.is_bound() && !r_sub.is_bound() {
-                    (self.relate_op)(r, r_sub);
+            ty::ty_tup(ref tuptys) => {
+                for &tupty in tuptys.iter() {
+                    self.accumulate_from_ty(tupty);
                 }
             }
+
+            ty::ty_infer(_) => {
+                // This should not happen, BUT:
+                //
+                //   Currently we uncover region relationships on
+                //   entering the fn check. We should do this after
+                //   the fn check, then we can call this case a bug().
+            }
+
+            ty::ty_open(_) => {
+                self.tcx.sess.bug(
+                    format!("Unexpected type encountered while doing wf check: {}",
+                            ty.repr(self.tcx)).as_slice());
+            }
         }
     }
-}
 
-pub fn relate_free_regions(tcx: &ty::ctxt, fn_sig: &ty::FnSig) {
-    /*!
-     * This function populates the region map's `free_region_map`.
-     * It walks over the transformed self type and argument types
-     * for each function just before we check the body of that
-     * function, looking for types where you have a borrowed
-     * pointer to other borrowed data (e.g., `&'a &'b [uint]`.
-     * We do not allow references to outlive the things they
-     * point at, so we can assume that `'a <= 'b`.
-     *
-     * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
-     */
+    fn accumulate_from_rptr(&mut self,
+                            ty: ty::t,
+                            r_b: ty::Region,
+                            ty_b: ty::t) {
+        // We are walking down a type like this, and current
+        // position is indicated by caret:
+        //
+        //     &'a &'b ty_b
+        //         ^
+        //
+        // At this point, top of stack will be `'a`. We must
+        // require that `'a <= 'b`.
+
+        self.push_region_constraint_from_top(r_b);
+
+        // Now we push `'b` onto the stack, because it must
+        // constrain any borrowed content we find within `T`.
 
-    debug!("relate_free_regions >>");
+        self.stack.push((r_b, Some(ty)));
+        self.accumulate_from_ty(ty_b);
+        self.stack.pop().unwrap();
+    }
+
+    fn push_region_constraint_from_top(&mut self,
+                                       r_b: ty::Region) {
+        /*!
+         * Pushes a constraint that `r_b` must outlive the
+         * top region on the stack.
+         */
+
+        // Indicates that we have found borrowed content with a lifetime
+        // of at least `r_b`. This adds a constraint that `r_b` must
+        // outlive the region `r_a` on top of the stack.
+        //
+        // As an example, imagine walking a type like:
+        //
+        //     &'a &'b T
+        //         ^
+        //
+        // when we hit the inner pointer (indicated by caret), `'a` will
+        // be on top of stack and `'b` will be the lifetime of the content
+        // we just found. So we add constraint that `'a <= 'b`.
+
+        let &(r_a, opt_ty) = self.stack.last().unwrap();
+        self.push_sub_region_constraint(opt_ty, r_a, r_b);
+    }
 
-    let mut all_tys = Vec::new();
-    for arg in fn_sig.inputs.iter() {
-        all_tys.push(*arg);
+    fn push_sub_region_constraint(&mut self,
+                                  opt_ty: Option<ty::t>,
+                                  r_a: ty::Region,
+                                  r_b: ty::Region) {
+        /*! Pushes a constraint that `r_a <= r_b`, due to `opt_ty` */
+        self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b));
     }
 
-    for &t in all_tys.iter() {
-        debug!("relate_free_regions(t={})", ppaux::ty_to_string(tcx, t));
-        relate_nested_regions(tcx, None, t, |a, b| {
-            match (&a, &b) {
-                (&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
-                    tcx.region_maps.relate_free_regions(free_a, free_b);
+    fn push_param_constraint_from_top(&mut self,
+                                      param_ty: ty::ParamTy) {
+        /*!
+         * Pushes a constraint that `param_ty` must outlive the
+         * top region on the stack.
+         */
+
+        let &(region, opt_ty) = self.stack.last().unwrap();
+        self.push_param_constraint(region, opt_ty, param_ty);
+    }
+
+    fn push_param_constraint(&mut self,
+                             region: ty::Region,
+                             opt_ty: Option<ty::t>,
+                             param_ty: ty::ParamTy) {
+        /*! Pushes a constraint that `region <= param_ty`, due to `opt_ty` */
+        self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
+    }
+
+    fn accumulate_from_adt(&mut self,
+                           ty: ty::t,
+                           def_id: ast::DefId,
+                           substs: &Substs)
+    {
+        // The generic declarations from the type, appropriately
+        // substituted for the actual substitutions.
+        let generics =
+            ty::lookup_item_type(self.tcx, def_id)
+            .generics
+            .subst(self.tcx, substs);
+
+        // Variance of each type/region parameter.
+        let variances = ty::item_variances(self.tcx, def_id);
+
+        for &space in ParamSpace::all().iter() {
+            let region_params = substs.regions().get_slice(space);
+            let region_variances = variances.regions.get_slice(space);
+            let region_param_defs = generics.regions.get_slice(space);
+            assert_eq!(region_params.len(), region_variances.len());
+            for (&region_param, (&region_variance, region_param_def)) in
+                region_params.iter().zip(
+                    region_variances.iter().zip(
+                        region_param_defs.iter()))
+            {
+                match region_variance {
+                    ty::Covariant | ty::Bivariant => {
+                        // Ignore covariant or bivariant region
+                        // parameters.  To understand why, consider a
+                        // struct `Foo<'a>`. If `Foo` contains any
+                        // references with lifetime `'a`, then `'a` must
+                        // be at least contravariant (and possibly
+                        // invariant). The only way to have a covariant
+                        // result is if `Foo` contains only a field with a
+                        // type like `fn() -> &'a T`; i.e., a bare
+                        // function that can produce a reference of
+                        // lifetime `'a`. In this case, there is no
+                        // *actual data* with lifetime `'a` that is
+                        // reachable. (Presumably this bare function is
+                        // really returning static data.)
+                    }
+
+                    ty::Contravariant | ty::Invariant => {
+                        // If the parameter is contravariant or
+                        // invariant, there may indeed be reachable
+                        // data with this lifetime. See other case for
+                        // more details.
+                        self.push_region_constraint_from_top(region_param);
+                    }
+                }
+
+                for &region_bound in region_param_def.bounds.iter() {
+                    // The type declared a constraint like
+                    //
+                    //     'b : 'a
+                    //
+                    // which means that `'a <= 'b` (after
+                    // substitution).  So take the region we
+                    // substituted for `'a` (`region_bound`) and make
+                    // it a subregion of the region we substituted
+                    // `'b` (`region_param`).
+                    self.push_sub_region_constraint(
+                        Some(ty), region_bound, region_param);
                 }
-                _ => {}
             }
-        })
+
+            let types = substs.types.get_slice(space);
+            let type_variances = variances.types.get_slice(space);
+            let type_param_defs = generics.types.get_slice(space);
+            assert_eq!(types.len(), type_variances.len());
+            for (&type_param_ty, (&variance, type_param_def)) in
+                types.iter().zip(
+                    type_variances.iter().zip(
+                        type_param_defs.iter()))
+            {
+                debug!("type_param_ty={} variance={}",
+                       type_param_ty.repr(self.tcx),
+                       variance.repr(self.tcx));
+
+                match variance {
+                    ty::Contravariant | ty::Bivariant => {
+                        // As above, except that in this it is a
+                        // *contravariant* reference that indices that no
+                        // actual data of type T is reachable.
+                    }
+
+                    ty::Covariant | ty::Invariant => {
+                        self.accumulate_from_ty(type_param_ty);
+                    }
+                }
+
+                // Inspect bounds on this type parameter for any
+                // region bounds.
+                for &r in type_param_def.bounds.opt_region_bound.iter() {
+                    self.stack.push((r, Some(ty)));
+                    self.accumulate_from_ty(type_param_ty);
+                    self.stack.pop().unwrap();
+                }
+            }
+        }
+    }
+
+    fn accumulate_from_closure_ty(&mut self,
+                                  ty: ty::t,
+                                  c: &ty::ClosureTy)
+    {
+        match c.store {
+            ty::RegionTraitStore(r_b, _) => {
+                self.push_region_constraint_from_top(r_b);
+            }
+            ty::UniqTraitStore => { }
+        }
+
+        self.accumulate_from_object_ty(ty, &c.bounds)
     }
 
-    debug!("<< relate_free_regions");
+    fn accumulate_from_object_ty(&mut self,
+                                 ty: ty::t,
+                                 bounds: &ty::ExistentialBounds)
+    {
+        // Imagine a type like this:
+        //
+        //     trait Foo { }
+        //     trait Bar<'c> : 'c { }
+        //
+        //     &'b (Foo+'c+Bar<'d>)
+        //         ^
+        //
+        // In this case, the following relationships must hold:
+        //
+        //     'b <= 'c
+        //     'd <= 'c
+        //
+        // The first conditions is due to the normal region pointer
+        // rules, which say that a reference cannot outlive its
+        // referent.
+        //
+        // The final condition may be a bit surprising. In particular,
+        // you may expect that it would have been `'c <= 'd`, since
+        // usually lifetimes of outer things are conservative
+        // approximations for inner things. However, it works somewhat
+        // differently with trait objects: here the idea is that if the
+        // user specifies a region bound (`'c`, in this case) it is the
+        // "master bound" that *implies* that bounds from other traits are
+        // all met. (Remember that *all bounds* in a type like
+        // `Foo+Bar+Zed` must be met, not just one, hence if we write
+        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
+        // 'y.)
+        //
+        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
+        // am looking forward to the future here.
+
+        // The content of this object type must outlive
+        // `bounds.region_bound`:
+        let r_c = bounds.region_bound;
+        self.push_region_constraint_from_top(r_c);
+
+        // And then, in turn, to be well-formed, the
+        // `region_bound` that user specified must imply the
+        // region bounds required from all of the trait types:
+        let required_region_bounds =
+            ty::required_region_bounds(self.tcx,
+                                       [],
+                                       bounds.builtin_bounds,
+                                       []);
+        for &r_d in required_region_bounds.iter() {
+            // Each of these is an instance of the `'c <= 'b`
+            // constraint above
+            self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c));
+        }
+    }
 }
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 530f8dd4b9e..2d4022a2eaa 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -94,7 +94,7 @@ fn lookup_vtables(vcx: &VtableContext,
     let result = type_param_defs.map_rev(|def| {
         let ty = *substs.types.get(def.space, def.index);
         lookup_vtables_for_param(vcx, span, Some(substs),
-                                 &*def.bounds, ty, is_early)
+                                 &def.bounds, ty, is_early)
     });
 
     debug!("lookup_vtables result(\
@@ -564,7 +564,7 @@ fn fixup_substs(vcx: &VtableContext,
     // use a dummy type just to package up the substs that need fixing up
     let t = ty::mk_trait(tcx,
                          id, substs,
-                         ty::empty_builtin_bounds());
+                         ty::region_existential_bound(ty::ReStatic));
     fixup_ty(vcx, span, t, is_early).map(|t_f| {
         match ty::get(t_f).sty {
           ty::ty_trait(ref inner) => inner.substs.clone(),
@@ -644,7 +644,6 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
           (&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {}
           (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => {
               infer::mk_subr(fcx.infcx(),
-                             false,
                              infer::RelateObjectBound(ex.span),
                              r_t,
                              r_s);
@@ -702,9 +701,11 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
               });
 
               let param_bounds = ty::ParamBounds {
+                  opt_region_bound: None,
                   builtin_bounds: ty::empty_builtin_bounds(),
                   trait_bounds: vec!(target_trait_ref)
               };
+
               let vtables =
                     lookup_vtables_for_param(&vcx,
                                              ex.span,
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 5c3317972cd..e7bc06d4972 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -42,47 +42,31 @@ use middle::ty::{Polytype};
 use middle::ty;
 use middle::ty_fold::TypeFolder;
 use middle::typeck::astconv::{AstConv, ty_of_arg};
-use middle::typeck::astconv::{ast_ty_to_ty};
+use middle::typeck::astconv::{ast_ty_to_ty, ast_region_to_region};
 use middle::typeck::astconv;
 use middle::typeck::infer;
 use middle::typeck::rscope::*;
 use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
 use middle::typeck;
 use util::ppaux;
-use util::ppaux::Repr;
+use util::ppaux::{Repr,UserString};
 
 use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
 use std::gc::Gc;
 
 use syntax::abi;
-use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
-use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
 use syntax::ast;
 use syntax::ast_map;
 use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod};
 use syntax::codemap::Span;
-use syntax::codemap;
-use syntax::owned_slice::OwnedSlice;
-use syntax::parse::token::special_idents;
+use syntax::parse::token::{special_idents};
 use syntax::parse::token;
 use syntax::print::pprust::{path_to_string};
 use syntax::visit;
 
-struct CollectItemTypesVisitor<'a> {
-    ccx: &'a CrateCtxt<'a>
-}
-
-impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> {
-    fn visit_item(&mut self, i: &ast::Item, _: ()) {
-        convert(self.ccx, i);
-        visit::walk_item(self, i, ());
-    }
-    fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
-        convert_foreign(self.ccx, i);
-        visit::walk_foreign_item(self, i, ());
-    }
-}
+///////////////////////////////////////////////////////////////////////////
+// Main entry point
 
 pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
     fn collect_intrinsic_type(ccx: &CrateCtxt,
@@ -99,10 +83,57 @@ pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
         Some(id) => { collect_intrinsic_type(ccx, id); } None => {}
     }
 
+    let mut visitor = CollectTraitDefVisitor{ ccx: ccx };
+    visit::walk_crate(&mut visitor, krate, ());
+
     let mut visitor = CollectItemTypesVisitor{ ccx: ccx };
     visit::walk_crate(&mut visitor, krate, ());
 }
 
+///////////////////////////////////////////////////////////////////////////
+// First phase: just collect *trait definitions* -- basically, the set
+// of type parameters and supertraits. This is information we need to
+// know later when parsing field defs.
+
+struct CollectTraitDefVisitor<'a> {
+    ccx: &'a CrateCtxt<'a>
+}
+
+impl<'a> visit::Visitor<()> for CollectTraitDefVisitor<'a> {
+    fn visit_item(&mut self, i: &ast::Item, _: ()) {
+        match i.node {
+            ast::ItemTrait(..) => {
+                // computing the trait def also fills in the table
+                let _ = trait_def_of_item(self.ccx, i);
+            }
+            _ => { }
+        }
+
+        visit::walk_item(self, i, ());
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Second phase: collection proper.
+
+struct CollectItemTypesVisitor<'a> {
+    ccx: &'a CrateCtxt<'a>
+}
+
+impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> {
+    fn visit_item(&mut self, i: &ast::Item, _: ()) {
+        convert(self.ccx, i);
+        visit::walk_item(self, i, ());
+    }
+    fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
+        convert_foreign(self.ccx, i);
+        visit::walk_foreign_item(self, i, ());
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Utility types and common code for the above passes.
+
 pub trait ToTy {
     fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
 }
@@ -193,9 +224,9 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
     }
 }
 
-pub fn ensure_trait_methods(ccx: &CrateCtxt,
-                            trait_id: ast::NodeId,
-                            trait_def: &ty::TraitDef) {
+fn collect_trait_methods(ccx: &CrateCtxt,
+                         trait_id: ast::NodeId,
+                         trait_def: &ty::TraitDef) {
     let tcx = ccx.tcx;
     match tcx.map.get(trait_id) {
         ast_map::NodeItem(item) => {
@@ -360,7 +391,13 @@ fn convert_methods(ccx: &CrateCtxt,
                    ms: &[Gc<ast::Method>],
                    untransformed_rcvr_ty: ty::t,
                    rcvr_ty_generics: &ty::Generics,
-                   rcvr_visibility: ast::Visibility) {
+                   rcvr_visibility: ast::Visibility)
+{
+    debug!("convert_methods(untransformed_rcvr_ty={}, \
+            rcvr_ty_generics={})",
+           untransformed_rcvr_ty.repr(ccx.tcx),
+           rcvr_ty_generics.repr(ccx.tcx));
+
     let tcx = ccx.tcx;
     let mut seen_methods = HashSet::new();
     for m in ms.iter() {
@@ -388,6 +425,9 @@ fn convert_methods(ccx: &CrateCtxt,
 
         write_ty_to_tcx(tcx, m.id, fty);
 
+        debug!("writing method type: def_id={} mty={}",
+               mty.def_id, mty.repr(ccx.tcx));
+
         tcx.impl_or_trait_items
            .borrow_mut()
            .insert(mty.def_id, ty::MethodTraitItem(mty));
@@ -448,9 +488,20 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
                                  generics: &ast::Generics,
                                  thing: &'static str) {
     for ty_param in generics.ty_params.iter() {
-        if ty_param.bounds.len() > 0 {
-            span_err!(ccx.tcx.sess, span, E0122,
-                      "trait bounds are not allowed in {} definitions", thing);
+        for bound in ty_param.bounds.iter() {
+            match *bound {
+                ast::TraitTyParamBound(..) | ast::UnboxedFnTyParamBound(..) => {
+                    // According to accepted RFC #XXX, we should
+                    // eventually accept these, but it will not be
+                    // part of this PR. Still, convert to warning to
+                    // make bootstrapping easier.
+                    span_warn!(ccx.tcx.sess, span, E0122,
+                               "trait bounds are not (yet) enforced \
+                                in {} definitions",
+                               thing);
+                }
+                ast::RegionTyParamBound(..) => { }
+            }
         }
     }
 }
@@ -520,6 +571,10 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
         ast::ItemTrait(_, _, _, ref trait_methods) => {
             let trait_def = trait_def_of_item(ccx, it);
 
+            debug!("trait_def: ident={} trait_def={}",
+                   it.ident.repr(ccx.tcx),
+                   trait_def.repr(ccx.tcx()));
+
             for trait_method in trait_methods.iter() {
                 let self_type = ty::mk_param(ccx.tcx,
                                              subst::SelfSpace,
@@ -556,7 +611,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
             // We need to do this *after* converting methods, since
             // convert_methods produces a tcache entry that is wrong for
             // static trait methods. This is somewhat unfortunate.
-            ensure_trait_methods(ccx, it.id, &*trait_def);
+            collect_trait_methods(ccx, it.id, &*trait_def);
         },
         ast::ItemStruct(struct_def, _) => {
             // Write the class type.
@@ -739,6 +794,19 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt,
     }
 }
 
+pub fn instantiate_unboxed_fn_ty(ccx: &CrateCtxt,
+                                 unboxed_function: &ast::UnboxedFnTy,
+                                 param_ty: ty::ParamTy)
+                                 -> Rc<ty::TraitRef>
+{
+    let rscope = ExplicitRscope;
+    let param_ty = param_ty.to_ty(ccx.tcx);
+    Rc::new(astconv::trait_ref_for_unboxed_function(ccx,
+                                                    &rscope,
+                                                    unboxed_function,
+                                                    Some(param_ty)))
+}
+
 fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
     if trait_id.krate != ast::LOCAL_CRATE {
         return ty::lookup_trait_def(ccx.tcx, trait_id)
@@ -761,9 +829,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
         _ => {}
     }
 
-    let (generics, unbound, supertraits) = match it.node {
-        ast::ItemTrait(ref generics, ref unbound, ref supertraits, _) => {
-            (generics, unbound, supertraits)
+    let (generics, unbound, bounds) = match it.node {
+        ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => {
+            (generics, unbound, bounds)
         }
         ref s => {
             tcx.sess.span_bug(
@@ -779,13 +847,16 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
                                             &substs,
                                             generics);
 
-    let builtin_bounds =
-        ensure_supertraits(ccx, it.id, it.span, supertraits, unbound);
+    let self_param_ty = ty::ParamTy::for_self(def_id);
+
+    let bounds = compute_bounds(ccx, token::SELF_KEYWORD_NAME, self_param_ty,
+                                bounds.as_slice(), unbound, it.span,
+                                &generics.where_clause);
 
     let substs = mk_item_substs(ccx, &ty_generics);
     let trait_def = Rc::new(ty::TraitDef {
         generics: ty_generics,
-        bounds: builtin_bounds,
+        bounds: bounds,
         trait_ref: Rc::new(ty::TraitRef {
             def_id: def_id,
             substs: substs
@@ -824,55 +895,6 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
 
         subst::Substs::new_trait(types, regions, self_ty)
     }
-
-    fn ensure_supertraits(ccx: &CrateCtxt,
-                          id: ast::NodeId,
-                          sp: codemap::Span,
-                          ast_trait_refs: &Vec<ast::TraitRef>,
-                          unbound: &Option<ast::TyParamBound>)
-                          -> ty::BuiltinBounds
-    {
-        let tcx = ccx.tcx;
-
-        // Called only the first time trait_def_of_item is called.
-        // Supertraits are ensured at the same time.
-        assert!(!tcx.supertraits.borrow().contains_key(&local_def(id)));
-
-        let self_ty = ty::mk_self_type(ccx.tcx, local_def(id));
-        let mut ty_trait_refs: Vec<Rc<ty::TraitRef>> = Vec::new();
-        let mut bounds = ty::empty_builtin_bounds();
-        for ast_trait_ref in ast_trait_refs.iter() {
-            let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref);
-
-            // FIXME(#8559): Need to instantiate the trait_ref whether
-            // or not it's a builtin trait, so that the trait's node
-            // id appears in the tcx trait_ref map. This is only
-            // needed for metadata; see the similar fixme in
-            // encoder.rs.
-
-            let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty);
-            if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
-
-                // FIXME(#5527) Could have same trait multiple times
-                if ty_trait_refs.iter().any(
-                    |other_trait| other_trait.def_id == trait_ref.def_id)
-                {
-                    // This means a trait inherited from the same
-                    // supertrait more than once.
-                    span_err!(tcx.sess, sp, E0127,
-                              "duplicate supertrait in trait declaration");
-                    break;
-                } else {
-                    ty_trait_refs.push(trait_ref);
-                }
-            }
-        }
-
-        add_unsized_bound(ccx, unbound, &mut bounds, "trait", sp);
-        tcx.supertraits.borrow_mut().insert(local_def(id),
-                                            Rc::new(ty_trait_refs));
-        bounds
-    }
 }
 
 pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
@@ -984,11 +1006,12 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
 
 fn ty_generics_for_type(ccx: &CrateCtxt,
                         generics: &ast::Generics)
-                        -> ty::Generics {
+                        -> ty::Generics
+{
     ty_generics(ccx,
                 subst::TypeSpace,
-                &generics.lifetimes,
-                &generics.ty_params,
+                generics.lifetimes.as_slice(),
+                generics.ty_params.as_slice(),
                 ty::Generics::empty(),
                 &generics.where_clause)
 }
@@ -1000,8 +1023,8 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
                          -> ty::Generics {
     let mut generics = ty_generics(ccx,
                                    subst::TypeSpace,
-                                   &generics.lifetimes,
-                                   &generics.ty_params,
+                                   generics.lifetimes.as_slice(),
+                                   generics.ty_params.as_slice(),
                                    ty::Generics::empty(),
                                    &generics.where_clause);
 
@@ -1018,10 +1041,11 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
         index: 0,
         ident: special_idents::type_self,
         def_id: local_def(param_id),
-        bounds: Rc::new(ty::ParamBounds {
+        bounds: ty::ParamBounds {
+            opt_region_bound: None,
             builtin_bounds: ty::empty_builtin_bounds(),
             trait_bounds: vec!(self_trait_ref),
-        }),
+        },
         default: None
     };
 
@@ -1039,8 +1063,8 @@ fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
     let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
     ty_generics(ccx,
                 subst::FnSpace,
-                &early_lifetimes,
-                &generics.ty_params,
+                early_lifetimes.as_slice(),
+                generics.ty_params.as_slice(),
                 base_generics,
                 &generics.where_clause)
 }
@@ -1053,7 +1077,7 @@ fn add_unsized_bound(ccx: &CrateCtxt,
                      span: Span) {
     let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
     match unbound {
-        &Some(TraitTyParamBound(ref tpb)) => {
+        &Some(ast::TraitTyParamBound(ref tpb)) => {
             // #FIXME(8559) currently requires the unbound to be built-in.
             let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
             match kind_id {
@@ -1084,18 +1108,23 @@ fn add_unsized_bound(ccx: &CrateCtxt,
 
 fn ty_generics(ccx: &CrateCtxt,
                space: subst::ParamSpace,
-               lifetimes: &Vec<ast::LifetimeDef>,
-               types: &OwnedSlice<ast::TyParam>,
+               lifetime_defs: &[ast::LifetimeDef],
+               types: &[ast::TyParam],
                base_generics: ty::Generics,
                where_clause: &ast::WhereClause)
-               -> ty::Generics {
+               -> ty::Generics
+{
     let mut result = base_generics;
 
-    for (i, l) in lifetimes.iter().enumerate() {
+    for (i, l) in lifetime_defs.iter().enumerate() {
+        let bounds = l.bounds.iter()
+                             .map(|l| ast_region_to_region(ccx.tcx, l))
+                             .collect();
         let def = ty::RegionParameterDef { name: l.lifetime.name,
                                            space: space,
                                            index: i,
-                                           def_id: local_def(l.lifetime.id) };
+                                           def_id: local_def(l.lifetime.id),
+                                           bounds: bounds };
         debug!("ty_generics: def for region param: {}", def);
         result.regions.push(space, def);
     }
@@ -1123,19 +1152,17 @@ fn ty_generics(ccx: &CrateCtxt,
             None => { }
         }
 
-        let param_ty = ty::ParamTy {space: space,
-                                    idx: index,
-                                    def_id: local_def(param.id)};
-        let bounds = Rc::new(compute_bounds(ccx,
-                                            param_ty,
-                                            &param.bounds,
-                                            &param.unbound,
-                                            param.ident,
-                                            param.span,
-                                            where_clause));
+        let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
+        let bounds = compute_bounds(ccx,
+                                    param.ident.name,
+                                    param_ty,
+                                    param.bounds.as_slice(),
+                                    &param.unbound,
+                                    param.span,
+                                    where_clause);
         let default = param.default.map(|path| {
             let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path);
-            let cur_idx = param_ty.idx;
+            let cur_idx = index;
 
             ty::walk_ty(ty, |t| {
                 match ty::get(t).sty {
@@ -1164,130 +1191,139 @@ fn ty_generics(ccx: &CrateCtxt,
 
         def
     }
+}
 
-    fn compute_bounds(ccx: &CrateCtxt,
-                      param_ty: ty::ParamTy,
-                      ast_bounds: &OwnedSlice<ast::TyParamBound>,
-                      unbound: &Option<ast::TyParamBound>,
-                      ident: ast::Ident,
-                      span: Span,
-                      where_clause: &ast::WhereClause)
-                      -> ty::ParamBounds {
-        /*!
-         * Translate the AST's notion of ty param bounds (which are an
-         * enum consisting of a newtyped Ty or a region) to ty's
-         * notion of ty param bounds, which can either be user-defined
-         * traits, or the built-in trait (formerly known as kind): Send.
-         */
-
-        let mut param_bounds = ty::ParamBounds {
-            builtin_bounds: ty::empty_builtin_bounds(),
-            trait_bounds: Vec::new()
-        };
-        for ast_bound in ast_bounds.iter() {
-            compute_bound(ccx, &mut param_bounds, param_ty, ast_bound);
-        }
-        for predicate in where_clause.predicates.iter() {
-            let predicate_param_id = ccx.tcx
-                                        .def_map
-                                        .borrow()
-                                        .find(&predicate.id)
-                                        .expect("compute_bounds(): resolve \
-                                                 didn't resolve the type \
-                                                 parameter identifier in a \
-                                                 `where` clause")
-                                        .def_id();
-            if param_ty.def_id != predicate_param_id {
-                continue
-            }
-            for bound in predicate.bounds.iter() {
-                compute_bound(ccx, &mut param_bounds, param_ty, bound);
-            }
-        }
-
-        add_unsized_bound(ccx,
-                          unbound,
-                          &mut param_bounds.builtin_bounds,
-                          "type parameter",
-                          span);
-
-        check_bounds_compatible(ccx.tcx, &param_bounds, ident, span);
+fn compute_bounds(
+    ccx: &CrateCtxt,
+    name_of_bounded_thing: ast::Name,
+    param_ty: ty::ParamTy,
+    ast_bounds: &[ast::TyParamBound],
+    unbound: &Option<ast::TyParamBound>,
+    span: Span,
+    where_clause: &ast::WhereClause)
+    -> ty::ParamBounds
+{
+    /*!
+     * Translate the AST's notion of ty param bounds (which are an
+     * enum consisting of a newtyped Ty or a region) to ty's
+     * notion of ty param bounds, which can either be user-defined
+     * traits, or the built-in trait (formerly known as kind): Send.
+     */
 
-        param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
+    let mut param_bounds = conv_param_bounds(ccx,
+                                             span,
+                                             param_ty,
+                                             ast_bounds,
+                                             where_clause);
 
-        param_bounds
-    }
 
-    /// Translates the AST's notion of a type parameter bound to
-    /// typechecking's notion of the same, and pushes the resulting bound onto
-    /// the appropriate section of `param_bounds`.
-    fn compute_bound(ccx: &CrateCtxt,
-                     param_bounds: &mut ty::ParamBounds,
-                     param_ty: ty::ParamTy,
-                     ast_bound: &ast::TyParamBound) {
-        match *ast_bound {
-            TraitTyParamBound(ref b) => {
-                let ty = ty::mk_param(ccx.tcx, param_ty.space,
-                                      param_ty.idx, param_ty.def_id);
-                let trait_ref = instantiate_trait_ref(ccx, b, ty);
-                if !ty::try_add_builtin_trait(
-                        ccx.tcx, trait_ref.def_id,
-                        &mut param_bounds.builtin_bounds) {
-                    // Must be a user-defined trait
-                    param_bounds.trait_bounds.push(trait_ref);
-                }
-            }
+    add_unsized_bound(ccx,
+                      unbound,
+                      &mut param_bounds.builtin_bounds,
+                      "type parameter",
+                      span);
 
-            StaticRegionTyParamBound => {
-                param_bounds.builtin_bounds.add(ty::BoundStatic);
-            }
+    check_bounds_compatible(ccx.tcx, name_of_bounded_thing,
+                            &param_bounds, span);
 
-            UnboxedFnTyParamBound(ref unboxed_function) => {
-                let rscope = ExplicitRscope;
-                let self_ty = ty::mk_param(ccx.tcx,
-                                           param_ty.space,
-                                           param_ty.idx,
-                                           param_ty.def_id);
-                let trait_ref =
-                    astconv::trait_ref_for_unboxed_function(ccx,
-                                                            &rscope,
-                                                            unboxed_function,
-                                                            Some(self_ty));
-                param_bounds.trait_bounds.push(Rc::new(trait_ref));
-            }
+    param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
 
-            OtherRegionTyParamBound(span) => {
-                if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
-                    ccx.tcx.sess.span_err(
-                        span,
-                        "only the 'static lifetime is accepted here.");
-                }
-            }
-        }
-    }
+    param_bounds
+}
 
-    fn check_bounds_compatible(tcx: &ty::ctxt,
-                               param_bounds: &ty::ParamBounds,
-                               ident: ast::Ident,
-                               span: Span) {
-        // Currently the only bound which is incompatible with other bounds is
-        // Sized/Unsized.
-        if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
-            ty::each_bound_trait_and_supertraits(tcx,
-                                                 param_bounds.trait_bounds.as_slice(),
-                                                 |trait_ref| {
+fn check_bounds_compatible(tcx: &ty::ctxt,
+                           name_of_bounded_thing: ast::Name,
+                           param_bounds: &ty::ParamBounds,
+                           span: Span) {
+    // Currently the only bound which is incompatible with other bounds is
+    // Sized/Unsized.
+    if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
+        ty::each_bound_trait_and_supertraits(
+            tcx,
+            param_bounds.trait_bounds.as_slice(),
+            |trait_ref| {
                 let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
-                if trait_def.bounds.contains_elem(ty::BoundSized) {
+                if trait_def.bounds.builtin_bounds.contains_elem(ty::BoundSized) {
                     span_err!(tcx.sess, span, E0129,
-                              "incompatible bounds on type parameter {}, \
-                               bound {} does not allow unsized type",
-                              token::get_ident(ident),
+                              "incompatible bounds on type parameter `{}`, \
+                               bound `{}` does not allow unsized type",
+                              name_of_bounded_thing.user_string(tcx),
                               ppaux::trait_ref_to_string(tcx, &*trait_ref));
                 }
                 true
             });
+    }
+}
+
+fn conv_param_bounds(ccx: &CrateCtxt,
+                     span: Span,
+                     param_ty: ty::ParamTy,
+                     ast_bounds: &[ast::TyParamBound],
+                     where_clause: &ast::WhereClause)
+                     -> ty::ParamBounds
+{
+    let all_bounds =
+        merge_param_bounds(ccx, param_ty, ast_bounds, where_clause);
+    let astconv::PartitionedBounds { builtin_bounds,
+                                     trait_bounds,
+                                     region_bounds,
+                                     unboxed_fn_ty_bounds } =
+        astconv::partition_bounds(ccx.tcx, span, all_bounds.as_slice());
+    let unboxed_fn_ty_bounds =
+        unboxed_fn_ty_bounds.move_iter()
+        .map(|b| instantiate_unboxed_fn_ty(ccx, b, param_ty));
+    let trait_bounds: Vec<Rc<ty::TraitRef>> =
+        trait_bounds.move_iter()
+        .map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx)))
+        .chain(unboxed_fn_ty_bounds)
+        .collect();
+    let opt_region_bound =
+        astconv::compute_opt_region_bound(
+            ccx.tcx, span, builtin_bounds, region_bounds.as_slice(),
+            trait_bounds.as_slice());
+    ty::ParamBounds {
+        opt_region_bound: opt_region_bound,
+        builtin_bounds: builtin_bounds,
+        trait_bounds: trait_bounds,
+    }
+}
+
+fn merge_param_bounds<'a>(ccx: &CrateCtxt,
+                          param_ty: ty::ParamTy,
+                          ast_bounds: &'a [ast::TyParamBound],
+                          where_clause: &'a ast::WhereClause)
+                          -> Vec<&'a ast::TyParamBound>
+{
+    /*!
+     * Merges the bounds declared on a type parameter with those
+     * found from where clauses into a single list.
+     */
+
+    let mut result = Vec::new();
+
+    for ast_bound in ast_bounds.iter() {
+        result.push(ast_bound);
+    }
+
+    for predicate in where_clause.predicates.iter() {
+        let predicate_param_id = ccx.tcx
+            .def_map
+            .borrow()
+            .find(&predicate.id)
+            .expect("compute_bounds(): resolve \
+                     didn't resolve the type \
+                     parameter identifier in a \
+                     `where` clause")
+            .def_id();
+        if param_ty.def_id != predicate_param_id {
+            continue
+        }
+        for bound in predicate.bounds.iter() {
+            result.push(bound);
         }
     }
+
+    result
 }
 
 pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index a57dec90455..47085877ad7 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -221,7 +221,7 @@ pub trait Combine {
         };
         let fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style));
         let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
-        let bounds = if_ok!(self.bounds(a.bounds, b.bounds));
+        let bounds = if_ok!(self.existential_bounds(a.bounds, b.bounds));
         let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
         let abi = if_ok!(self.abi(a.abi, b.abi));
         Ok(ty::ClosureTy {
@@ -251,9 +251,26 @@ pub trait Combine {
     }
 
     fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
-    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds>;
+
+    fn existential_bounds(&self,
+                          a: ty::ExistentialBounds,
+                          b: ty::ExistentialBounds)
+                          -> cres<ty::ExistentialBounds>
+    {
+        let r = try!(self.contraregions(a.region_bound, b.region_bound));
+        let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
+        Ok(ty::ExistentialBounds { region_bound: r,
+                                   builtin_bounds: nb })
+    }
+
+    fn builtin_bounds(&self,
+                      a: ty::BuiltinBounds,
+                      b: ty::BuiltinBounds)
+                      -> cres<ty::BuiltinBounds>;
+
     fn contraregions(&self, a: ty::Region, b: ty::Region)
                   -> cres<ty::Region>;
+
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>;
 
     fn trait_stores(&self,
@@ -479,7 +496,7 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
       if a_.def_id == b_.def_id => {
           debug!("Trying to match traits {:?} and {:?}", a, b);
           let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs));
-          let bounds = if_ok!(this.bounds(a_.bounds, b_.bounds));
+          let bounds = if_ok!(this.existential_bounds(a_.bounds, b_.bounds));
           Ok(ty::mk_trait(tcx,
                           a_.def_id,
                           substs.clone(),
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index 920fa23f31d..2883a960df9 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -75,6 +75,7 @@ use middle::typeck::infer::region_inference::RegionResolutionError;
 use middle::typeck::infer::region_inference::ConcreteFailure;
 use middle::typeck::infer::region_inference::SubSupConflict;
 use middle::typeck::infer::region_inference::SupSupConflict;
+use middle::typeck::infer::region_inference::ParamBoundFailure;
 use middle::typeck::infer::region_inference::ProcessedErrors;
 use middle::typeck::infer::region_inference::SameRegions;
 use std::cell::{Cell, RefCell};
@@ -89,10 +90,13 @@ use syntax::owned_slice::OwnedSlice;
 use syntax::codemap;
 use syntax::parse::token;
 use syntax::print::pprust;
-use util::ppaux::UserString;
 use util::ppaux::bound_region_to_string;
 use util::ppaux::note_and_explain_region;
 
+// Note: only import UserString, not Repr, since user-facing error
+// messages shouldn't include debug serializations.
+use util::ppaux::UserString;
+
 pub trait ErrorReporting {
     fn report_region_errors(&self,
                             errors: &Vec<RegionResolutionError>);
@@ -118,6 +122,12 @@ pub trait ErrorReporting {
                                sub: Region,
                                sup: Region);
 
+    fn report_param_bound_failure(&self,
+                                  origin: SubregionOrigin,
+                                  param_ty: ty::ParamTy,
+                                  sub: Region,
+                                  sups: Vec<Region>);
+
     fn report_sub_sup_conflict(&self,
                                var_origin: RegionVariableOrigin,
                                sub_origin: SubregionOrigin,
@@ -145,7 +155,7 @@ trait ErrorReportingHelpers {
                                 var_origin: RegionVariableOrigin);
 
     fn note_region_origin(&self,
-                          origin: SubregionOrigin);
+                          origin: &SubregionOrigin);
 
     fn give_expl_lifetime_param(&self,
                                 decl: &ast::FnDecl,
@@ -167,6 +177,10 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
                     self.report_concrete_failure(origin, sub, sup);
                 }
 
+                ParamBoundFailure(origin, param_ty, sub, sups) => {
+                    self.report_param_bound_failure(origin, param_ty, sub, sups);
+                }
+
                 SubSupConflict(var_origin,
                                sub_origin, sub_r,
                                sup_origin, sup_r) => {
@@ -410,6 +424,62 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
                      found.user_string(self.tcx)))
     }
 
+    fn report_param_bound_failure(&self,
+                                  origin: SubregionOrigin,
+                                  param_ty: ty::ParamTy,
+                                  sub: Region,
+                                  _sups: Vec<Region>) {
+
+        // FIXME: it would be better to report the first error message
+        // with the span of the parameter itself, rather than the span
+        // where the error was detected. But that span is not readily
+        // accessible.
+
+        match sub {
+            ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
+                // Does the required lifetime have a nice name we can print?
+                self.tcx.sess.span_err(
+                    origin.span(),
+                    format!(
+                        "the parameter type `{}` may not live long enough; \
+                         consider adding an explicit lifetime bound `{}:{}`...",
+                        param_ty.user_string(self.tcx),
+                        param_ty.user_string(self.tcx),
+                        sub.user_string(self.tcx)).as_slice());
+            }
+
+            ty::ReStatic => {
+                // Does the required lifetime have a nice name we can print?
+                self.tcx.sess.span_err(
+                    origin.span(),
+                    format!(
+                        "the parameter type `{}` may not live long enough; \
+                         consider adding an explicit lifetime bound `{}:'static`...",
+                        param_ty.user_string(self.tcx),
+                        param_ty.user_string(self.tcx)).as_slice());
+            }
+
+            _ => {
+                // If not, be less specific.
+                self.tcx.sess.span_err(
+                    origin.span(),
+                    format!(
+                        "the parameter type `{}` may not live long enough; \
+                         consider adding an explicit lifetime bound to `{}`",
+                        param_ty.user_string(self.tcx),
+                        param_ty.user_string(self.tcx)).as_slice());
+                note_and_explain_region(
+                    self.tcx,
+                    format!("the parameter type `{}` must be valid for ",
+                            param_ty.user_string(self.tcx)).as_slice(),
+                    sub,
+                    "...");
+            }
+        }
+
+        self.note_region_origin(&origin);
+    }
+
     fn report_concrete_failure(&self,
                                origin: SubregionOrigin,
                                sub: Region,
@@ -538,6 +608,67 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
                     sup,
                     "");
             }
+            infer::RelateProcBound(span, var_node_id, ty) => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!(
+                        "the type `{}` of captured variable `{}` \
+                         outlives the `proc()` it \
+                         is captured in",
+                        self.ty_to_string(ty),
+                        ty::local_var_name_str(self.tcx,
+                                               var_node_id)).as_slice());
+                note_and_explain_region(
+                    self.tcx,
+                    "`proc()` is valid for ",
+                    sub,
+                    "");
+                note_and_explain_region(
+                    self.tcx,
+                    format!("the type `{}` is only valid for ",
+                            self.ty_to_string(ty)).as_slice(),
+                    sup,
+                    "");
+            }
+            infer::RelateParamBound(span, param_ty, ty) => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!("the type `{}` (provided as the value of \
+                             the parameter `{}`) does not fulfill the \
+                             required lifetime",
+                            self.ty_to_string(ty),
+                            param_ty.user_string(self.tcx)).as_slice());
+                note_and_explain_region(self.tcx,
+                                        "type must outlive ",
+                                        sub,
+                                        "");
+            }
+            infer::RelateRegionParamBound(span) => {
+                self.tcx.sess.span_err(
+                    span,
+                    "declared lifetime bound not satisfied");
+                note_and_explain_region(
+                    self.tcx,
+                    "lifetime parameter instantiated with ",
+                    sup,
+                    "");
+                note_and_explain_region(
+                    self.tcx,
+                    "but lifetime parameter must outlive ",
+                    sub,
+                    "");
+            }
+            infer::RelateDefaultParamBound(span, ty) => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!("the type `{}` (provided as the value of \
+                             a type parameter) is not valid at this point",
+                            self.ty_to_string(ty)).as_slice());
+                note_and_explain_region(self.tcx,
+                                        "type must outlive ",
+                                        sub,
+                                        "");
+            }
             infer::CallRcvr(span) => {
                 self.tcx.sess.span_err(
                     span,
@@ -593,6 +724,18 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
                     sup,
                     "");
             }
+            infer::ExprTypeIsNotInScope(t, span) => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!("type of expression contains references \
+                             that are not valid during the expression: `{}`",
+                            self.ty_to_string(t)).as_slice());
+                note_and_explain_region(
+                    self.tcx,
+                    "type is only valid for ",
+                    sup,
+                    "");
+            }
             infer::BindingTypeIsNotValidAtDecl(span) => {
                 self.tcx.sess.span_err(
                     span,
@@ -606,9 +749,9 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
             infer::ReferenceOutlivesReferent(ty, span) => {
                 self.tcx.sess.span_err(
                     span,
-                    format!("in type `{}`, pointer has a longer lifetime than \
-                          the data it references",
-                         ty.user_string(self.tcx)).as_slice());
+                    format!("in type `{}`, reference has a longer lifetime \
+                             than the data it references",
+                            self.ty_to_string(ty)).as_slice());
                 note_and_explain_region(
                     self.tcx,
                     "the pointer is valid for ",
@@ -620,6 +763,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
                     sup,
                     "");
             }
+            infer::Managed(span) => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!("cannot put borrowed references into managed memory").as_slice());
+            }
         }
     }
 
@@ -637,7 +785,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
             sup_region,
             "...");
 
-        self.note_region_origin(sup_origin);
+        self.note_region_origin(&sup_origin);
 
         note_and_explain_region(
             self.tcx,
@@ -645,7 +793,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
             sub_region,
             "...");
 
-        self.note_region_origin(sub_origin);
+        self.note_region_origin(&sub_origin);
     }
 
     fn report_sup_sup_conflict(&self,
@@ -662,7 +810,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
             region1,
             "...");
 
-        self.note_region_origin(origin1);
+        self.note_region_origin(&origin1);
 
         note_and_explain_region(
             self.tcx,
@@ -670,7 +818,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
             region2,
             "...");
 
-        self.note_region_origin(origin2);
+        self.note_region_origin(&origin2);
     }
 
     fn report_processed_errors(&self,
@@ -920,8 +1068,12 @@ impl<'a> Rebuilder<'a> {
                                -> OwnedSlice<ast::TyParamBound> {
         ty_param_bounds.map(|tpb| {
             match tpb {
-                &ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
-                &ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
+                &ast::RegionTyParamBound(lt) => {
+                    // FIXME -- it's unclear whether I'm supposed to
+                    // substitute lifetime here. I suspect we need to
+                    // be passing down a map.
+                    ast::RegionTyParamBound(lt)
+                }
                 &ast::UnboxedFnTyParamBound(unboxed_function_type) => {
                     ast::UnboxedFnTyParamBound(unboxed_function_type)
                 }
@@ -1291,8 +1443,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
                     var_description).as_slice());
     }
 
-    fn note_region_origin(&self, origin: SubregionOrigin) {
-        match origin {
+    fn note_region_origin(&self, origin: &SubregionOrigin) {
+        match *origin {
             infer::Subtype(ref trace) => {
                 let desc = match trace.origin {
                     infer::Misc(_) => {
@@ -1384,8 +1536,16 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
             infer::RelateObjectBound(span) => {
                 self.tcx.sess.span_note(
                     span,
-                    "...so that source pointer does not outlive \
-                     lifetime bound of the object type");
+                    "...so that it can be closed over into an object");
+            }
+            infer::RelateProcBound(span, var_node_id, _ty) => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!(
+                        "...so that the variable `{}` can be captured \
+                         into a proc",
+                        ty::local_var_name_str(self.tcx,
+                                               var_node_id)).as_slice());
             }
             infer::CallRcvr(span) => {
                 self.tcx.sess.span_note(
@@ -1414,16 +1574,52 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
                     "...so that reference is valid \
                      at the time of implicit borrow");
             }
+            infer::ExprTypeIsNotInScope(t, span) => {
+                self.tcx.sess.span_note(
+                    span,
+                    format!("...so type `{}` of expression is valid during the \
+                             expression",
+                            self.ty_to_string(t)).as_slice());
+            }
             infer::BindingTypeIsNotValidAtDecl(span) => {
                 self.tcx.sess.span_note(
                     span,
                     "...so that variable is valid at time of its declaration");
             }
-            infer::ReferenceOutlivesReferent(_, span) => {
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                self.tcx.sess.span_note(
+                    span,
+                    format!("...so that the reference type `{}` \
+                             does not outlive the data it points at",
+                            self.ty_to_string(ty)).as_slice());
+            }
+            infer::Managed(span) => {
+                self.tcx.sess.span_note(
+                    span,
+                    "...so that the value can be stored in managed memory.");
+            }
+            infer::RelateParamBound(span, param_ty, t) => {
+                self.tcx.sess.span_note(
+                    span,
+                    format!("...so that the parameter `{}`, \
+                             when instantiated with `{}`, \
+                             will meet its declared lifetime bounds.",
+                            param_ty.user_string(self.tcx),
+                            self.ty_to_string(t)).as_slice());
+            }
+            infer::RelateDefaultParamBound(span, t) => {
+                self.tcx.sess.span_note(
+                    span,
+                    format!("...so that type parameter \
+                             instantiated with `{}`, \
+                             will meet its declared lifetime bounds.",
+                            self.ty_to_string(t)).as_slice());
+            }
+            infer::RelateRegionParamBound(span) => {
                 self.tcx.sess.span_note(
                     span,
-                    "...so that the pointer does not outlive the \
-                    data it points at");
+                    format!("...so that the declared lifetime parameter bounds \
+                                are satisfied").as_slice());
             }
         }
     }
diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs
index b6628c22ae6..00eaa4d235b 100644
--- a/src/librustc/middle/typeck/infer/glb.rs
+++ b/src/librustc/middle/typeck/infer/glb.rs
@@ -96,7 +96,10 @@ impl<'f> Combine for Glb<'f> {
         }
     }
 
-    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
+    fn builtin_bounds(&self,
+                      a: ty::BuiltinBounds,
+                      b: ty::BuiltinBounds)
+                      -> cres<ty::BuiltinBounds> {
         // More bounds is a subtype of fewer bounds, so
         // the GLB (mutual subtype) is the union.
         Ok(a.union(b))
diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs
index 6a50038afe7..8707efc622b 100644
--- a/src/librustc/middle/typeck/infer/lub.rs
+++ b/src/librustc/middle/typeck/infer/lub.rs
@@ -90,7 +90,10 @@ impl<'f> Combine for Lub<'f> {
         }
     }
 
-    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
+    fn builtin_bounds(&self,
+                      a: ty::BuiltinBounds,
+                      b: ty::BuiltinBounds)
+                      -> cres<ty::BuiltinBounds> {
         // More bounds is a subtype of fewer bounds, so
         // the LUB (mutual supertype) is the intersection.
         Ok(a.intersection(b))
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 5629a085500..ed96effdd83 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -168,6 +168,22 @@ pub enum SubregionOrigin {
     // relating `'a` to `'b`
     RelateObjectBound(Span),
 
+    // When closing over a variable in a closure/proc, ensure that the
+    // type of the variable outlives the lifetime bound.
+    RelateProcBound(Span, ast::NodeId, ty::t),
+
+    // The given type parameter was instantiated with the given type,
+    // and that type must outlive some region.
+    RelateParamBound(Span, ty::ParamTy, ty::t),
+
+    // The given region parameter was instantiated with a region
+    // that must outlive some other region.
+    RelateRegionParamBound(Span),
+
+    // A bound placed on type parameters that states that must outlive
+    // the moment of their instantiation.
+    RelateDefaultParamBound(Span, ty::t),
+
     // Creating a pointer `b` to contents of another reference
     Reborrow(Span),
 
@@ -177,6 +193,9 @@ pub enum SubregionOrigin {
     // (&'a &'b T) where a >= b
     ReferenceOutlivesReferent(ty::t, Span),
 
+    // The type T of an expression E must outlive the lifetime for E.
+    ExprTypeIsNotInScope(ty::t, Span),
+
     // A `ref b` whose region does not enclose the decl site
     BindingTypeIsNotValidAtDecl(Span),
 
@@ -194,6 +213,9 @@ pub enum SubregionOrigin {
 
     // An auto-borrow that does not enclose the expr where it occurs
     AutoBorrow(Span),
+
+    // Managed data cannot contain borrowed pointers.
+    Managed(Span),
 }
 
 /// Reasons to create a region inference variable
@@ -336,7 +358,6 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures {
 }
 
 pub fn mk_subr(cx: &InferCtxt,
-               _a_is_expected: bool,
                origin: SubregionOrigin,
                a: ty::Region,
                b: ty::Region) {
@@ -346,6 +367,18 @@ pub fn mk_subr(cx: &InferCtxt,
     cx.region_vars.commit(snapshot);
 }
 
+pub fn verify_param_bound(cx: &InferCtxt,
+                          origin: SubregionOrigin,
+                          param_ty: ty::ParamTy,
+                          a: ty::Region,
+                          bs: Vec<ty::Region>) {
+    debug!("verify_param_bound({}, {} <: {})",
+           param_ty.repr(cx.tcx),
+           a.repr(cx.tcx),
+           bs.repr(cx.tcx));
+
+    cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
+}
 pub fn mk_eqty(cx: &InferCtxt,
                a_is_expected: bool,
                origin: TypeOrigin,
@@ -589,6 +622,13 @@ impl<'a> InferCtxt<'a> {
         self.rollback_to(snapshot);
         r
     }
+
+    pub fn add_given(&self,
+                     sub: ty::FreeRegion,
+                     sup: ty::RegionVid)
+    {
+        self.region_vars.add_given(sub, sup);
+    }
 }
 
 impl<'a> InferCtxt<'a> {
@@ -687,14 +727,13 @@ impl<'a> InferCtxt<'a> {
     }
 
     pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
-                                                      trait_ref:
-                                                      &ty::TraitRef)
+                                                      trait_ref: &ty::TraitRef)
                                                       -> ty::TraitRef {
         // make up a dummy type just to reuse/abuse the resolve machinery
         let dummy0 = ty::mk_trait(self.tcx,
                                   trait_ref.def_id,
                                   trait_ref.substs.clone(),
-                                  ty::empty_builtin_bounds());
+                                  ty::region_existential_bound(ty::ReStatic));
         let dummy1 = self.resolve_type_vars_if_possible(dummy0);
         match ty::get(dummy1).sty {
             ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => {
@@ -896,15 +935,21 @@ impl SubregionOrigin {
             FreeVariable(a, _) => a,
             IndexSlice(a) => a,
             RelateObjectBound(a) => a,
+            RelateProcBound(a, _, _) => a,
+            RelateParamBound(a, _, _) => a,
+            RelateRegionParamBound(a) => a,
+            RelateDefaultParamBound(a, _) => a,
             Reborrow(a) => a,
             ReborrowUpvar(a, _) => a,
             ReferenceOutlivesReferent(_, a) => a,
+            ExprTypeIsNotInScope(_, a) => a,
             BindingTypeIsNotValidAtDecl(a) => a,
             CallRcvr(a) => a,
             CallArg(a) => a,
             CallReturn(a) => a,
             AddrOf(a) => a,
             AutoBorrow(a) => a,
+            Managed(a) => a,
         }
     }
 }
@@ -933,6 +978,27 @@ impl Repr for SubregionOrigin {
             RelateObjectBound(a) => {
                 format!("RelateObjectBound({})", a.repr(tcx))
             }
+            RelateProcBound(a, b, c) => {
+                format!("RelateProcBound({},{},{})",
+                        a.repr(tcx),
+                        b,
+                        c.repr(tcx))
+            }
+            RelateParamBound(a, b, c) => {
+                format!("RelateParamBound({},{},{})",
+                        a.repr(tcx),
+                        b.repr(tcx),
+                        c.repr(tcx))
+            }
+            RelateRegionParamBound(a) => {
+                format!("RelateRegionParamBound({})",
+                        a.repr(tcx))
+            }
+            RelateDefaultParamBound(a, b) => {
+                format!("RelateDefaultParamBound({},{})",
+                        a.repr(tcx),
+                        b.repr(tcx))
+            }
             Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
             ReborrowUpvar(a, b) => {
                 format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
@@ -940,6 +1006,11 @@ impl Repr for SubregionOrigin {
             ReferenceOutlivesReferent(_, a) => {
                 format!("ReferenceOutlivesReferent({})", a.repr(tcx))
             }
+            ExprTypeIsNotInScope(a, b) => {
+                format!("ExprTypeIsNotInScope({}, {})",
+                        a.repr(tcx),
+                        b.repr(tcx))
+            }
             BindingTypeIsNotValidAtDecl(a) => {
                 format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
             }
@@ -948,6 +1019,7 @@ impl Repr for SubregionOrigin {
             CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
             AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
             AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
+            Managed(a) => format!("Managed({})", a.repr(tcx)),
         }
     }
 }
diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs
index dc674da38af..7c8d10dd994 100644
--- a/src/librustc/middle/typeck/infer/region_inference/mod.rs
+++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs
@@ -30,12 +30,32 @@ use syntax::ast;
 
 mod doc;
 
+// A constraint that influences the inference process.
 #[deriving(PartialEq, Eq, Hash)]
 pub enum Constraint {
+    // One region variable is subregion of another
     ConstrainVarSubVar(RegionVid, RegionVid),
+
+    // Concrete region is subregion of region variable
     ConstrainRegSubVar(Region, RegionVid),
+
+    // Region variable is subregion of concrete region
     ConstrainVarSubReg(RegionVid, Region),
-    ConstrainRegSubReg(Region, Region),
+}
+
+// Something we have to verify after region inference is done, but
+// which does not directly influence the inference process
+pub enum Verify {
+    // VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor
+    // `b` are inference variables.
+    VerifyRegSubReg(SubregionOrigin, Region, Region),
+
+    // VerifyParamBound(T, _, R, RS): The parameter type `T` must
+    // outlive the region `R`. `T` is known to outlive `RS`. Therefore
+    // verify that `R <= RS[i]` for some `i`. Inference variables may
+    // be involved (but this verification step doesn't influence
+    // inference).
+    VerifyParamBound(ty::ParamTy, SubregionOrigin, Region, Vec<Region>),
 }
 
 #[deriving(PartialEq, Eq, Hash)]
@@ -51,6 +71,8 @@ pub enum UndoLogEntry {
     Mark,
     AddVar(RegionVid),
     AddConstraint(Constraint),
+    AddVerify(uint),
+    AddGiven(ty::FreeRegion, ty::RegionVid),
     AddCombination(CombineMapType, TwoRegions)
 }
 
@@ -66,6 +88,13 @@ pub enum RegionResolutionError {
     /// `o` requires that `a <= b`, but this does not hold
     ConcreteFailure(SubregionOrigin, Region, Region),
 
+    /// `ParamBoundFailure(p, s, a, bs)
+    ///
+    /// The parameter type `p` must be known to outlive the lifetime
+    /// `a`, but it is only known to outlive `bs` (and none of the
+    /// regions in `bs` outlive `a`).
+    ParamBoundFailure(SubregionOrigin, ty::ParamTy, Region, Vec<Region>),
+
     /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
     ///
     /// Could not infer a value for `v` because `sub_r <= v` (due to
@@ -125,7 +154,38 @@ pub type CombineMap = HashMap<TwoRegions, RegionVid>;
 pub struct RegionVarBindings<'a> {
     tcx: &'a ty::ctxt,
     var_origins: RefCell<Vec<RegionVariableOrigin>>,
+
+    // Constraints of the form `A <= B` introduced by the region
+    // checker.  Here at least one of `A` and `B` must be a region
+    // variable.
     constraints: RefCell<HashMap<Constraint, SubregionOrigin>>,
+
+    // A "verify" is something that we need to verify after inference is
+    // done, but which does not directly affect inference in any way.
+    //
+    // An example is a `A <= B` where neither `A` nor `B` are
+    // inference variables.
+    verifys: RefCell<Vec<Verify>>,
+
+    // A "given" is a relationship that is known to hold. In particular,
+    // we often know from closure fn signatures that a particular free
+    // region must be a subregion of a region variable:
+    //
+    //    foo.iter().filter(<'a> |x: &'a &'b T| ...)
+    //
+    // In situations like this, `'b` is in fact a region variable
+    // introduced by the call to `iter()`, and `'a` is a bound region
+    // on the closure (as indicated by the `<'a>` prefix). If we are
+    // naive, we wind up inferring that `'b` must be `'static`,
+    // because we require that it be greater than `'a` and we do not
+    // know what `'a` is precisely.
+    //
+    // This hashmap is used to avoid that naive scenario. Basically we
+    // record the fact that `'a <= 'b` is implied by the fn signature,
+    // and then ignore the constraint when solving equations. This is
+    // a bit of a hack but seems to work.
+    givens: RefCell<HashSet<(ty::FreeRegion, ty::RegionVid)>>,
+
     lubs: RefCell<CombineMap>,
     glbs: RefCell<CombineMap>,
     skolemization_count: Cell<uint>,
@@ -164,6 +224,8 @@ impl<'a> RegionVarBindings<'a> {
             var_origins: RefCell::new(Vec::new()),
             values: RefCell::new(None),
             constraints: RefCell::new(HashMap::new()),
+            verifys: RefCell::new(Vec::new()),
+            givens: RefCell::new(HashSet::new()),
             lubs: RefCell::new(HashMap::new()),
             glbs: RefCell::new(HashMap::new()),
             skolemization_count: Cell::new(0),
@@ -216,12 +278,19 @@ impl<'a> RegionVarBindings<'a> {
                 Mark | CommitedSnapshot => { }
                 AddVar(vid) => {
                     let mut var_origins = self.var_origins.borrow_mut();
-                    assert_eq!(var_origins.len(), vid.index + 1);
                     var_origins.pop().unwrap();
+                    assert_eq!(var_origins.len(), vid.index);
                 }
                 AddConstraint(ref constraint) => {
                     self.constraints.borrow_mut().remove(constraint);
                 }
+                AddVerify(index) => {
+                    self.verifys.borrow_mut().pop();
+                    assert_eq!(self.verifys.borrow().len(), index);
+                }
+                AddGiven(sub, sup) => {
+                    self.givens.borrow_mut().remove(&(sub, sup));
+                }
                 AddCombination(Glb, ref regions) => {
                     self.glbs.borrow_mut().remove(regions);
                 }
@@ -289,13 +358,14 @@ impl<'a> RegionVarBindings<'a> {
         self.values.borrow().is_none()
     }
 
-    pub fn add_constraint(&self,
-                          constraint: Constraint,
-                          origin: SubregionOrigin) {
+    fn add_constraint(&self,
+                      constraint: Constraint,
+                      origin: SubregionOrigin) {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: add_constraint({:?})", constraint);
+        debug!("RegionVarBindings: add_constraint({})",
+               constraint.repr(self.tcx));
 
         if self.constraints.borrow_mut().insert(constraint, origin) {
             if self.in_snapshot() {
@@ -304,6 +374,38 @@ impl<'a> RegionVarBindings<'a> {
         }
     }
 
+    fn add_verify(&self,
+                  verify: Verify) {
+        // cannot add verifys once regions are resolved
+        assert!(self.values_are_none());
+
+        debug!("RegionVarBindings: add_verify({})",
+               verify.repr(self.tcx));
+
+        let mut verifys = self.verifys.borrow_mut();
+        let index = verifys.len();
+        verifys.push(verify);
+        if self.in_snapshot() {
+            self.undo_log.borrow_mut().push(AddVerify(index));
+        }
+    }
+
+    pub fn add_given(&self,
+                     sub: ty::FreeRegion,
+                     sup: ty::RegionVid) {
+        // cannot add givens once regions are resolved
+        assert!(self.values_are_none());
+
+        let mut givens = self.givens.borrow_mut();
+        if givens.insert((sub, sup)) {
+            debug!("add_given({} <= {})",
+                   sub.repr(self.tcx),
+                   sup);
+
+            self.undo_log.borrow_mut().push(AddGiven(sub, sup));
+        }
+    }
+
     pub fn make_subregion(&self,
                           origin: SubregionOrigin,
                           sub: Region,
@@ -320,7 +422,9 @@ impl<'a> RegionVarBindings<'a> {
           (ReEarlyBound(..), ReEarlyBound(..)) => {
             // This case is used only to make sure that explicitly-specified
             // `Self` types match the real self type in implementations.
-            self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
+            //
+            // FIXME(NDM) -- we really shouldn't be comparing bound things
+            self.add_verify(VerifyRegSubReg(origin, sub, sup));
           }
           (ReEarlyBound(..), _) |
           (ReLateBound(..), _) |
@@ -345,11 +449,19 @@ impl<'a> RegionVarBindings<'a> {
             self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
           }
           _ => {
-            self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
+            self.add_verify(VerifyRegSubReg(origin, sub, sup));
           }
         }
     }
 
+    pub fn verify_param_bound(&self,
+                              origin: SubregionOrigin,
+                              param_ty: ty::ParamTy,
+                              sub: Region,
+                              sups: Vec<Region>) {
+        self.add_verify(VerifyParamBound(param_ty, origin, sub, sups));
+    }
+
     pub fn lub_regions(&self,
                        origin: SubregionOrigin,
                        a: Region,
@@ -358,7 +470,9 @@ impl<'a> RegionVarBindings<'a> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
+        debug!("RegionVarBindings: lub_regions({}, {})",
+               a.repr(self.tcx),
+               b.repr(self.tcx));
         match (a, b) {
             (ReStatic, _) | (_, ReStatic) => {
                 ReStatic // nothing lives longer than static
@@ -381,7 +495,9 @@ impl<'a> RegionVarBindings<'a> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
+        debug!("RegionVarBindings: glb_regions({}, {})",
+               a.repr(self.tcx),
+               b.repr(self.tcx));
         match (a, b) {
             (ReStatic, r) | (r, ReStatic) => {
                 // static lives longer than everything else
@@ -397,30 +513,29 @@ impl<'a> RegionVarBindings<'a> {
         }
     }
 
+    pub fn max_regions(&self,
+                       a: Region,
+                       b: Region)
+                       -> Option<Region>
+    {
+        match self.glb_concrete_regions(a, b) {
+            Ok(r) => Some(r),
+            Err(_) => None
+        }
+    }
+
     pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
-        let v = match *self.values.borrow() {
+        match *self.values.borrow() {
             None => {
                 self.tcx.sess.span_bug(
                     self.var_origins.borrow().get(rid.index).span(),
                     "attempt to resolve region variable before values have \
                      been computed!")
             }
-            Some(ref values) => *values.get(rid.index)
-        };
-
-        debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
-               rid, rid.index, v);
-        match v {
-            Value(r) => r,
-
-            NoValue => {
-                // No constraints, return ty::ReEmpty
-                ReEmpty
-            }
-
-            ErrorValue => {
-                // An error that has previously been reported.
-                ReStatic
+            Some(ref values) => {
+                let r = lookup(values, rid);
+                debug!("resolve_var({}) = {}", rid, r.repr(self.tcx));
+                r
             }
         }
     }
@@ -456,7 +571,7 @@ impl<'a> RegionVarBindings<'a> {
         }
         relate(self, a, ReInfer(ReVar(c)));
         relate(self, b, ReInfer(ReVar(c)));
-        debug!("combine_vars() c={:?}", c);
+        debug!("combine_vars() c={}", c);
         ReInfer(ReVar(c))
     }
 
@@ -493,40 +608,53 @@ impl<'a> RegionVarBindings<'a> {
         while result_index < result_set.len() {
             // nb: can't use uint::range() here because result_set grows
             let r = *result_set.get(result_index);
-            debug!("result_index={}, r={:?}", result_index, r);
+            debug!("result_index={}, r={}", result_index, r);
 
             for undo_entry in
                 self.undo_log.borrow().slice_from(mark.length).iter()
             {
-                let regs = match undo_entry {
-                    &AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
-                        Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b))))
+                match undo_entry {
+                    &AddConstraint(ConstrainVarSubVar(a, b)) => {
+                        consider_adding_bidirectional_edges(
+                            &mut result_set, r,
+                            ReInfer(ReVar(a)), ReInfer(ReVar(b)));
+                    }
+                    &AddConstraint(ConstrainRegSubVar(a, b)) => {
+                        consider_adding_bidirectional_edges(
+                            &mut result_set, r,
+                            a, ReInfer(ReVar(b)));
                     }
-                    &AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
-                        Some((*a, ReInfer(ReVar(*b))))
+                    &AddConstraint(ConstrainVarSubReg(a, b)) => {
+                        consider_adding_bidirectional_edges(
+                            &mut result_set, r,
+                            ReInfer(ReVar(a)), b);
                     }
-                    &AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
-                        Some((ReInfer(ReVar(*a)), *b))
+                    &AddGiven(a, b) => {
+                        consider_adding_bidirectional_edges(
+                            &mut result_set, r,
+                            ReFree(a), ReInfer(ReVar(b)));
                     }
-                    &AddConstraint(ConstrainRegSubReg(a, b)) => {
-                        Some((a, b))
+                    &AddVerify(i) => {
+                        match self.verifys.borrow().get(i) {
+                            &VerifyRegSubReg(_, a, b) => {
+                                consider_adding_bidirectional_edges(
+                                    &mut result_set, r,
+                                    a, b);
+                            }
+                            &VerifyParamBound(_, _, a, ref bs) => {
+                                for &b in bs.iter() {
+                                    consider_adding_bidirectional_edges(
+                                        &mut result_set, r,
+                                        a, b);
+                                }
+                            }
+                        }
                     }
                     &AddCombination(..) |
                     &Mark |
                     &AddVar(..) |
                     &OpenSnapshot |
                     &CommitedSnapshot => {
-                        None
-                    }
-                };
-
-                match regs {
-                    None => {}
-                    Some((r1, r2)) => {
-                        result_set =
-                            consider_adding_edge(result_set, r, r1, r2);
-                        result_set =
-                            consider_adding_edge(result_set, r, r2, r1);
                     }
                 }
             }
@@ -536,17 +664,24 @@ impl<'a> RegionVarBindings<'a> {
 
         return result_set;
 
-        fn consider_adding_edge(result_set: Vec<Region> ,
-                                r: Region,
-                                r1: Region,
-                                r2: Region) -> Vec<Region> {
-            let mut result_set = result_set;
-            if r == r1 { // Clearly, this is potentially inefficient.
+        fn consider_adding_bidirectional_edges(result_set: &mut Vec<Region>,
+                                               r: Region,
+                                               r1: Region,
+                                               r2: Region) {
+            consider_adding_directed_edge(result_set, r, r1, r2);
+            consider_adding_directed_edge(result_set, r, r2, r1);
+        }
+
+        fn consider_adding_directed_edge(result_set: &mut Vec<Region>,
+                                         r: Region,
+                                         r1: Region,
+                                         r2: Region) {
+            if r == r1 {
+                // Clearly, this is potentially inefficient.
                 if !result_set.iter().any(|x| *x == r2) {
                     result_set.push(r2);
                 }
             }
-            return result_set;
         }
     }
 
@@ -595,7 +730,7 @@ impl<'a> RegionVarBindings<'a> {
             self.tcx.sess.span_bug(
                 self.var_origins.borrow().get(v_id.index).span(),
                 format!("lub_concrete_regions invoked with \
-                         non-concrete regions: {:?}, {:?}",
+                         non-concrete regions: {}, {}",
                         a,
                         b).as_slice());
           }
@@ -675,7 +810,7 @@ impl<'a> RegionVarBindings<'a> {
                             a: Region,
                             b: Region)
                          -> cres<Region> {
-        debug!("glb_concrete_regions({:?}, {:?})", a, b);
+        debug!("glb_concrete_regions({}, {})", a, b);
         match (a, b) {
             (ReLateBound(..), _) |
             (_, ReLateBound(..)) |
@@ -702,7 +837,7 @@ impl<'a> RegionVarBindings<'a> {
                 self.tcx.sess.span_bug(
                     self.var_origins.borrow().get(v_id.index).span(),
                     format!("glb_concrete_regions invoked with \
-                             non-concrete regions: {:?}, {:?}",
+                             non-concrete regions: {}, {}",
                             a,
                             b).as_slice());
             }
@@ -783,7 +918,7 @@ impl<'a> RegionVarBindings<'a> {
         // scopes or two free regions.  So, if one of
         // these scopes is a subscope of the other, return
         // it.  Otherwise fail.
-        debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
+        debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={})",
                scope_a, scope_b, region_a, region_b);
         match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) {
             Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
@@ -815,12 +950,16 @@ type RegionGraph = graph::Graph<(), Constraint>;
 impl<'a> RegionVarBindings<'a> {
     fn infer_variable_values(&self,
                              errors: &mut Vec<RegionResolutionError>)
-                             -> Vec<VarValue> {
+                             -> Vec<VarValue>
+    {
         let mut var_data = self.construct_var_data();
         self.expansion(var_data.as_mut_slice());
         self.contraction(var_data.as_mut_slice());
-        self.collect_concrete_region_errors(&mut *errors);
-        self.extract_values_and_collect_conflicts(var_data.as_slice(), errors)
+        let values =
+            self.extract_values_and_collect_conflicts(var_data.as_slice(),
+                                                      errors);
+        self.collect_concrete_region_errors(&values, errors);
+        values
     }
 
     fn construct_var_data(&self) -> Vec<VarData> {
@@ -838,6 +977,12 @@ impl<'a> RegionVarBindings<'a> {
 
     fn expansion(&self, var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Expansion", |constraint| {
+            debug!("expansion: constraint={} origin={}",
+                   constraint.repr(self.tcx),
+                   self.constraints.borrow()
+                                   .find(constraint)
+                                   .unwrap()
+                                   .repr(self.tcx));
             match *constraint {
               ConstrainRegSubVar(a_region, b_vid) => {
                 let b_data = &mut var_data[b_vid.index];
@@ -856,10 +1001,6 @@ impl<'a> RegionVarBindings<'a> {
                 // This is a contraction constraint.  Ignore it.
                 false
               }
-              ConstrainRegSubReg(..) => {
-                // No region variables involved. Ignore.
-                false
-              }
             }
         })
     }
@@ -868,14 +1009,29 @@ impl<'a> RegionVarBindings<'a> {
                    a_region: Region,
                    b_vid: RegionVid,
                    b_data: &mut VarData)
-                   -> bool {
-        debug!("expand_node({:?}, {:?} == {:?})",
-               a_region, b_vid, b_data.value);
+                   -> bool
+    {
+        debug!("expand_node({}, {} == {})",
+               a_region.repr(self.tcx),
+               b_vid,
+               b_data.value.repr(self.tcx));
+
+        // Check if this relationship is implied by a given.
+        match a_region {
+            ty::ReFree(fr) => {
+                if self.givens.borrow().contains(&(fr, b_vid)) {
+                    debug!("given");
+                    return false;
+                }
+            }
+            _ => { }
+        }
 
         b_data.classification = Expanding;
         match b_data.value {
           NoValue => {
-            debug!("Setting initial value of {:?} to {:?}", b_vid, a_region);
+            debug!("Setting initial value of {} to {}",
+                   b_vid, a_region.repr(self.tcx));
 
             b_data.value = Value(a_region);
             return true;
@@ -887,8 +1043,10 @@ impl<'a> RegionVarBindings<'a> {
                 return false;
             }
 
-            debug!("Expanding value of {:?} from {:?} to {:?}",
-                   b_vid, cur_region, lub);
+            debug!("Expanding value of {} from {} to {}",
+                   b_vid,
+                   cur_region.repr(self.tcx),
+                   lub.repr(self.tcx));
 
             b_data.value = Value(lub);
             return true;
@@ -903,6 +1061,12 @@ impl<'a> RegionVarBindings<'a> {
     fn contraction(&self,
                    var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Contraction", |constraint| {
+            debug!("contraction: constraint={} origin={}",
+                   constraint.repr(self.tcx),
+                   self.constraints.borrow()
+                                   .find(constraint)
+                                   .unwrap()
+                                   .repr(self.tcx));
             match *constraint {
               ConstrainRegSubVar(..) => {
                 // This is an expansion constraint.  Ignore.
@@ -921,10 +1085,6 @@ impl<'a> RegionVarBindings<'a> {
                 let a_data = &mut var_data[a_vid.index];
                 self.contract_node(a_vid, a_data, b_region)
               }
-              ConstrainRegSubReg(..) => {
-                // No region variables involved. Ignore.
-                false
-              }
             }
         })
     }
@@ -934,8 +1094,9 @@ impl<'a> RegionVarBindings<'a> {
                      a_data: &mut VarData,
                      b_region: Region)
                      -> bool {
-        debug!("contract_node({:?} == {:?}/{:?}, {:?})",
-               a_vid, a_data.value, a_data.classification, b_region);
+        debug!("contract_node({} == {}/{}, {})",
+               a_vid, a_data.value.repr(self.tcx),
+               a_data.classification, b_region.repr(self.tcx));
 
         return match a_data.value {
             NoValue => {
@@ -967,8 +1128,10 @@ impl<'a> RegionVarBindings<'a> {
                       b_region: Region)
                    -> bool {
             if !this.is_subregion_of(a_region, b_region) {
-                debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
-                       a_vid, a_region, b_region);
+                debug!("Setting {} to ErrorValue: {} not subregion of {}",
+                       a_vid,
+                       a_region.repr(this.tcx),
+                       b_region.repr(this.tcx));
                 a_data.value = ErrorValue;
             }
             false
@@ -985,15 +1148,19 @@ impl<'a> RegionVarBindings<'a> {
                     if glb == a_region {
                         false
                     } else {
-                        debug!("Contracting value of {:?} from {:?} to {:?}",
-                               a_vid, a_region, glb);
+                        debug!("Contracting value of {} from {} to {}",
+                               a_vid,
+                               a_region.repr(this.tcx),
+                               glb.repr(this.tcx));
                         a_data.value = Value(glb);
                         true
                     }
                 }
                 Err(_) => {
-                    debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
-                           a_vid, a_region, b_region);
+                    debug!("Setting {} to ErrorValue: no glb of {}, {}",
+                           a_vid,
+                           a_region.repr(this.tcx),
+                           b_region.repr(this.tcx));
                     a_data.value = ErrorValue;
                     false
                 }
@@ -1001,30 +1168,44 @@ impl<'a> RegionVarBindings<'a> {
         }
     }
 
-    fn collect_concrete_region_errors(
-        &self,
-        errors: &mut Vec<RegionResolutionError>)
+    fn collect_concrete_region_errors(&self,
+                                      values: &Vec<VarValue>,
+                                      errors: &mut Vec<RegionResolutionError>)
     {
-        for (constraint, _) in self.constraints.borrow().iter() {
-            let (sub, sup) = match *constraint {
-                ConstrainVarSubVar(..) |
-                ConstrainRegSubVar(..) |
-                ConstrainVarSubReg(..) => {
-                    continue;
-                }
-                ConstrainRegSubReg(sub, sup) => {
-                    (sub, sup)
+        let mut reg_reg_dups = HashSet::new();
+        for verify in self.verifys.borrow().iter() {
+            match *verify {
+                VerifyRegSubReg(ref origin, sub, sup) => {
+                    if self.is_subregion_of(sub, sup) {
+                        continue;
+                    }
+
+                    if !reg_reg_dups.insert((sub, sup)) {
+                        continue;
+                    }
+
+                    debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}",
+                           sub.repr(self.tcx),
+                           sup.repr(self.tcx));
+                    errors.push(ConcreteFailure((*origin).clone(), sub, sup));
                 }
-            };
 
-            if self.is_subregion_of(sub, sup) {
-                continue;
-            }
+                VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => {
+                    let sub = normalize(values, sub);
+                    if sups.iter()
+                           .map(|&sup| normalize(values, sup))
+                           .any(|sup| self.is_subregion_of(sub, sup))
+                    {
+                        continue;
+                    }
 
-            debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
-                   sub, sup);
-            let origin = self.constraints.borrow().get_copy(constraint);
-            errors.push(ConcreteFailure(origin, sub, sup));
+                    let sups = sups.iter().map(|&sup| normalize(values, sup))
+                                          .collect();
+                    errors.push(
+                        ParamBoundFailure(
+                            (*origin).clone(), *param_ty, sub, sups));
+                }
+            }
         }
     }
 
@@ -1032,7 +1213,8 @@ impl<'a> RegionVarBindings<'a> {
         &self,
         var_data: &[VarData],
         errors: &mut Vec<RegionResolutionError>)
-        -> Vec<VarValue> {
+        -> Vec<VarValue>
+    {
         debug!("extract_values_and_collect_conflicts()");
 
         // This is the best way that I have found to suppress
@@ -1141,10 +1323,6 @@ impl<'a> RegionVarBindings<'a> {
                                    dummy_idx,
                                    *constraint);
                 }
-                ConstrainRegSubReg(..) => {
-                    // Relations between two concrete regions do not
-                    // require an edge in the graph.
-                }
             }
         }
 
@@ -1206,16 +1384,10 @@ impl<'a> RegionVarBindings<'a> {
         self.tcx.sess.span_bug(
             self.var_origins.borrow().get(node_idx.index).span(),
             format!("collect_error_for_expanding_node() could not find error \
-                  for var {:?}, lower_bounds={}, upper_bounds={}",
-                 node_idx,
-                 lower_bounds.iter()
-                             .map(|x| x.region)
-                             .collect::<Vec<ty::Region>>()
-                             .repr(self.tcx),
-                 upper_bounds.iter()
-                             .map(|x| x.region)
-                             .collect::<Vec<ty::Region>>()
-                             .repr(self.tcx)).as_slice());
+                    for var {}, lower_bounds={}, upper_bounds={}",
+                    node_idx,
+                    lower_bounds.repr(self.tcx),
+                    upper_bounds.repr(self.tcx)).as_slice());
     }
 
     fn collect_error_for_contracting_node(
@@ -1257,12 +1429,9 @@ impl<'a> RegionVarBindings<'a> {
         self.tcx.sess.span_bug(
             self.var_origins.borrow().get(node_idx.index).span(),
             format!("collect_error_for_contracting_node() could not find error \
-                  for var {:?}, upper_bounds={}",
-                 node_idx,
-                 upper_bounds.iter()
-                             .map(|x| x.region)
-                             .collect::<Vec<ty::Region>>()
-                             .repr(self.tcx)).as_slice());
+                     for var {}, upper_bounds={}",
+                    node_idx,
+                    upper_bounds.repr(self.tcx)).as_slice());
     }
 
     fn collect_concrete_regions(&self,
@@ -1301,8 +1470,8 @@ impl<'a> RegionVarBindings<'a> {
                 state.dup_found = true;
             }
 
-            debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
-                    classification={:?})",
+            debug!("collect_concrete_regions(orig_node_idx={}, node_idx={}, \
+                    classification={})",
                    orig_node_idx, node_idx, classification);
 
             // figure out the direction from which this node takes its
@@ -1323,7 +1492,7 @@ impl<'a> RegionVarBindings<'a> {
                          graph: &RegionGraph,
                          source_vid: RegionVid,
                          dir: Direction) {
-            debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
+            debug!("process_edges(source_vid={}, dir={})", source_vid, dir);
 
             let source_node_index = NodeIndex(source_vid.index);
             graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
@@ -1343,8 +1512,6 @@ impl<'a> RegionVarBindings<'a> {
                             origin: this.constraints.borrow().get_copy(&edge.data)
                         });
                     }
-
-                    ConstrainRegSubReg(..) => {}
                 }
                 true
             });
@@ -1386,9 +1553,53 @@ impl Repr for Constraint {
             ConstrainVarSubReg(a, b) => {
                 format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
             }
-            ConstrainRegSubReg(a, b) => {
-                format!("ConstrainRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
+        }
+    }
+}
+
+impl Repr for Verify {
+    fn repr(&self, tcx: &ty::ctxt) -> String {
+        match *self {
+            VerifyRegSubReg(_, ref a, ref b) => {
+                format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
+            }
+            VerifyParamBound(_, ref p, ref a, ref bs) => {
+                format!("VerifyParamBound({}, {}, {})",
+                        p.repr(tcx), a.repr(tcx), bs.repr(tcx))
             }
         }
     }
 }
+
+fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
+    match r {
+        ty::ReInfer(ReVar(rid)) => lookup(values, rid),
+        _ => r
+    }
+}
+
+fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
+    match *values.get(rid.index) {
+        Value(r) => r,
+        NoValue => ReEmpty, // No constraints, return ty::ReEmpty
+        ErrorValue => ReStatic, // Previously reported error.
+    }
+}
+
+impl Repr for VarValue {
+    fn repr(&self, tcx: &ty::ctxt) -> String {
+        match *self {
+            NoValue => format!("NoValue"),
+            Value(r) => format!("Value({})", r.repr(tcx)),
+            ErrorValue => format!("ErrorValue"),
+        }
+    }
+}
+
+impl Repr for RegionAndOrigin {
+    fn repr(&self, tcx: &ty::ctxt) -> String {
+        format!("RegionAndOrigin({},{})",
+                self.region.repr(tcx),
+                self.origin.repr(tcx))
+    }
+}
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index a54afb1102f..a9e8d1e8603 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -102,7 +102,8 @@ impl<'f> Combine for Sub<'f> {
         })
     }
 
-    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
+    fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds)
+                      -> cres<BuiltinBounds> {
         // More bounds is a subtype of fewer bounds.
         //
         // e.g., fn:Copy() <: fn(), because the former is a function
diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs
index 44afc04d3f0..33bdded5234 100644
--- a/src/librustc/middle/typeck/infer/unify.rs
+++ b/src/librustc/middle/typeck/infer/unify.rs
@@ -555,3 +555,12 @@ impl SimplyUnifiable for ast::FloatTy {
         return ty::terr_float_mismatch(err);
     }
 }
+
+impl<K:Repr,V:Repr> Repr for VarValue<K,V> {
+    fn repr(&self, tcx: &ty::ctxt) -> String {
+        match *self {
+            Redirect(ref k) => format!("Redirect({})", k.repr(tcx)),
+            Root(ref v, r) => format!("Root({}, {})", v.repr(tcx), r)
+        }
+    }
+}
diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs
index cdb691073cd..530f65855d4 100644
--- a/src/librustc/middle/typeck/rscope.rs
+++ b/src/librustc/middle/typeck/rscope.rs
@@ -30,12 +30,19 @@ pub trait RegionScope {
                     span: Span,
                     count: uint)
                     -> Result<Vec<ty::Region> , ()>;
+
+    fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
 }
 
-// A scope in which all regions must be explicitly named
+// A scope in which all regions must be explicitly named. This is used
+// for types that appear in structs and so on.
 pub struct ExplicitRscope;
 
 impl RegionScope for ExplicitRscope {
+    fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
+        None
+    }
+
     fn anon_regions(&self,
                     _span: Span,
                     _count: uint)
@@ -44,6 +51,33 @@ impl RegionScope for ExplicitRscope {
     }
 }
 
+// A scope in which any omitted region defaults to `default`. This is
+// used after the `->` in function signatures, but also for backwards
+// compatibility with object types. The latter use may go away.
+pub struct SpecificRscope {
+    default: ty::Region
+}
+
+impl SpecificRscope {
+    pub fn new(r: ty::Region) -> SpecificRscope {
+        SpecificRscope { default: r }
+    }
+}
+
+impl RegionScope for SpecificRscope {
+    fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
+        Some(self.default)
+    }
+
+    fn anon_regions(&self,
+                    _span: Span,
+                    count: uint)
+                    -> Result<Vec<ty::Region> , ()>
+    {
+        Ok(Vec::from_elem(count, self.default))
+    }
+}
+
 /// A scope in which we generate anonymous, late-bound regions for
 /// omitted regions. This occurs in function signatures.
 pub struct BindingRscope {
@@ -58,30 +92,26 @@ impl BindingRscope {
             anon_bindings: Cell::new(0),
         }
     }
-}
 
-impl RegionScope for BindingRscope {
-    fn anon_regions(&self,
-                    _: Span,
-                    count: uint)
-                    -> Result<Vec<ty::Region>, ()> {
+    fn next_region(&self) -> ty::Region {
         let idx = self.anon_bindings.get();
-        self.anon_bindings.set(idx + count);
-        Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id,
-                                                   ty::BrAnon(idx + i))))
+        self.anon_bindings.set(idx + 1);
+        ty::ReLateBound(self.binder_id, ty::BrAnon(idx))
     }
 }
 
-/// A scope in which we generate one specific region. This occurs after the
-/// `->` (i.e. in the return type) of function signatures.
-pub struct ImpliedSingleRscope {
-    pub region: ty::Region,
-}
+impl RegionScope for BindingRscope {
+    fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
+    {
+        Some(self.next_region())
+    }
 
-impl RegionScope for ImpliedSingleRscope {
-    fn anon_regions(&self, _: Span, count: uint)
-                    -> Result<Vec<ty::Region>,()> {
-        Ok(Vec::from_elem(count, self.region.clone()))
+    fn anon_regions(&self,
+                    _: Span,
+                    count: uint)
+                    -> Result<Vec<ty::Region> , ()>
+    {
+        Ok(Vec::from_fn(count, |_| self.next_region()))
     }
 }
 
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 9c9942d2628..61ef9df99e8 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -10,6 +10,8 @@
 
 #![allow(non_camel_case_types)]
 
+use std::hash::{Hash, Hasher};
+use std::collections::HashMap;
 use syntax::ast;
 use syntax::visit;
 use syntax::visit::Visitor;
@@ -105,3 +107,51 @@ pub fn block_query(b: ast::P<ast::Block>, p: |&ast::Expr| -> bool) -> bool {
     visit::walk_block(&mut v, &*b, ());
     return v.flag;
 }
+
+// K: Eq + Hash<S>, V, S, H: Hasher<S>
+pub fn can_reach<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>(
+    edges_map: &HashMap<T,Vec<T>,H>,
+    source: T,
+    destination: T)
+    -> bool
+{
+    /*!
+     * Determines whether there exists a path from `source` to
+     * `destination`.  The graph is defined by the `edges_map`, which
+     * maps from a node `S` to a list of its adjacent nodes `T`.
+     *
+     * Efficiency note: This is implemented in an inefficient way
+     * because it is typically invoked on very small graphs. If the graphs
+     * become larger, a more efficient graph representation and algorithm
+     * would probably be advised.
+     */
+
+    if source == destination {
+        return true;
+    }
+
+    // Do a little breadth-first-search here.  The `queue` list
+    // doubles as a way to detect if we've seen a particular FR
+    // before.  Note that we expect this graph to be an *extremely
+    // shallow* tree.
+    let mut queue = vec!(source);
+    let mut i = 0;
+    while i < queue.len() {
+        match edges_map.find(queue.get(i)) {
+            Some(edges) => {
+                for target in edges.iter() {
+                    if *target == destination {
+                        return true;
+                    }
+
+                    if !queue.iter().any(|x| x == target) {
+                        queue.push((*target).clone());
+                    }
+                }
+            }
+            None => {}
+        }
+        i += 1;
+    }
+    return false;
+}
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 5dff183108c..11f16f1ea95 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -23,11 +23,9 @@ use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
 use middle::ty::{ty_unboxed_closure};
 use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
 use middle::ty;
-use middle::typeck::infer::region_inference;
-use middle::typeck::infer::unify::VarValue as VV;
-use middle::typeck::infer::unify;
-use middle::typeck::infer;
 use middle::typeck;
+use middle::typeck::check::regionmanip;
+use middle::typeck::infer;
 
 use std::gc::Gc;
 use std::rc::Rc;
@@ -66,6 +64,22 @@ pub fn note_and_explain_region(cx: &ctxt,
     }
 }
 
+fn item_scope_tag(item: &ast::Item) -> &'static str {
+    /*!
+     * When a free region is associated with `item`, how should we describe
+     * the item in the error message.
+     */
+
+    match item.node {
+        ast::ItemImpl(..) => "impl",
+        ast::ItemStruct(..) => "struct",
+        ast::ItemEnum(..) => "enum",
+        ast::ItemTrait(..) => "trait",
+        ast::ItemFn(..) => "function body",
+        _ => "item"
+    }
+}
+
 pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
                             -> (String, Option<Span>) {
     return match region {
@@ -87,9 +101,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
           Some(ast_map::NodeStmt(stmt)) => {
               explain_span(cx, "statement", stmt.span)
           }
-          Some(ast_map::NodeItem(it)) if (match it.node {
-                ast::ItemFn(..) => true, _ => false}) => {
-              explain_span(cx, "function body", it.span)
+          Some(ast_map::NodeItem(it)) => {
+              let tag = item_scope_tag(&*it);
+              explain_span(cx, tag, it.span)
           }
           Some(_) | None => {
             // this really should not happen
@@ -112,17 +126,17 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
 
         match cx.map.find(fr.scope_id) {
           Some(ast_map::NodeBlock(ref blk)) => {
-            let (msg, opt_span) = explain_span(cx, "block", blk.span);
-            (format!("{} {}", prefix, msg), opt_span)
+              let (msg, opt_span) = explain_span(cx, "block", blk.span);
+              (format!("{} {}", prefix, msg), opt_span)
           }
-          Some(ast_map::NodeItem(it)) if match it.node {
-                ast::ItemImpl(..) => true, _ => false} => {
-            let (msg, opt_span) = explain_span(cx, "impl", it.span);
-            (format!("{} {}", prefix, msg), opt_span)
+          Some(ast_map::NodeItem(it)) => {
+              let tag = item_scope_tag(&*it);
+              let (msg, opt_span) = explain_span(cx, tag, it.span);
+              (format!("{} {}", prefix, msg), opt_span)
           }
           Some(_) | None => {
-            // this really should not happen
-            (format!("{} node {}", prefix, fr.scope_id), None)
+              // this really should not happen
+              (format!("{} node {}", prefix, fr.scope_id), None)
           }
         }
       }
@@ -143,7 +157,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
     };
 
     fn explain_span(cx: &ctxt, heading: &str, span: Span)
-        -> (String, Option<Span>) {
+                    -> (String, Option<Span>) {
         let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo);
         (format!("the {} at {}:{}", heading, lo.line, lo.col.to_uint()),
          Some(span))
@@ -273,7 +287,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
             _ => { }
         }
 
-        push_sig_to_string(cx, &mut s, '(', ')', sig);
+        push_sig_to_string(cx, &mut s, '(', ')', sig, "");
 
         s
     }
@@ -296,34 +310,34 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
             }
         };
 
+        let bounds_str = cty.bounds.user_string(cx);
+
         match cty.store {
             ty::UniqTraitStore => {
                 assert_eq!(cty.onceness, ast::Once);
                 s.push_str("proc");
-                push_sig_to_string(cx, &mut s, '(', ')', &cty.sig);
+                push_sig_to_string(cx, &mut s, '(', ')', &cty.sig,
+                                   bounds_str.as_slice());
             }
             ty::RegionTraitStore(..) => {
                 match cty.onceness {
                     ast::Many => {}
                     ast::Once => s.push_str("once ")
                 }
-                push_sig_to_string(cx, &mut s, '|', '|', &cty.sig);
+                push_sig_to_string(cx, &mut s, '|', '|', &cty.sig,
+                                   bounds_str.as_slice());
             }
         }
 
-        if !cty.bounds.is_empty() {
-            s.push_str(":");
-            s.push_str(cty.bounds.repr(cx).as_slice());
-        }
-
-        s
+        s.into_owned()
     }
 
     fn push_sig_to_string(cx: &ctxt,
                        s: &mut String,
                        bra: char,
                        ket: char,
-                       sig: &ty::FnSig) {
+                       sig: &ty::FnSig,
+                       bounds: &str) {
         s.push_char(bra);
         let strs: Vec<String> = sig.inputs.iter().map(|a| fn_input_to_string(cx, *a)).collect();
         s.push_str(strs.connect(", ").as_slice());
@@ -332,6 +346,11 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
         }
         s.push_char(ket);
 
+        if !bounds.is_empty() {
+            s.push_str(":");
+            s.push_str(bounds);
+        }
+
         if ty::get(sig.output).sty != ty_nil {
             s.push_str(" -> ");
             if ty::type_is_bot(sig.output) {
@@ -383,18 +402,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
       }
       ty_infer(infer_ty) => infer_ty.to_string(),
       ty_err => "[type error]".to_string(),
-      ty_param(ParamTy {idx: id, def_id: did, ..}) => {
-          let ident = match cx.ty_param_defs.borrow().find(&did.node) {
-              Some(def) => token::get_ident(def.ident).get().to_string(),
-              // This can only happen when a type mismatch error happens and
-              // the actual type has more type parameters than the expected one.
-              None => format!("<generic #{}>", id),
-          };
-          if !cx.sess.verbose() {
-              ident
-          } else {
-              format!("{}:{:?}", ident, did)
-          }
+      ty_param(ref param_ty) => {
+          param_ty.repr(cx)
       }
       ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
           let base = ty::item_path_str(cx, did);
@@ -408,8 +417,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
           let trait_def = ty::lookup_trait_def(cx, did);
           let ty = parameterized(cx, base.as_slice(),
                                  substs, &trait_def.generics);
-          let bound_sep = if bounds.is_empty() { "" } else { "+" };
-          let bound_str = bounds.repr(cx);
+          let bound_str = bounds.user_string(cx);
+          let bound_sep = if bound_str.is_empty() { "" } else { "+" };
           format!("{}{}{}",
                   ty,
                   bound_sep,
@@ -573,6 +582,14 @@ impl<T:Repr> Repr for Vec<T> {
     }
 }
 
+impl<T:UserString> UserString for Vec<T> {
+    fn user_string(&self, tcx: &ctxt) -> String {
+        let strs: Vec<String> =
+            self.iter().map(|t| t.user_string(tcx)).collect();
+        strs.connect(", ")
+    }
+}
+
 impl Repr for def::Def {
     fn repr(&self, _tcx: &ctxt) -> String {
         format!("{:?}", *self)
@@ -581,16 +598,18 @@ impl Repr for def::Def {
 
 impl Repr for ty::TypeParameterDef {
     fn repr(&self, tcx: &ctxt) -> String {
-        format!("TypeParameterDef({:?}, {})", self.def_id,
+        format!("TypeParameterDef({}, {})",
+                self.def_id.repr(tcx),
                 self.bounds.repr(tcx))
     }
 }
 
 impl Repr for ty::RegionParameterDef {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("RegionParameterDef({}, {:?})",
+    fn repr(&self, tcx: &ctxt) -> String {
+        format!("RegionParameterDef(name={}, def_id={}, bounds={})",
                 token::get_name(self.name),
-                self.def_id)
+                self.def_id.repr(tcx),
+                self.bounds.repr(tcx))
     }
 }
 
@@ -638,18 +657,31 @@ impl Repr for subst::RegionSubsts {
     }
 }
 
-impl Repr for ty::ParamBounds {
-    fn repr(&self, tcx: &ctxt) -> String {
+impl Repr for ty::BuiltinBounds {
+    fn repr(&self, _tcx: &ctxt) -> String {
         let mut res = Vec::new();
-        for b in self.builtin_bounds.iter() {
+        for b in self.iter() {
             res.push(match b {
-                ty::BoundStatic => "'static".to_string(),
-                ty::BoundSend => "Send".to_string(),
-                ty::BoundSized => "Sized".to_string(),
-                ty::BoundCopy => "Copy".to_string(),
-                ty::BoundSync => "Sync".to_string(),
+                ty::BoundSend => "Send".to_owned(),
+                ty::BoundSized => "Sized".to_owned(),
+                ty::BoundCopy => "Copy".to_owned(),
+                ty::BoundSync => "Sync".to_owned(),
             });
         }
+        res.connect("+")
+    }
+}
+
+impl Repr for ty::ExistentialBounds {
+    fn repr(&self, tcx: &ctxt) -> String {
+        self.user_string(tcx)
+    }
+}
+
+impl Repr for ty::ParamBounds {
+    fn repr(&self, tcx: &ctxt) -> String {
+        let mut res = Vec::new();
+        res.push(self.builtin_bounds.repr(tcx));
         for t in self.trait_bounds.iter() {
             res.push(t.repr(tcx));
         }
@@ -663,6 +695,15 @@ impl Repr for ty::TraitRef {
     }
 }
 
+impl Repr for ty::TraitDef {
+    fn repr(&self, tcx: &ctxt) -> String {
+        format!("TraitDef(generics={}, bounds={}, trait_ref={})",
+                self.generics.repr(tcx),
+                self.bounds.repr(tcx),
+                self.trait_ref.repr(tcx))
+    }
+}
+
 impl Repr for ast::Expr {
     fn repr(&self, _tcx: &ctxt) -> String {
         format!("expr({}: {})", self.id, pprust::expr_to_string(self))
@@ -675,12 +716,24 @@ impl Repr for ast::Path {
     }
 }
 
+impl UserString for ast::Path {
+    fn user_string(&self, _tcx: &ctxt) -> String {
+        pprust::path_to_string(self)
+    }
+}
+
 impl Repr for ast::Item {
     fn repr(&self, tcx: &ctxt) -> String {
         format!("item({})", tcx.map.node_to_string(self.id))
     }
 }
 
+impl Repr for ast::Lifetime {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
+    }
+}
+
 impl Repr for ast::Stmt {
     fn repr(&self, _tcx: &ctxt) -> String {
         format!("stmt({}: {})",
@@ -724,11 +777,7 @@ impl Repr for ty::Region {
                         bound_region.repr(tcx))
             }
 
-            ty::ReFree(ref fr) => {
-                format!("ReFree({}, {})",
-                        fr.scope_id,
-                        fr.bound_region.repr(tcx))
-            }
+            ty::ReFree(ref fr) => fr.repr(tcx),
 
             ty::ReScope(id) => {
                 format!("ReScope({})", id)
@@ -753,6 +802,20 @@ impl Repr for ty::Region {
     }
 }
 
+impl UserString for ty::Region {
+    fn user_string(&self, tcx: &ctxt) -> String {
+        region_to_string(tcx, "", false, *self)
+    }
+}
+
+impl Repr for ty::FreeRegion {
+    fn repr(&self, tcx: &ctxt) -> String {
+        format!("ReFree({}, {})",
+                self.scope_id,
+                self.bound_region.repr(tcx))
+    }
+}
+
 impl Repr for ast::DefId {
     fn repr(&self, tcx: &ctxt) -> String {
         // Unfortunately, there seems to be no way to attempt to print
@@ -833,6 +896,12 @@ impl Repr for ast::Name {
     }
 }
 
+impl UserString for ast::Name {
+    fn user_string(&self, _tcx: &ctxt) -> String {
+        token::get_name(*self).get().to_string()
+    }
+}
+
 impl Repr for ast::Ident {
     fn repr(&self, _tcx: &ctxt) -> String {
         token::get_ident(*self).get().to_string()
@@ -928,21 +997,14 @@ impl Repr for ty::BuiltinBound {
 impl UserString for ty::BuiltinBound {
     fn user_string(&self, _tcx: &ctxt) -> String {
         match *self {
-            ty::BoundStatic => "'static".to_string(),
-            ty::BoundSend => "Send".to_string(),
-            ty::BoundSized => "Sized".to_string(),
-            ty::BoundCopy => "Copy".to_string(),
-            ty::BoundSync => "Sync".to_string(),
+            ty::BoundSend => "Send".to_owned(),
+            ty::BoundSized => "Sized".to_owned(),
+            ty::BoundCopy => "Copy".to_owned(),
+            ty::BoundSync => "Sync".to_owned(),
         }
     }
 }
 
-impl Repr for ty::BuiltinBounds {
-    fn repr(&self, tcx: &ctxt) -> String {
-        self.user_string(tcx)
-    }
-}
-
 impl Repr for Span {
     fn repr(&self, tcx: &ctxt) -> String {
         tcx.sess.codemap().span_to_string(*self).to_string()
@@ -956,6 +1018,43 @@ impl<A:UserString> UserString for Rc<A> {
     }
 }
 
+impl UserString for ty::ParamBounds {
+    fn user_string(&self, tcx: &ctxt) -> String {
+        let mut result = Vec::new();
+        let s = self.builtin_bounds.user_string(tcx);
+        if !s.is_empty() {
+            result.push(s);
+        }
+        for n in self.trait_bounds.iter() {
+            result.push(n.user_string(tcx));
+        }
+        result.connect("+")
+    }
+}
+
+impl UserString for ty::ExistentialBounds {
+    fn user_string(&self, tcx: &ctxt) -> String {
+        if self.builtin_bounds.contains_elem(ty::BoundSend) &&
+            self.region_bound == ty::ReStatic
+        { // Region bound is implied by builtin bounds:
+            return self.builtin_bounds.repr(tcx);
+        }
+
+        let mut res = Vec::new();
+
+        let region_str = self.region_bound.user_string(tcx);
+        if !region_str.is_empty() {
+            res.push(region_str);
+        }
+
+        for bound in self.builtin_bounds.iter() {
+            res.push(bound.user_string(tcx));
+        }
+
+        res.connect("+")
+    }
+}
+
 impl UserString for ty::BuiltinBounds {
     fn user_string(&self, tcx: &ctxt) -> String {
         self.iter()
@@ -1083,33 +1182,55 @@ impl<T:Repr> Repr for infer::Bounds<T> {
     }
 }
 
-impl<K:Repr,V:Repr> Repr for VV<K,V> {
-    fn repr(&self, tcx: &ctxt) -> String {
-        match *self {
-            unify::Redirect(ref k) =>
-                format!("Redirect({})", k.repr(tcx)),
-            unify::Root(ref v, r) =>
-                format!("Root({}, {})", v.repr(tcx), r)
-        }
+impl Repr for ty::ExplicitSelfCategory {
+    fn repr(&self, _: &ctxt) -> String {
+        explicit_self_category_to_str(self).to_string()
     }
 }
 
-impl Repr for region_inference::VarValue {
+
+impl Repr for regionmanip::WfConstraint {
     fn repr(&self, tcx: &ctxt) -> String {
         match *self {
-            infer::region_inference::NoValue =>
-                format!("NoValue"),
-            infer::region_inference::Value(r) =>
-                format!("Value({})", r.repr(tcx)),
-            infer::region_inference::ErrorValue =>
-                format!("ErrorValue"),
+            regionmanip::RegionSubRegionConstraint(_, r_a, r_b) => {
+                format!("RegionSubRegionConstraint({}, {})",
+                        r_a.repr(tcx),
+                        r_b.repr(tcx))
+            }
+
+            regionmanip::RegionSubParamConstraint(_, r, p) => {
+                format!("RegionSubParamConstraint({}, {})",
+                        r.repr(tcx),
+                        p.repr(tcx))
+            }
         }
     }
 }
 
-impl Repr for ty::ExplicitSelfCategory {
-    fn repr(&self, _: &ctxt) -> String {
-        explicit_self_category_to_str(self).to_string()
+impl UserString for ParamTy {
+    fn user_string(&self, tcx: &ctxt) -> String {
+        let id = self.idx;
+        let did = self.def_id;
+        let ident = match tcx.ty_param_defs.borrow().find(&did.node) {
+            Some(def) => token::get_ident(def.ident).get().to_string(),
+
+            // This can only happen when a type mismatch error happens and
+            // the actual type has more type parameters than the expected one.
+            None => format!("<generic #{}>", id),
+        };
+        ident
+    }
+}
+
+impl Repr for ParamTy {
+    fn repr(&self, tcx: &ctxt) -> String {
+        self.user_string(tcx)
     }
 }
 
+impl<A:Repr,B:Repr> Repr for (A,B) {
+    fn repr(&self, tcx: &ctxt) -> String {
+        let &(ref a, ref b) = self;
+        format!("({},{})", a.repr(tcx), b.repr(tcx))
+    }
+}
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 1ac0aee85d4..522941cee8c 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -192,7 +192,7 @@ impl AttrHelper for SpecialAttribute {
 }
 
 pub struct AttrBuilder {
-    attrs: Vec<(uint, Box<AttrHelper>)>
+    attrs: Vec<(uint, Box<AttrHelper+'static>)>
 }
 
 impl AttrBuilder {
@@ -203,12 +203,12 @@ impl AttrBuilder {
     }
 
     pub fn arg<'a, T: AttrHelper + 'static>(&'a mut self, idx: uint, a: T) -> &'a mut AttrBuilder {
-        self.attrs.push((idx, box a as Box<AttrHelper>));
+        self.attrs.push((idx, box a as Box<AttrHelper+'static>));
         self
     }
 
     pub fn ret<'a, T: AttrHelper + 'static>(&'a mut self, a: T) -> &'a mut AttrBuilder {
-        self.attrs.push((ReturnIndex as uint, box a as Box<AttrHelper>));
+        self.attrs.push((ReturnIndex as uint, box a as Box<AttrHelper+'static>));
         self
     }
 
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 445672fcdc4..ee1b51683c2 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -159,18 +159,12 @@ pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
             clean::RequiredMethod(trait_item)
         }
     });
-    let supertraits = ty::trait_supertraits(tcx, did);
-    let mut parents = supertraits.iter().map(|i| {
-        match i.clean() {
-            clean::TraitBound(ty) => ty,
-            clean::RegionBound => unreachable!()
-        }
-    });
-
+    let trait_def = ty::lookup_trait_def(tcx, did);
+    let bounds = trait_def.bounds.clean();
     clean::Trait {
         generics: (&def.generics, subst::TypeSpace).clean(),
         items: items.collect(),
-        parents: parents.collect()
+        bounds: bounds,
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index dc2c0d1d083..af4df81f996 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -481,15 +481,14 @@ impl Clean<TyParam> for ty::TypeParameterDef {
 
 #[deriving(Clone, Encodable, Decodable, PartialEq)]
 pub enum TyParamBound {
-    RegionBound,
+    RegionBound, // FIXME(#16518) -- need to include name of actual region
     TraitBound(Type)
 }
 
 impl Clean<TyParamBound> for ast::TyParamBound {
     fn clean(&self) -> TyParamBound {
         match *self {
-            ast::StaticRegionTyParamBound => RegionBound,
-            ast::OtherRegionTyParamBound(_) => RegionBound,
+            ast::RegionTyParamBound(_) => RegionBound,
             ast::UnboxedFnTyParamBound(_) => {
                 // FIXME(pcwalton): Wrong.
                 RegionBound
@@ -499,6 +498,16 @@ impl Clean<TyParamBound> for ast::TyParamBound {
     }
 }
 
+impl Clean<Vec<TyParamBound>> for ty::ExistentialBounds {
+    fn clean(&self) -> Vec<TyParamBound> {
+        let mut vec = vec!(RegionBound);
+        for bb in self.builtin_bounds.iter() {
+            vec.push(bb.clean());
+        }
+        vec
+    }
+}
+
 fn external_path(name: &str, substs: &subst::Substs) -> Path {
     let lifetimes = substs.regions().get_slice(subst::TypeSpace)
                     .iter()
@@ -525,7 +534,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
         };
         let empty = subst::Substs::empty();
         let (did, path) = match *self {
-            ty::BoundStatic => return RegionBound,
             ty::BoundSend =>
                 (tcx.lang_items.send_trait().unwrap(),
                  external_path("Send", &empty)),
@@ -810,10 +818,7 @@ impl Clean<ClosureDecl> for ast::ClosureTy {
             decl: self.decl.clean(),
             onceness: self.onceness,
             fn_style: self.fn_style,
-            bounds: match self.bounds {
-                Some(ref x) => x.clean(),
-                None        => Vec::new()
-            },
+            bounds: self.bounds.clean()
         }
     }
 }
@@ -909,7 +914,7 @@ impl Clean<RetStyle> for ast::RetStyle {
 pub struct Trait {
     pub items: Vec<TraitItem>,
     pub generics: Generics,
-    pub parents: Vec<Type>,
+    pub bounds: Vec<TyParamBound>,
 }
 
 impl Clean<Item> for doctree::Trait {
@@ -924,7 +929,7 @@ impl Clean<Item> for doctree::Trait {
             inner: TraitItem(Trait {
                 items: self.items.clean(),
                 generics: self.generics.clean(),
-                parents: self.parents.clean(),
+                bounds: self.bounds.clean(),
             }),
         }
     }
@@ -1060,7 +1065,7 @@ pub enum Type {
     Self(ast::DefId),
     /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
     Primitive(Primitive),
-    Closure(Box<ClosureDecl>, Option<Lifetime>),
+    Closure(Box<ClosureDecl>),
     Proc(Box<ClosureDecl>),
     /// extern "ABI" fn
     BareFunction(Box<BareFunctionDecl>),
@@ -1208,7 +1213,7 @@ impl Clean<Type> for ast::Ty {
                              tpbs.clean().map(|x| x),
                              id)
             }
-            TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
+            TyClosure(ref c) => Closure(box c.clean()),
             TyProc(ref c) => Proc(box c.clean()),
             TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
             TyParen(ref ty) => ty.clean(),
@@ -1273,11 +1278,11 @@ impl Clean<Type> for ty::t {
                     decl: (ast_util::local_def(0), &fty.sig).clean(),
                     onceness: fty.onceness,
                     fn_style: fty.fn_style,
-                    bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
+                    bounds: fty.bounds.clean(),
                 };
                 match fty.store {
                     ty::UniqTraitStore => Proc(decl),
-                    ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
+                    ty::RegionTraitStore(..) => Closure(decl),
                 }
             }
             ty::ty_struct(did, ref substs) |
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index da45321e7fd..4d2cf852b8a 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -156,7 +156,7 @@ pub struct Trait {
     pub name: Ident,
     pub items: Vec<ast::TraitItem>, //should be TraitItem
     pub generics: ast::Generics,
-    pub parents: Vec<ast::TraitRef>,
+    pub bounds: Vec<ast::TyParamBound>,
     pub attrs: Vec<ast::Attribute>,
     pub id: ast::NodeId,
     pub whence: Span,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 37349388588..e526286ef46 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -355,7 +355,7 @@ impl fmt::Show for clean::Type {
             }
             clean::Self(..) => f.write("Self".as_bytes()),
             clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
-            clean::Closure(ref decl, ref region) => {
+            clean::Closure(ref decl) => {
                 write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
                        style = FnStyleSpace(decl.fn_style),
                        lifetimes = if decl.lifetimes.len() == 0 {
@@ -370,13 +370,6 @@ impl fmt::Show for clean::Type {
                        },
                        bounds = {
                            let mut ret = String::new();
-                           match *region {
-                               Some(ref lt) => {
-                                   ret.push_str(format!(": {}",
-                                                        *lt).as_slice());
-                               }
-                               None => {}
-                           }
                            for bound in decl.bounds.iter() {
                                 match *bound {
                                     clean::RegionBound => {}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 6415ee85f57..8342b6bd675 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1610,12 +1610,12 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
 
 fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
               t: &clean::Trait) -> fmt::Result {
-    let mut parents = String::new();
-    if t.parents.len() > 0 {
-        parents.push_str(": ");
-        for (i, p) in t.parents.iter().enumerate() {
-            if i > 0 { parents.push_str(" + "); }
-            parents.push_str(format!("{}", *p).as_slice());
+    let mut bounds = String::new();
+    if t.bounds.len() > 0 {
+        bounds.push_str(": ");
+        for (i, p) in t.bounds.iter().enumerate() {
+            if i > 0 { bounds.push_str(" + "); }
+            bounds.push_str(format!("{}", *p).as_slice());
         }
     }
 
@@ -1624,7 +1624,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                   VisSpace(it.visibility),
                   it.name.get_ref().as_slice(),
                   t.generics,
-                  parents));
+                  bounds));
     let required = t.items.iter()
                           .filter(|m| {
                               match **m {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b67b3c394d6..1706ebfbcf4 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -317,12 +317,12 @@ impl<'a> RustdocVisitor<'a> {
                 };
                 om.statics.push(s);
             },
-            ast::ItemTrait(ref gen, _, ref tr, ref items) => {
+            ast::ItemTrait(ref gen, _, ref b, ref items) => {
                 let t = Trait {
                     name: item.ident,
                     items: items.iter().map(|x| (*x).clone()).collect(),
                     generics: gen.clone(),
-                    parents: tr.iter().map(|x| (*x).clone()).collect(),
+                    bounds: b.iter().map(|x| (*x).clone()).collect(),
                     id: item.id,
                     attrs: item.attrs.iter().map(|x| *x).collect(),
                     whence: item.span,
diff --git a/src/librustrt/exclusive.rs b/src/librustrt/exclusive.rs
index 179d050f598..28514bec5b4 100644
--- a/src/librustrt/exclusive.rs
+++ b/src/librustrt/exclusive.rs
@@ -26,7 +26,8 @@ pub struct Exclusive<T> {
     data: UnsafeCell<T>,
 }
 
-/// An RAII guard returned via `lock`
+/// stage0 only
+#[cfg(stage0)]
 pub struct ExclusiveGuard<'a, T> {
     // FIXME #12808: strange name to try to avoid interfering with
     // field accesses of the contained type via Deref
@@ -34,6 +35,15 @@ pub struct ExclusiveGuard<'a, T> {
     _guard: mutex::LockGuard<'a>,
 }
 
+/// An RAII guard returned via `lock`
+#[cfg(not(stage0))]
+pub struct ExclusiveGuard<'a, T:'a> {
+    // FIXME #12808: strange name to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _data: &'a mut T,
+    _guard: mutex::LockGuard<'a>,
+}
+
 impl<T: Send> Exclusive<T> {
     /// Creates a new `Exclusive` which will protect the data provided.
     pub fn new(user_data: T) -> Exclusive<T> {
diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs
index 70ce85ee649..5ca46a728c3 100644
--- a/src/librustrt/lib.rs
+++ b/src/librustrt/lib.rs
@@ -19,6 +19,7 @@
 #![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
 #![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
 #![feature(import_shadowing)]
+#![feature(issue_5723_bootstrap)]
 #![no_std]
 #![experimental]
 
@@ -98,7 +99,7 @@ pub trait Runtime {
     fn can_block(&self) -> bool;
 
     // FIXME: This is a serious code smell and this should not exist at all.
-    fn wrap(self: Box<Self>) -> Box<Any>;
+    fn wrap(self: Box<Self>) -> Box<Any+'static>;
 }
 
 /// The default error code of the rust runtime if the main task fails instead
diff --git a/src/librustrt/local_data.rs b/src/librustrt/local_data.rs
index 6a0b599179c..fedea3c31e0 100644
--- a/src/librustrt/local_data.rs
+++ b/src/librustrt/local_data.rs
@@ -144,6 +144,16 @@ unsafe fn get_local_map<'a>() -> Option<&'a mut Map> {
 ///
 /// The task-local data can be accessed through this value, and when this
 /// structure is dropped it will return the borrow on the data.
+#[cfg(not(stage0))]
+pub struct Ref<T:'static> {
+    // FIXME #12808: strange names to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _inner: &'static TLDValueBox<T>,
+    _marker: marker::NoSend
+}
+
+/// stage0 only
+#[cfg(stage0)]
 pub struct Ref<T> {
     // FIXME #12808: strange names to try to avoid interfering with
     // field accesses of the contained type via Deref
diff --git a/src/librustrt/rtio.rs b/src/librustrt/rtio.rs
index 261d544a241..1afd88edbc2 100644
--- a/src/librustrt/rtio.rs
+++ b/src/librustrt/rtio.rs
@@ -120,7 +120,7 @@ pub struct ProcessConfig<'a> {
 }
 
 pub struct LocalIo<'a> {
-    factory: &'a mut IoFactory,
+    factory: &'a mut IoFactory+'a,
 }
 
 #[unsafe_destructor]
@@ -174,7 +174,7 @@ impl<'a> LocalIo<'a> {
         }
     }
 
-    pub fn new<'a>(io: &'a mut IoFactory) -> LocalIo<'a> {
+    pub fn new<'a>(io: &'a mut IoFactory+'a) -> LocalIo<'a> {
         LocalIo { factory: io }
     }
 
diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs
index acd53535e3b..e39071864a7 100644
--- a/src/librustrt/task.rs
+++ b/src/librustrt/task.rs
@@ -103,7 +103,7 @@ pub struct Task {
     pub name: Option<SendStr>,
 
     state: TaskState,
-    imp: Option<Box<Runtime + Send>>,
+    imp: Option<Box<Runtime + Send + 'static>>,
 }
 
 // Once a task has entered the `Armed` state it must be destroyed via `drop`,
@@ -353,14 +353,14 @@ impl Task {
     /// Inserts a runtime object into this task, transferring ownership to the
     /// task. It is illegal to replace a previous runtime object in this task
     /// with this argument.
-    pub fn put_runtime(&mut self, ops: Box<Runtime + Send>) {
+    pub fn put_runtime(&mut self, ops: Box<Runtime + Send + 'static>) {
         assert!(self.imp.is_none());
         self.imp = Some(ops);
     }
 
     /// Removes the runtime from this task, transferring ownership to the
     /// caller.
-    pub fn take_runtime(&mut self) -> Box<Runtime + Send> {
+    pub fn take_runtime(&mut self) -> Box<Runtime + Send + 'static> {
         assert!(self.imp.is_some());
         self.imp.take().unwrap()
     }
@@ -390,7 +390,7 @@ impl Task {
                 Ok(t) => Some(t),
                 Err(t) => {
                     let data = mem::transmute::<_, raw::TraitObject>(t).data;
-                    let obj: Box<Runtime + Send> =
+                    let obj: Box<Runtime + Send + 'static> =
                         mem::transmute(raw::TraitObject {
                             vtable: vtable,
                             data: data,
diff --git a/src/librustuv/access.rs b/src/librustuv/access.rs
index 290293cf086..0fa89ce989a 100644
--- a/src/librustuv/access.rs
+++ b/src/librustuv/access.rs
@@ -26,11 +26,18 @@ pub struct Access<T> {
     inner: Arc<UnsafeCell<Inner<T>>>,
 }
 
+#[cfg(stage0)]
 pub struct Guard<'a, T> {
     access: &'a mut Access<T>,
     missile: Option<HomingMissile>,
 }
 
+#[cfg(not(stage0))]
+pub struct Guard<'a, T:'static> {
+    access: &'a mut Access<T>,
+    missile: Option<HomingMissile>,
+}
+
 struct Inner<T> {
     queue: Vec<(BlockedTask, uint)>,
     held: bool,
diff --git a/src/librustuv/timeout.rs b/src/librustuv/timeout.rs
index 32d73952416..d2482ee6b60 100644
--- a/src/librustuv/timeout.rs
+++ b/src/librustuv/timeout.rs
@@ -28,12 +28,20 @@ pub struct AccessTimeout<T> {
     pub access: access::Access<T>,
 }
 
+#[cfg(stage0)]
 pub struct Guard<'a, T> {
     state: &'a mut TimeoutState,
     pub access: access::Guard<'a, T>,
     pub can_timeout: bool,
 }
 
+#[cfg(not(stage0))]
+pub struct Guard<'a, T:'static> {
+    state: &'a mut TimeoutState,
+    pub access: access::Guard<'a, T>,
+    pub can_timeout: bool,
+}
+
 #[deriving(PartialEq)]
 enum TimeoutState {
     NoTimeout,
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index cfc915c7d0a..d70b6b4d57b 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -382,7 +382,7 @@ fn fmt_number_or_null(v: f64) -> String {
 
 /// A structure for implementing serialization to JSON.
 pub struct Encoder<'a> {
-    writer: &'a mut io::Writer,
+    writer: &'a mut io::Writer+'a,
 }
 
 impl<'a> Encoder<'a> {
@@ -594,7 +594,7 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
 /// Another encoder for JSON, but prints out human-readable JSON instead of
 /// compact data
 pub struct PrettyEncoder<'a> {
-    writer: &'a mut io::Writer,
+    writer: &'a mut io::Writer+'a,
     curr_indent: uint,
     indent: uint,
 }
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 5c35ad85233..44ea56f4c73 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -24,6 +24,7 @@ Core encoding and decoding interfaces.
        html_root_url = "http://doc.rust-lang.org/master/",
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(macro_rules, managed_boxes, default_type_params, phase)]
+#![feature(issue_5723_bootstrap)]
 
 // test harness access
 #[cfg(test)]
diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs
index b8f8bd41a2d..714712d9eba 100644
--- a/src/libstd/collections/hashmap.rs
+++ b/src/libstd/collections/hashmap.rs
@@ -409,20 +409,38 @@ mod table {
         assert_eq!(size_of::<SafeHash>(), size_of::<u64>())
     }
 
-    /// Iterator over shared references to entries in a table.
+    /// Note: stage0-specific version that lacks bound.
+    #[cfg(stage0)]
     pub struct Entries<'a, K, V> {
         table: &'a RawTable<K, V>,
         idx: uint,
         elems_seen: uint,
     }
 
-    /// Iterator over mutable references to entries in a table.
+    /// Iterator over shared references to entries in a table.
+    #[cfg(not(stage0))]
+    pub struct Entries<'a, K:'a, V:'a> {
+        table: &'a RawTable<K, V>,
+        idx: uint,
+        elems_seen: uint,
+    }
+
+    /// Note: stage0-specific version that lacks bound.
+    #[cfg(stage0)]
     pub struct MutEntries<'a, K, V> {
         table: &'a mut RawTable<K, V>,
         idx: uint,
         elems_seen: uint,
     }
 
+    /// Iterator over mutable references to entries in a table.
+    #[cfg(not(stage0))]
+    pub struct MutEntries<'a, K:'a, V:'a> {
+        table: &'a mut RawTable<K, V>,
+        idx: uint,
+        elems_seen: uint,
+    }
+
     /// Iterator over the entries in a table, consuming the table.
     pub struct MoveEntries<K, V> {
         table: RawTable<K, V>,
diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs
index 12caa715865..ffbcdd87bfe 100644
--- a/src/libstd/io/extensions.rs
+++ b/src/libstd/io/extensions.rs
@@ -37,10 +37,29 @@ use ptr::RawPtr;
 ///
 /// Any error other than `EndOfFile` that is produced by the underlying Reader
 /// is returned by the iterator and should be handled by the caller.
+#[cfg(stage0)]
 pub struct Bytes<'r, T> {
     reader: &'r mut T,
 }
 
+/// An iterator that reads a single byte on each iteration,
+/// until `.read_byte()` returns `EndOfFile`.
+///
+/// # Notes about the Iteration Protocol
+///
+/// The `Bytes` may yield `None` and thus terminate
+/// an iteration, but continue to yield elements if iteration
+/// is attempted again.
+///
+/// # Error
+///
+/// Any error other than `EndOfFile` that is produced by the underlying Reader
+/// is returned by the iterator and should be handled by the caller.
+#[cfg(not(stage0))]
+pub struct Bytes<'r, T:'r> {
+    reader: &'r mut T,
+}
+
 impl<'r, R: Reader> Bytes<'r, R> {
     /// Constructs a new byte iterator from the given Reader instance.
     pub fn new(r: &'r mut R) -> Bytes<'r, R> {
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index dc6478df360..38aa58f1c6a 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -945,11 +945,11 @@ pub trait Reader {
     }
 }
 
-impl Reader for Box<Reader> {
+impl Reader for Box<Reader+'static> {
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
 }
 
-impl<'a> Reader for &'a mut Reader {
+impl<'a> Reader for &'a mut Reader+'a {
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
 }
 
@@ -976,6 +976,13 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
     })
 }
 
+/// Note: stage0-specific version that lacks bound.
+#[cfg(stage0)]
+pub struct RefReader<'a, R> {
+    /// The underlying reader which this is referencing
+    inner: &'a mut R
+}
+
 /// A `RefReader` is a struct implementing `Reader` which contains a reference
 /// to another reader. This is often useful when composing streams.
 ///
@@ -1000,7 +1007,8 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
 ///
 /// # }
 /// ```
-pub struct RefReader<'a, R> {
+#[cfg(not(stage0))]
+pub struct RefReader<'a, R:'a> {
     /// The underlying reader which this is referencing
     inner: &'a mut R
 }
@@ -1058,12 +1066,21 @@ pub trait Writer {
     ///
     /// This function will return any I/O error reported while formatting.
     fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
+        // Note: stage0-specific version that lacks bound.
+        #[cfg(stage0)]
+        struct Adaptor<'a, T> {
+            inner: &'a mut T,
+            error: IoResult<()>,
+        }
+
         // Create a shim which translates a Writer to a FormatWriter and saves
         // off I/O errors. instead of discarding them
-        struct Adaptor<'a, T> {
+        #[cfg(not(stage0))]
+        struct Adaptor<'a, T:'a> {
             inner: &'a mut T,
             error: IoResult<()>,
         }
+
         impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
             fn write(&mut self, bytes: &[u8]) -> fmt::Result {
                 match self.inner.write(bytes) {
@@ -1278,7 +1295,7 @@ pub trait Writer {
     }
 }
 
-impl Writer for Box<Writer> {
+impl Writer for Box<Writer+'static> {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
 
@@ -1286,7 +1303,7 @@ impl Writer for Box<Writer> {
     fn flush(&mut self) -> IoResult<()> { self.flush() }
 }
 
-impl<'a> Writer for &'a mut Writer {
+impl<'a> Writer for &'a mut Writer+'a {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
 
@@ -1318,11 +1335,42 @@ impl<'a> Writer for &'a mut Writer {
 /// println!("input processed: {}", output.unwrap());
 /// # }
 /// ```
+#[cfg(stage0)]
 pub struct RefWriter<'a, W> {
     /// The underlying writer which this is referencing
     inner: &'a mut W
 }
 
+/// A `RefWriter` is a struct implementing `Writer` which contains a reference
+/// to another writer. This is often useful when composing streams.
+///
+/// # Example
+///
+/// ```
+/// # fn main() {}
+/// # fn process_input<R: Reader>(r: R) {}
+/// # fn foo () {
+/// use std::io::util::TeeReader;
+/// use std::io::{stdin, MemWriter};
+///
+/// let mut output = MemWriter::new();
+///
+/// {
+///     // Don't give ownership of 'output' to the 'tee'. Instead we keep a
+///     // handle to it in the outer scope
+///     let mut tee = TeeReader::new(stdin(), output.by_ref());
+///     process_input(tee);
+/// }
+///
+/// println!("input processed: {}", output.unwrap());
+/// # }
+/// ```
+#[cfg(not(stage0))]
+pub struct RefWriter<'a, W:'a> {
+    /// The underlying writer which this is referencing
+    inner: &'a mut W
+}
+
 impl<'a, W: Writer> Writer for RefWriter<'a, W> {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }
@@ -1351,10 +1399,29 @@ impl<T: Reader + Writer> Stream for T {}
 ///
 /// Any error other than `EndOfFile` that is produced by the underlying Reader
 /// is returned by the iterator and should be handled by the caller.
+#[cfg(stage0)]
 pub struct Lines<'r, T> {
     buffer: &'r mut T,
 }
 
+/// An iterator that reads a line on each iteration,
+/// until `.read_line()` encounters `EndOfFile`.
+///
+/// # Notes about the Iteration Protocol
+///
+/// The `Lines` may yield `None` and thus terminate
+/// an iteration, but continue to yield elements if iteration
+/// is attempted again.
+///
+/// # Error
+///
+/// Any error other than `EndOfFile` that is produced by the underlying Reader
+/// is returned by the iterator and should be handled by the caller.
+#[cfg(not(stage0))]
+pub struct Lines<'r, T:'r> {
+    buffer: &'r mut T,
+}
+
 impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
     fn next(&mut self) -> Option<IoResult<String>> {
         match self.buffer.read_line() {
@@ -1378,10 +1445,29 @@ impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
 ///
 /// Any error other than `EndOfFile` that is produced by the underlying Reader
 /// is returned by the iterator and should be handled by the caller.
+#[cfg(stage0)]
 pub struct Chars<'r, T> {
     buffer: &'r mut T
 }
 
+/// An iterator that reads a utf8-encoded character on each iteration,
+/// until `.read_char()` encounters `EndOfFile`.
+///
+/// # Notes about the Iteration Protocol
+///
+/// The `Chars` may yield `None` and thus terminate
+/// an iteration, but continue to yield elements if iteration
+/// is attempted again.
+///
+/// # Error
+///
+/// Any error other than `EndOfFile` that is produced by the underlying Reader
+/// is returned by the iterator and should be handled by the caller.
+#[cfg(not(stage0))]
+pub struct Chars<'r, T:'r> {
+    buffer: &'r mut T
+}
+
 impl<'r, T: Buffer> Iterator<IoResult<char>> for Chars<'r, T> {
     fn next(&mut self) -> Option<IoResult<char>> {
         match self.buffer.read_char() {
@@ -1611,6 +1697,12 @@ pub trait Acceptor<T> {
     }
 }
 
+/// Note: stage0-specific version that lacks bound on A.
+#[cfg(stage0)]
+pub struct IncomingConnections<'a, A> {
+    inc: &'a mut A,
+}
+
 /// An infinite iterator over incoming connection attempts.
 /// Calling `next` will block the task until a connection is attempted.
 ///
@@ -1618,7 +1710,8 @@ pub trait Acceptor<T> {
 /// `Some`. The `Some` contains the `IoResult` representing whether the
 /// connection attempt was successful.  A successful connection will be wrapped
 /// in `Ok`. A failed connection is represented as an `Err`.
-pub struct IncomingConnections<'a, A> {
+#[cfg(not(stage0))]
+pub struct IncomingConnections<'a, A:'a> {
     inc: &'a mut A,
 }
 
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
index 1fe0ba780a6..7fba0bc85a6 100644
--- a/src/libstd/io/util.rs
+++ b/src/libstd/io/util.rs
@@ -126,12 +126,12 @@ impl Buffer for NullReader {
 /// The `Writer`s are delegated to in order. If any `Writer` returns an error,
 /// that error is returned immediately and remaining `Writer`s are not called.
 pub struct MultiWriter {
-    writers: Vec<Box<Writer>>
+    writers: Vec<Box<Writer+'static>>
 }
 
 impl MultiWriter {
     /// Creates a new `MultiWriter`
-    pub fn new(writers: Vec<Box<Writer>>) -> MultiWriter {
+    pub fn new(writers: Vec<Box<Writer+'static>>) -> MultiWriter {
         MultiWriter { writers: writers }
     }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index d35b644b643..8c1ed7cfa8f 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -108,6 +108,7 @@
 #![feature(macro_rules, globs, managed_boxes, linkage)]
 #![feature(default_type_params, phase, lang_items, unsafe_destructor)]
 #![feature(import_shadowing)]
+#![feature(issue_5723_bootstrap)]
 
 // Don't link to std. We are std.
 #![no_std]
diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs
index 50441cb534d..6a10be84a62 100644
--- a/src/libstd/path/mod.rs
+++ b/src/libstd/path/mod.rs
@@ -825,12 +825,20 @@ pub trait GenericPathUnsafe {
     unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
 }
 
-/// Helper struct for printing paths with format!()
+/// Note: stage0-specific version that lacks bound.
+#[cfg(stage0)]
 pub struct Display<'a, P> {
     path: &'a P,
     filename: bool
 }
 
+/// Helper struct for printing paths with format!()
+#[cfg(not(stage0))]
+pub struct Display<'a, P:'a> {
+    path: &'a P,
+    filename: bool
+}
+
 impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         self.as_maybe_owned().as_slice().fmt(f)
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
index 42384892e69..58b3179a297 100644
--- a/src/libstd/rt/backtrace.rs
+++ b/src/libstd/rt/backtrace.rs
@@ -291,7 +291,7 @@ mod imp {
 
         struct Context<'a> {
             idx: int,
-            writer: &'a mut Writer,
+            writer: &'a mut Writer+'a,
             last_error: Option<IoError>,
         }
 
diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs
index 16bcdd9bbb6..16f6eea6144 100644
--- a/src/libsync/comm/mod.rs
+++ b/src/libsync/comm/mod.rs
@@ -386,6 +386,14 @@ pub struct Receiver<T> {
 /// whenever `next` is called, waiting for a new message, and `None` will be
 /// returned when the corresponding channel has hung up.
 #[unstable]
+#[cfg(not(stage0))]
+pub struct Messages<'a, T:'a> {
+    rx: &'a Receiver<T>
+}
+
+/// Stage0 only
+#[cfg(stage0)]
+#[unstable]
 pub struct Messages<'a, T> {
     rx: &'a Receiver<T>
 }
diff --git a/src/libsync/comm/select.rs b/src/libsync/comm/select.rs
index 737a4bfe299..dc9891dd1ee 100644
--- a/src/libsync/comm/select.rs
+++ b/src/libsync/comm/select.rs
@@ -76,6 +76,24 @@ pub struct Select {
 /// A handle to a receiver which is currently a member of a `Select` set of
 /// receivers.  This handle is used to keep the receiver in the set as well as
 /// interact with the underlying receiver.
+#[cfg(not(stage0))]
+pub struct Handle<'rx, T:'rx> {
+    /// The ID of this handle, used to compare against the return value of
+    /// `Select::wait()`
+    id: uint,
+    selector: &'rx Select,
+    next: *mut Handle<'static, ()>,
+    prev: *mut Handle<'static, ()>,
+    added: bool,
+    packet: &'rx Packet+'rx,
+
+    // due to our fun transmutes, we be sure to place this at the end. (nothing
+    // previous relies on T)
+    rx: &'rx Receiver<T>,
+}
+
+/// Stage0 only
+#[cfg(stage0)]
 pub struct Handle<'rx, T> {
     /// The ID of this handle, used to compare against the return value of
     /// `Select::wait()`
@@ -84,7 +102,7 @@ pub struct Handle<'rx, T> {
     next: *mut Handle<'static, ()>,
     prev: *mut Handle<'static, ()>,
     added: bool,
-    packet: &'rx Packet,
+    packet: &'rx Packet+'rx,
 
     // due to our fun transmutes, we be sure to place this at the end. (nothing
     // previous relies on T)
diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs
index bed90743503..c2744751ee5 100644
--- a/src/libsync/lib.rs
+++ b/src/libsync/lib.rs
@@ -29,6 +29,7 @@
 
 #![feature(phase, globs, macro_rules, unsafe_destructor)]
 #![feature(import_shadowing)]
+#![feature(issue_5723_bootstrap)]
 #![deny(missing_doc)]
 #![no_std]
 
diff --git a/src/libsync/lock.rs b/src/libsync/lock.rs
index b07d06ca18e..e1cae6c62d5 100644
--- a/src/libsync/lock.rs
+++ b/src/libsync/lock.rs
@@ -180,6 +180,18 @@ pub struct Mutex<T> {
 
 /// An guard which is created by locking a mutex. Through this guard the
 /// underlying data can be accessed.
+#[cfg(not(stage0))]
+pub struct MutexGuard<'a, T:'a> {
+    // FIXME #12808: strange name to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _data: &'a mut T,
+    /// Inner condition variable connected to the locked mutex that this guard
+    /// was created from. This can be used for atomic-unlock-and-deschedule.
+    pub cond: Condvar<'a>,
+}
+
+/// stage0 only
+#[cfg(stage0)]
 pub struct MutexGuard<'a, T> {
     // FIXME #12808: strange name to try to avoid interfering with
     // field accesses of the contained type via Deref
@@ -280,6 +292,18 @@ pub struct RWLock<T> {
 
 /// A guard which is created by locking an rwlock in write mode. Through this
 /// guard the underlying data can be accessed.
+#[cfg(not(stage0))]
+pub struct RWLockWriteGuard<'a, T:'a> {
+    // FIXME #12808: strange name to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _data: &'a mut T,
+    /// Inner condition variable that can be used to sleep on the write mode of
+    /// this rwlock.
+    pub cond: Condvar<'a>,
+}
+
+/// stage0 only
+#[cfg(stage0)]
 pub struct RWLockWriteGuard<'a, T> {
     // FIXME #12808: strange name to try to avoid interfering with
     // field accesses of the contained type via Deref
@@ -291,6 +315,16 @@ pub struct RWLockWriteGuard<'a, T> {
 
 /// A guard which is created by locking an rwlock in read mode. Through this
 /// guard the underlying data can be accessed.
+#[cfg(not(stage0))]
+pub struct RWLockReadGuard<'a, T:'a> {
+    // FIXME #12808: strange names to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _data: &'a T,
+    _guard: raw::RWLockReadGuard<'a>,
+}
+
+/// Stage0 only
+#[cfg(stage0)]
 pub struct RWLockReadGuard<'a, T> {
     // FIXME #12808: strange names to try to avoid interfering with
     // field accesses of the contained type via Deref
diff --git a/src/libsync/raw.rs b/src/libsync/raw.rs
index c42d567fc18..98934d87474 100644
--- a/src/libsync/raw.rs
+++ b/src/libsync/raw.rs
@@ -103,10 +103,17 @@ struct SemInner<Q> {
 }
 
 #[must_use]
+#[cfg(stage0)]
 struct SemGuard<'a, Q> {
     sem: &'a Sem<Q>,
 }
 
+#[must_use]
+#[cfg(not(stage0))]
+struct SemGuard<'a, Q:'a> {
+    sem: &'a Sem<Q>,
+}
+
 impl<Q: Send> Sem<Q> {
     fn new(count: int, q: Q) -> Sem<Q> {
         assert!(count >= 0,
diff --git a/src/libsync/spsc_queue.rs b/src/libsync/spsc_queue.rs
index 578e518cb8f..32b77be78a4 100644
--- a/src/libsync/spsc_queue.rs
+++ b/src/libsync/spsc_queue.rs
@@ -315,27 +315,6 @@ mod test {
         assert_eq!(consumer.pop(), None);
     }
 
-    // This behaviour is blocked by the type system if using the safe constructor
-    #[test]
-    fn pop_peeked_unchecked() {
-        let q = unsafe { Queue::new(0) };
-        q.push(vec![1i]);
-        q.push(vec![2]);
-        let peeked = q.peek().unwrap();
-
-        assert_eq!(*peeked, vec![1]);
-        assert_eq!(q.pop(), Some(vec![1]));
-
-        assert_eq!(*peeked, vec![1]);
-        q.push(vec![7]);
-
-        // Note: This should actually expect 1, but this test is to highlight
-        // the unsafety allowed by the unchecked usage. A Rust user would not
-        // expect their peeked value to mutate like this without the type system
-        // complaining.
-        assert_eq!(*peeked, vec![7]);
-    }
-
     #[test]
     fn peek() {
         let (mut consumer, mut producer) = queue(0);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 7d5787092a5..d574a02fded 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -224,16 +224,17 @@ pub static DUMMY_NODE_ID: NodeId = -1;
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum TyParamBound {
     TraitTyParamBound(TraitRef),
-    StaticRegionTyParamBound,
     UnboxedFnTyParamBound(UnboxedFnTy),
-    OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands
+    RegionTyParamBound(Lifetime)
 }
 
+pub type TyParamBounds = OwnedSlice<TyParamBound>;
+
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub struct TyParam {
     pub ident: Ident,
     pub id: NodeId,
-    pub bounds: OwnedSlice<TyParamBound>,
+    pub bounds: TyParamBounds,
     pub unbound: Option<TyParamBound>,
     pub default: Option<P<Ty>>,
     pub span: Span
@@ -892,11 +893,7 @@ pub struct ClosureTy {
     pub fn_style: FnStyle,
     pub onceness: Onceness,
     pub decl: P<FnDecl>,
-    /// Optional optvec distinguishes between "fn()" and "fn:()" so we can
-    /// implement issue #7264. None means "fn()", which means infer a default
-    /// bound based on pointer sigil during typeck. Some(Empty) means "fn:()",
-    /// which means use no bounds (e.g., not even Owned on a ~fn()).
-    pub bounds: Option<OwnedSlice<TyParamBound>>,
+    pub bounds: TyParamBounds,
 }
 
 #[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)]
@@ -923,12 +920,12 @@ pub enum Ty_ {
     TyFixedLengthVec(P<Ty>, Gc<Expr>),
     TyPtr(MutTy),
     TyRptr(Option<Lifetime>, MutTy),
-    TyClosure(Gc<ClosureTy>, Option<Lifetime>),
+    TyClosure(Gc<ClosureTy>),
     TyProc(Gc<ClosureTy>),
     TyBareFn(Gc<BareFnTy>),
     TyUnboxedFn(Gc<UnboxedFnTy>),
     TyTup(Vec<P<Ty>> ),
-    TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
+    TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
     /// No-op; kept solely so that we can pretty-print faithfully
     TyParen(P<Ty>),
     TyTypeof(Gc<Expr>),
@@ -1281,7 +1278,7 @@ pub enum Item_ {
     ItemTrait(Generics,
               Option<TyParamBound>, // (optional) default bound not required for Self.
                                     // Currently, only Sized makes sense here.
-              Vec<TraitRef> ,
+              TyParamBounds,
               Vec<TraitItem>),
     ItemImpl(Generics,
              Option<TraitRef>, // (optional) trait this impl implements
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 5fccf6cc3f0..993c5ce676a 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -68,10 +68,15 @@ impl<'a> Iterator<PathElem> for LinkedPath<'a> {
     }
 }
 
-// HACK(eddyb) move this into libstd (value wrapper for slice::Items).
+#[cfg(stage0)]
 #[deriving(Clone)]
 pub struct Values<'a, T>(pub slice::Items<'a, T>);
 
+// HACK(eddyb) move this into libstd (value wrapper for slice::Items).
+#[cfg(not(stage0))]
+#[deriving(Clone)]
+pub struct Values<'a, T:'a>(pub slice::Items<'a, T>);
+
 impl<'a, T: Copy> Iterator<T> for Values<'a, T> {
     fn next(&mut self) -> Option<T> {
         let &Values(ref mut items) = self;
@@ -478,6 +483,7 @@ impl Map {
     }
 }
 
+#[cfg(stage0)]
 pub struct NodesMatchingSuffix<'a, S> {
     map: &'a Map,
     item_name: &'a S,
@@ -485,6 +491,14 @@ pub struct NodesMatchingSuffix<'a, S> {
     idx: NodeId,
 }
 
+#[cfg(not(stage0))]
+pub struct NodesMatchingSuffix<'a, S:'a> {
+    map: &'a Map,
+    item_name: &'a S,
+    in_which: &'a [S],
+    idx: NodeId,
+}
+
 impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
     /// Returns true only if some suffix of the module path for parent
     /// matches `self.in_which`.
@@ -676,11 +690,7 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
                     None => {}
                 }
             }
-            ItemTrait(_, _, ref traits, ref methods) => {
-                for t in traits.iter() {
-                    self.insert(t.ref_id, EntryItem(self.parent, i));
-                }
-
+            ItemTrait(_, _, _, ref methods) => {
                 for tm in methods.iter() {
                     match *tm {
                         RequiredMethod(ref m) => {
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 1a4b41404be..cc586a3affa 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -349,12 +349,20 @@ pub trait IdVisitingOperation {
 /// A visitor that applies its operation to all of the node IDs
 /// in a visitable thing.
 
+#[cfg(stage0)]
 pub struct IdVisitor<'a, O> {
     pub operation: &'a O,
     pub pass_through_items: bool,
     pub visited_outermost: bool,
 }
 
+#[cfg(not(stage0))]
+pub struct IdVisitor<'a, O:'a> {
+    pub operation: &'a O,
+    pub pass_through_items: bool,
+    pub visited_outermost: bool,
+}
+
 impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
     fn visit_generics_helper(&self, generics: &Generics) {
         for type_parameter in generics.ty_params.iter() {
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index 209296989fa..25a6a4c01bd 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -45,8 +45,10 @@ fn with_used_diagnostics<T>(f: |&mut HashMap<Name, Span>| -> T) -> T {
     }
 }
 
-pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span,
-                              token_tree: &[TokenTree]) -> Box<MacResult> {
+pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
+                                   span: Span,
+                                   token_tree: &[TokenTree])
+                                   -> Box<MacResult+'cx> {
     let code = match token_tree {
         [ast::TTTok(_, token::IDENT(code, _))] => code,
         _ => unreachable!()
@@ -75,8 +77,10 @@ pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span,
     MacExpr::new(quote_expr!(ecx, ()))
 }
 
-pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span,
-                                  token_tree: &[TokenTree]) -> Box<MacResult> {
+pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
+                                       span: Span,
+                                       token_tree: &[TokenTree])
+                                       -> Box<MacResult+'cx> {
     let (code, description) = match token_tree {
         [ast::TTTok(_, token::IDENT(ref code, _))] => {
             (code, None)
@@ -101,8 +105,10 @@ pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span,
     MacItem::new(quote_item!(ecx, mod $sym {}).unwrap())
 }
 
-pub fn expand_build_diagnostic_array(ecx: &mut ExtCtxt, span: Span,
-                                     token_tree: &[TokenTree]) -> Box<MacResult> {
+pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
+                                          span: Span,
+                                          token_tree: &[TokenTree])
+                                          -> Box<MacResult+'cx> {
     let name = match token_tree {
         [ast::TTTok(_, token::IDENT(ref name, _))] => name,
         _ => unreachable!()
diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs
index 180f2409b8a..8028d51a7b5 100644
--- a/src/libsyntax/ext/asm.rs
+++ b/src/libsyntax/ext/asm.rs
@@ -45,8 +45,8 @@ impl State {
 
 static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
 
-pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                  -> Box<base::MacResult> {
+pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                       -> Box<base::MacResult+'cx> {
     let mut p = cx.new_parser_from_tts(tts);
     let mut asm = InternedString::new("");
     let mut asm_str_style = None;
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 01d3920a254..b3b66a6a604 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -52,23 +52,23 @@ pub struct BasicMacroExpander {
 
 /// Represents a thing that maps token trees to Macro Results
 pub trait TTMacroExpander {
-    fn expand(&self,
-              ecx: &mut ExtCtxt,
-              span: Span,
-              token_tree: &[ast::TokenTree])
-              -> Box<MacResult>;
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   span: Span,
+                   token_tree: &[ast::TokenTree])
+                   -> Box<MacResult+'cx>;
 }
 
 pub type MacroExpanderFn =
-    fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
-       -> Box<MacResult>;
+    fn<'cx>(ecx: &'cx mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
+            -> Box<MacResult+'cx>;
 
 impl TTMacroExpander for BasicMacroExpander {
-    fn expand(&self,
-              ecx: &mut ExtCtxt,
-              span: Span,
-              token_tree: &[ast::TokenTree])
-              -> Box<MacResult> {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   span: Span,
+                   token_tree: &[ast::TokenTree])
+                   -> Box<MacResult+'cx> {
         (self.expander)(ecx, span, token_tree)
     }
 }
@@ -79,27 +79,27 @@ pub struct BasicIdentMacroExpander {
 }
 
 pub trait IdentMacroExpander {
-    fn expand(&self,
-              cx: &mut ExtCtxt,
-              sp: Span,
-              ident: ast::Ident,
-              token_tree: Vec<ast::TokenTree> )
-              -> Box<MacResult>;
+    fn expand<'cx>(&self,
+                   cx: &'cx mut ExtCtxt,
+                   sp: Span,
+                   ident: ast::Ident,
+                   token_tree: Vec<ast::TokenTree> )
+                   -> Box<MacResult+'cx>;
 }
 
 impl IdentMacroExpander for BasicIdentMacroExpander {
-    fn expand(&self,
-              cx: &mut ExtCtxt,
-              sp: Span,
-              ident: ast::Ident,
-              token_tree: Vec<ast::TokenTree> )
-              -> Box<MacResult> {
+    fn expand<'cx>(&self,
+                   cx: &'cx mut ExtCtxt,
+                   sp: Span,
+                   ident: ast::Ident,
+                   token_tree: Vec<ast::TokenTree> )
+                   -> Box<MacResult+'cx> {
         (self.expander)(cx, sp, ident, token_tree)
     }
 }
 
 pub type IdentMacroExpanderFn =
-    fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree>) -> Box<MacResult>;
+    fn<'cx>(&'cx mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree>) -> Box<MacResult+'cx>;
 
 /// The result of a macro expansion. The return values of the various
 /// methods are spliced into the AST at the callsite of the macro (or
@@ -146,8 +146,8 @@ pub struct MacExpr {
     e: Gc<ast::Expr>,
 }
 impl MacExpr {
-    pub fn new(e: Gc<ast::Expr>) -> Box<MacResult> {
-        box MacExpr { e: e } as Box<MacResult>
+    pub fn new(e: Gc<ast::Expr>) -> Box<MacResult+'static> {
+        box MacExpr { e: e } as Box<MacResult+'static>
     }
 }
 impl MacResult for MacExpr {
@@ -160,8 +160,8 @@ pub struct MacPat {
     p: Gc<ast::Pat>,
 }
 impl MacPat {
-    pub fn new(p: Gc<ast::Pat>) -> Box<MacResult> {
-        box MacPat { p: p } as Box<MacResult>
+    pub fn new(p: Gc<ast::Pat>) -> Box<MacResult+'static> {
+        box MacPat { p: p } as Box<MacResult+'static>
     }
 }
 impl MacResult for MacPat {
@@ -174,8 +174,8 @@ pub struct MacItem {
     i: Gc<ast::Item>
 }
 impl MacItem {
-    pub fn new(i: Gc<ast::Item>) -> Box<MacResult> {
-        box MacItem { i: i } as Box<MacResult>
+    pub fn new(i: Gc<ast::Item>) -> Box<MacResult+'static> {
+        box MacItem { i: i } as Box<MacResult+'static>
     }
 }
 impl MacResult for MacItem {
@@ -203,8 +203,8 @@ impl DummyResult {
     ///
     /// Use this as a return value after hitting any errors and
     /// calling `span_err`.
-    pub fn any(sp: Span) -> Box<MacResult> {
-        box DummyResult { expr_only: false, span: sp } as Box<MacResult>
+    pub fn any(sp: Span) -> Box<MacResult+'static> {
+        box DummyResult { expr_only: false, span: sp } as Box<MacResult+'static>
     }
 
     /// Create a default MacResult that can only be an expression.
@@ -212,8 +212,8 @@ impl DummyResult {
     /// Use this for macros that must expand to an expression, so even
     /// if an error is encountered internally, the user will receive
     /// an error that they also used it in the wrong place.
-    pub fn expr(sp: Span) -> Box<MacResult> {
-        box DummyResult { expr_only: true, span: sp } as Box<MacResult>
+    pub fn expr(sp: Span) -> Box<MacResult+'static> {
+        box DummyResult { expr_only: true, span: sp } as Box<MacResult+'static>
     }
 
     /// A plain dummy expression.
diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs
index 6ea55096348..18367511495 100644
--- a/src/libsyntax/ext/bytes.rs
+++ b/src/libsyntax/ext/bytes.rs
@@ -17,8 +17,10 @@ use ext::base;
 use ext::build::AstBuilder;
 
 
-pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt,
+                              sp: Span,
+                              tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
     cx.span_warn(sp, "`bytes!` is deprecated, use `b\"foo\"` literals instead");
     cx.parse_sess.span_diagnostic.span_note(sp,
         "see http://doc.rust-lang.org/rust.html#byte-and-byte-string-literals \
diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs
index c2930662bc4..0c3a951c982 100644
--- a/src/libsyntax/ext/cfg.rs
+++ b/src/libsyntax/ext/cfg.rs
@@ -26,8 +26,10 @@ use parse::token::InternedString;
 use parse::token;
 
 
-pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                  -> Box<base::MacResult> {
+pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
+                       sp: Span,
+                       tts: &[ast::TokenTree])
+                       -> Box<base::MacResult+'static> {
     let mut p = cx.new_parser_from_tts(tts);
     let mut cfgs = Vec::new();
     // parse `cfg!(meta_item, meta_item(x,y), meta_item="foo", ...)`
diff --git a/src/libsyntax/ext/concat.rs b/src/libsyntax/ext/concat.rs
index dd1153bf666..ea7a4d061c0 100644
--- a/src/libsyntax/ext/concat.rs
+++ b/src/libsyntax/ext/concat.rs
@@ -19,7 +19,7 @@ use std::string::String;
 pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
                          sp: codemap::Span,
                          tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+                         -> Box<base::MacResult+'static> {
     let es = match base::get_exprs_from_tts(cx, sp, tts) {
         Some(e) => e,
         None => return base::DummyResult::expr(sp)
diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs
index 7cf901bbd5e..0ac26a3a904 100644
--- a/src/libsyntax/ext/concat_idents.rs
+++ b/src/libsyntax/ext/concat_idents.rs
@@ -18,8 +18,8 @@ use parse::token::{str_to_ident};
 
 use std::gc::GC;
 
-pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
     let mut res_str = String::new();
     for (i, e) in tts.iter().enumerate() {
         if i & 1 == 1 {
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index 4b185419b40..50bdc296aad 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -407,9 +407,15 @@ impl<'a> TraitDef<'a> {
                     cx.typarambound(p.to_path(cx, self.span,
                                                   type_ident, generics))
                 }).collect();
+
             // require the current trait
             bounds.push(cx.typarambound(trait_path.clone()));
 
+            // also add in any bounds from the declaration
+            for declared_bound in ty_param.bounds.iter() {
+                bounds.push((*declared_bound).clone());
+            }
+
             cx.typaram(self.span,
                        ty_param.ident,
                        OwnedSlice::from_vec(bounds),
diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs
index b24cfb85794..aae92ae85fc 100644
--- a/src/libsyntax/ext/env.rs
+++ b/src/libsyntax/ext/env.rs
@@ -23,8 +23,8 @@ use parse::token;
 
 use std::os;
 
-pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
     let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
         None => return DummyResult::expr(sp),
         Some(v) => v
@@ -59,8 +59,8 @@ pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
     MacExpr::new(e)
 }
 
-pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                  -> Box<base::MacResult> {
+pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                       -> Box<base::MacResult+'cx> {
     let exprs = match get_exprs_from_tts(cx, sp, tts) {
         Some(ref exprs) if exprs.len() == 0 => {
             cx.span_err(sp, "env! takes 1 or 2 arguments");
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d918b28d4dc..9dbea1c9ac2 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -31,6 +31,10 @@ use util::small_vector::SmallVector;
 
 use std::gc::{Gc, GC};
 
+enum Either<L,R> {
+    Left(L),
+    Right(R)
+}
 
 fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
     match e.node {
@@ -102,7 +106,8 @@ fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
                        parse_thunk: |Box<MacResult>|->Option<T>,
                        mark_thunk: |T,Mrk|->T,
                        fld: &mut MacroExpander)
-    -> Option<T> {
+                       -> Option<T>
+{
     match (*mac).node {
         // it would almost certainly be cleaner to pass the whole
         // macro invocation in, rather than pulling it apart and
@@ -149,10 +154,13 @@ fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
                         // the macro.
                         let mac_span = original_span(fld.cx);
 
-                        let expanded = expandfun.expand(fld.cx,
-                                                        mac_span.call_site,
-                                                        marked_before.as_slice());
-                        let parsed = match parse_thunk(expanded) {
+                        let opt_parsed = {
+                            let expanded = expandfun.expand(fld.cx,
+                                                            mac_span.call_site,
+                                                            marked_before.as_slice());
+                            parse_thunk(expanded)
+                        };
+                        let parsed = match opt_parsed {
                             Some(e) => e,
                             None => {
                                 fld.cx.span_err(
@@ -358,7 +366,8 @@ fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
 // Support for item-position macro invocations, exactly the same
 // logic as for expression-position macro invocations.
 fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
-                       -> SmallVector<Gc<ast::Item>> {
+                   -> SmallVector<Gc<ast::Item>>
+{
     let (pth, tts) = match it.node {
         ItemMac(codemap::Spanned {
             node: MacInvocTT(ref pth, ref tts, _),
@@ -372,86 +381,93 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
     let extname = pth.segments.get(0).identifier;
     let extnamestr = token::get_ident(extname);
     let fm = fresh_mark();
-    let expanded = match fld.cx.syntax_env.find(&extname.name) {
-        None => {
-            fld.cx.span_err(pth.span,
-                            format!("macro undefined: '{}!'",
-                                    extnamestr).as_slice());
-            // let compilation continue
-            return SmallVector::zero();
-        }
+    let def_or_items = {
+        let expanded = match fld.cx.syntax_env.find(&extname.name) {
+            None => {
+                fld.cx.span_err(pth.span,
+                                format!("macro undefined: '{}!'",
+                                        extnamestr).as_slice());
+                // let compilation continue
+                return SmallVector::zero();
+            }
 
-        Some(rc) => match *rc {
-            NormalTT(ref expander, span) => {
-                if it.ident.name != parse::token::special_idents::invalid.name {
-                    fld.cx
-                    .span_err(pth.span,
-                                format!("macro {}! expects no ident argument, \
+            Some(rc) => match *rc {
+                NormalTT(ref expander, span) => {
+                    if it.ident.name != parse::token::special_idents::invalid.name {
+                        fld.cx
+                            .span_err(pth.span,
+                                      format!("macro {}! expects no ident argument, \
                                         given '{}'",
-                                        extnamestr,
-                                        token::get_ident(it.ident)).as_slice());
-                    return SmallVector::zero();
+                                      extnamestr,
+                                      token::get_ident(it.ident)).as_slice());
+                        return SmallVector::zero();
+                    }
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: it.span,
+                        callee: NameAndSpan {
+                            name: extnamestr.get().to_string(),
+                            format: MacroBang,
+                            span: span
+                        }
+                    });
+                    // mark before expansion:
+                    let marked_before = mark_tts(tts.as_slice(), fm);
+                    expander.expand(fld.cx, it.span, marked_before.as_slice())
                 }
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: it.span,
-                    callee: NameAndSpan {
-                        name: extnamestr.get().to_string(),
-                        format: MacroBang,
-                        span: span
+                IdentTT(ref expander, span) => {
+                    if it.ident.name == parse::token::special_idents::invalid.name {
+                        fld.cx.span_err(pth.span,
+                                        format!("macro {}! expects an ident argument",
+                                                extnamestr.get()).as_slice());
+                        return SmallVector::zero();
                     }
-                });
-                // mark before expansion:
-                let marked_before = mark_tts(tts.as_slice(), fm);
-                expander.expand(fld.cx, it.span, marked_before.as_slice())
-            }
-            IdentTT(ref expander, span) => {
-                if it.ident.name == parse::token::special_idents::invalid.name {
-                    fld.cx.span_err(pth.span,
-                                    format!("macro {}! expects an ident argument",
-                                            extnamestr.get()).as_slice());
-                    return SmallVector::zero();
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: it.span,
+                        callee: NameAndSpan {
+                            name: extnamestr.get().to_string(),
+                            format: MacroBang,
+                            span: span
+                        }
+                    });
+                    // mark before expansion:
+                    let marked_tts = mark_tts(tts.as_slice(), fm);
+                    expander.expand(fld.cx, it.span, it.ident, marked_tts)
                 }
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: it.span,
-                    callee: NameAndSpan {
-                        name: extnamestr.get().to_string(),
-                        format: MacroBang,
-                        span: span
+                LetSyntaxTT(ref expander, span) => {
+                    if it.ident.name == parse::token::special_idents::invalid.name {
+                        fld.cx.span_err(pth.span,
+                                        format!("macro {}! expects an ident argument",
+                                                extnamestr.get()).as_slice());
+                        return SmallVector::zero();
                     }
-                });
-                // mark before expansion:
-                let marked_tts = mark_tts(tts.as_slice(), fm);
-                expander.expand(fld.cx, it.span, it.ident, marked_tts)
-            }
-            LetSyntaxTT(ref expander, span) => {
-                if it.ident.name == parse::token::special_idents::invalid.name {
-                    fld.cx.span_err(pth.span,
-                                    format!("macro {}! expects an ident argument",
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: it.span,
+                        callee: NameAndSpan {
+                            name: extnamestr.get().to_string(),
+                            format: MacroBang,
+                            span: span
+                        }
+                    });
+                    // DON'T mark before expansion:
+                    expander.expand(fld.cx, it.span, it.ident, tts)
+                }
+                _ => {
+                    fld.cx.span_err(it.span,
+                                    format!("{}! is not legal in item position",
                                             extnamestr.get()).as_slice());
                     return SmallVector::zero();
                 }
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: it.span,
-                    callee: NameAndSpan {
-                        name: extnamestr.get().to_string(),
-                        format: MacroBang,
-                        span: span
-                    }
-                });
-                // DON'T mark before expansion:
-                expander.expand(fld.cx, it.span, it.ident, tts)
-            }
-            _ => {
-                fld.cx.span_err(it.span,
-                                format!("{}! is not legal in item position",
-                                        extnamestr.get()).as_slice());
-                return SmallVector::zero();
             }
+        };
+
+        match expanded.make_def() {
+            Some(def) => Left(def),
+            None => Right(expanded.make_items())
         }
     };
 
-    let items = match expanded.make_def() {
-        Some(MacroDef { name, ext }) => {
+    let items = match def_or_items {
+        Left(MacroDef { name, ext }) => {
             // hidden invariant: this should only be possible as the
             // result of expanding a LetSyntaxTT, and thus doesn't
             // need to be marked. Not that it could be marked anyway.
@@ -462,23 +478,20 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
             }
             SmallVector::zero()
         }
-        None => {
-            match expanded.make_items() {
-                Some(items) => {
-                    items.move_iter()
-                        .map(|i| mark_item(i, fm))
-                        .flat_map(|i| fld.fold_item(i).move_iter())
-                        .collect()
-                }
-                None => {
-                    fld.cx.span_err(pth.span,
-                                    format!("non-item macro in item position: {}",
-                                            extnamestr.get()).as_slice());
-                    return SmallVector::zero();
-                }
-            }
+        Right(Some(items)) => {
+            items.move_iter()
+                .map(|i| mark_item(i, fm))
+                .flat_map(|i| fld.fold_item(i).move_iter())
+                .collect()
+        }
+        Right(None) => {
+            fld.cx.span_err(pth.span,
+                            format!("non-item macro in item position: {}",
+                                    extnamestr.get()).as_slice());
+            return SmallVector::zero();
         }
     };
+
     fld.cx.bt_pop();
     return items;
 }
@@ -901,7 +914,7 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: &ast::FnDecl, block: Gc<ast::Blo
 }
 
 /// A tree-folder that performs macro expansion
-pub struct MacroExpander<'a, 'b> {
+pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
 }
 
diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs
index 4185458bfbe..5352cfaf749 100644
--- a/src/libsyntax/ext/fmt.rs
+++ b/src/libsyntax/ext/fmt.rs
@@ -19,7 +19,7 @@ use ext::build::AstBuilder;
 pub fn expand_syntax_ext(ecx: &mut base::ExtCtxt,
                          sp: Span,
                          _tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+                         -> Box<base::MacResult+'static> {
     ecx.span_err(sp, "`fmt!` is deprecated, use `format!` instead");
     ecx.parse_sess.span_diagnostic.span_note(sp,
         "see http://doc.rust-lang.org/std/fmt/ \
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index 124e9e95942..0994abaadc7 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -33,7 +33,7 @@ enum Position {
     Named(String),
 }
 
-struct Context<'a, 'b> {
+struct Context<'a, 'b:'a> {
     ecx: &'a mut ExtCtxt<'b>,
     fmtsp: Span,
 
@@ -668,8 +668,9 @@ impl<'a, 'b> Context<'a, 'b> {
     }
 }
 
-pub fn expand_format_args(ecx: &mut ExtCtxt, sp: Span,
-                          tts: &[ast::TokenTree]) -> Box<base::MacResult> {
+pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span,
+                               tts: &[ast::TokenTree])
+                               -> Box<base::MacResult+'cx> {
 
     match parse_args(ecx, sp, false, tts) {
         (invocation, Some((efmt, args, order, names))) => {
@@ -680,8 +681,8 @@ pub fn expand_format_args(ecx: &mut ExtCtxt, sp: Span,
     }
 }
 
-pub fn expand_format_args_method(ecx: &mut ExtCtxt, sp: Span,
-                                 tts: &[ast::TokenTree]) -> Box<base::MacResult> {
+pub fn expand_format_args_method<'cx>(ecx: &'cx mut ExtCtxt, sp: Span,
+                                      tts: &[ast::TokenTree]) -> Box<base::MacResult+'cx> {
 
     match parse_args(ecx, sp, true, tts) {
         (invocation, Some((efmt, args, order, names))) => {
diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs
index 1f4d087abd0..8df5746e412 100644
--- a/src/libsyntax/ext/log_syntax.rs
+++ b/src/libsyntax/ext/log_syntax.rs
@@ -15,10 +15,10 @@ use print;
 
 use std::rc::Rc;
 
-pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
-                         sp: codemap::Span,
-                         tt: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
+                              sp: codemap::Span,
+                              tt: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
 
     cx.print_backtrace();
     println!("{}", print::pprust::tt_to_string(&ast::TTDelim(
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index d7d6c20b475..0c41db7ecd6 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -410,35 +410,36 @@ pub mod rt {
 
 }
 
-pub fn expand_quote_tokens(cx: &mut ExtCtxt,
-                           sp: Span,
-                           tts: &[ast::TokenTree])
-                           -> Box<base::MacResult> {
+pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
+                                sp: Span,
+                                tts: &[ast::TokenTree])
+                                -> Box<base::MacResult+'cx> {
     let (cx_expr, expr) = expand_tts(cx, sp, tts);
     let expanded = expand_wrapper(cx, sp, cx_expr, expr);
     base::MacExpr::new(expanded)
 }
 
-pub fn expand_quote_expr(cx: &mut ExtCtxt,
-                         sp: Span,
-                         tts: &[ast::TokenTree]) -> Box<base::MacResult> {
+pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
+                              sp: Span,
+                              tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
     let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts);
     base::MacExpr::new(expanded)
 }
 
-pub fn expand_quote_item(cx: &mut ExtCtxt,
-                         sp: Span,
-                         tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt,
+                              sp: Span,
+                              tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
     let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes",
                                     vec!(), tts);
     base::MacExpr::new(expanded)
 }
 
-pub fn expand_quote_pat(cx: &mut ExtCtxt,
-                        sp: Span,
-                        tts: &[ast::TokenTree])
-                        -> Box<base::MacResult> {
+pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
+                             sp: Span,
+                             tts: &[ast::TokenTree])
+                             -> Box<base::MacResult+'cx> {
     let expanded = expand_parse_call(cx, sp, "parse_pat", vec!(), tts);
     base::MacExpr::new(expanded)
 }
@@ -446,7 +447,7 @@ pub fn expand_quote_pat(cx: &mut ExtCtxt,
 pub fn expand_quote_arm(cx: &mut ExtCtxt,
                         sp: Span,
                         tts: &[ast::TokenTree])
-                        -> Box<base::MacResult> {
+                        -> Box<base::MacResult+'static> {
     let expanded = expand_parse_call(cx, sp, "parse_arm", vec!(), tts);
     base::MacExpr::new(expanded)
 }
@@ -454,7 +455,7 @@ pub fn expand_quote_arm(cx: &mut ExtCtxt,
 pub fn expand_quote_ty(cx: &mut ExtCtxt,
                        sp: Span,
                        tts: &[ast::TokenTree])
-                       -> Box<base::MacResult> {
+                       -> Box<base::MacResult+'static> {
     let e_param_colons = cx.expr_lit(sp, ast::LitBool(false));
     let expanded = expand_parse_call(cx, sp, "parse_ty",
                                      vec!(e_param_colons), tts);
@@ -464,7 +465,7 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt,
 pub fn expand_quote_method(cx: &mut ExtCtxt,
                            sp: Span,
                            tts: &[ast::TokenTree])
-                           -> Box<base::MacResult> {
+                           -> Box<base::MacResult+'static> {
     let e_param_colons = cx.expr_none(sp);
     let expanded = expand_parse_call(cx, sp, "parse_method",
                                      vec!(e_param_colons), tts);
@@ -474,7 +475,7 @@ pub fn expand_quote_method(cx: &mut ExtCtxt,
 pub fn expand_quote_stmt(cx: &mut ExtCtxt,
                          sp: Span,
                          tts: &[ast::TokenTree])
-                         -> Box<base::MacResult> {
+                         -> Box<base::MacResult+'static> {
     let e_attrs = cx.expr_vec_ng(sp);
     let expanded = expand_parse_call(cx, sp, "parse_stmt",
                                     vec!(e_attrs), tts);
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 703adcbd335..5cc0ec4a122 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -29,7 +29,7 @@ use std::rc::Rc;
 
 /// line!(): expands to the current line number
 pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                   -> Box<base::MacResult> {
+                   -> Box<base::MacResult+'static> {
     base::check_zero_tts(cx, sp, tts, "line!");
 
     let topmost = topmost_expn_info(cx.backtrace().unwrap());
@@ -40,7 +40,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 
 /* col!(): expands to the current column number */
 pub fn expand_col(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                  -> Box<base::MacResult> {
+                  -> Box<base::MacResult+'static> {
     base::check_zero_tts(cx, sp, tts, "col!");
 
     let topmost = topmost_expn_info(cx.backtrace().unwrap());
@@ -52,7 +52,7 @@ pub fn expand_col(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 /// The filemap (`loc.file`) contains a bunch more information we could spit
 /// out if we wanted.
 pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                   -> Box<base::MacResult> {
+                   -> Box<base::MacResult+'static> {
     base::check_zero_tts(cx, sp, tts, "file!");
 
     let topmost = topmost_expn_info(cx.backtrace().unwrap());
@@ -62,14 +62,14 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 }
 
 pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                        -> Box<base::MacResult> {
+                        -> Box<base::MacResult+'static> {
     let s = pprust::tts_to_string(tts);
     base::MacExpr::new(cx.expr_str(sp,
                                    token::intern_and_get_ident(s.as_slice())))
 }
 
 pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                  -> Box<base::MacResult> {
+                  -> Box<base::MacResult+'static> {
     base::check_zero_tts(cx, sp, tts, "module_path!");
     let string = cx.mod_path()
                    .iter()
@@ -85,7 +85,7 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 /// This is generally a bad idea because it's going to behave
 /// unhygienically.
 pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                      -> Box<base::MacResult> {
+                      -> Box<base::MacResult+'static> {
     let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
         Some(f) => f,
         None => return DummyResult::expr(sp),
@@ -105,7 +105,7 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 
 // include_str! : read the given file, insert it as a literal string expr
 pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                          -> Box<base::MacResult> {
+                          -> Box<base::MacResult+'static> {
     let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
         Some(f) => f,
         None => return DummyResult::expr(sp)
@@ -141,7 +141,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 }
 
 pub fn expand_include_bin(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                          -> Box<base::MacResult> {
+                          -> Box<base::MacResult+'static> {
     let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") {
         Some(f) => f,
         None => return DummyResult::expr(sp)
diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs
index 77324632664..1f50eb933bb 100644
--- a/src/libsyntax/ext/trace_macros.rs
+++ b/src/libsyntax/ext/trace_macros.rs
@@ -18,7 +18,7 @@ use parse::token::{keywords, is_keyword};
 pub fn expand_trace_macros(cx: &mut ExtCtxt,
                            sp: Span,
                            tt: &[ast::TokenTree])
-                           -> Box<base::MacResult> {
+                           -> Box<base::MacResult+'static> {
     match tt {
         [ast::TTTok(_, ref tok)] if is_keyword(keywords::True, tok) => {
             cx.set_trace_macros(true);
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 1eb37abb781..d8f0eb32ad7 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -14,7 +14,6 @@ use ast;
 use codemap::{Span, Spanned, DUMMY_SP};
 use ext::base::{ExtCtxt, MacResult, MacroDef};
 use ext::base::{NormalTT, TTMacroExpander};
-use ext::base;
 use ext::tt::macro_parser::{Success, Error, Failure};
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
 use ext::tt::macro_parser::{parse, parse_or_else};
@@ -113,11 +112,11 @@ struct MacroRulesMacroExpander {
 }
 
 impl TTMacroExpander for MacroRulesMacroExpander {
-    fn expand(&self,
-              cx: &mut ExtCtxt,
-              sp: Span,
-              arg: &[ast::TokenTree])
-              -> Box<MacResult> {
+    fn expand<'cx>(&self,
+                   cx: &'cx mut ExtCtxt,
+                   sp: Span,
+                   arg: &[ast::TokenTree])
+                   -> Box<MacResult+'cx> {
         generic_extension(cx,
                           sp,
                           self.name,
@@ -137,13 +136,13 @@ impl MacResult for MacroRulesDefiner {
 }
 
 /// Given `lhses` and `rhses`, this is the new macro we create
-fn generic_extension(cx: &ExtCtxt,
-                     sp: Span,
-                     name: Ident,
-                     arg: &[ast::TokenTree],
-                     lhses: &[Rc<NamedMatch>],
-                     rhses: &[Rc<NamedMatch>])
-                     -> Box<MacResult> {
+fn generic_extension<'cx>(cx: &'cx ExtCtxt,
+                          sp: Span,
+                          name: Ident,
+                          arg: &[ast::TokenTree],
+                          lhses: &[Rc<NamedMatch>],
+                          rhses: &[Rc<NamedMatch>])
+                          -> Box<MacResult+'cx> {
     if cx.trace_macros() {
         println!("{}! {} {} {}",
                  token::get_ident(name),
@@ -195,7 +194,7 @@ fn generic_extension(cx: &ExtCtxt,
                 // Weird, but useful for X-macros.
                 return box ParserAnyMacro {
                     parser: RefCell::new(p),
-                } as Box<MacResult>
+                } as Box<MacResult+'cx>
               }
               Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
                 best_fail_spot = sp;
@@ -213,11 +212,11 @@ fn generic_extension(cx: &ExtCtxt,
 /// This procedure performs the expansion of the
 /// macro_rules! macro. It parses the RHS and adds
 /// an extension to the current context.
-pub fn add_new_extension(cx: &mut ExtCtxt,
-                         sp: Span,
-                         name: Ident,
-                         arg: Vec<ast::TokenTree> )
-                         -> Box<base::MacResult> {
+pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
+                              sp: Span,
+                              name: Ident,
+                              arg: Vec<ast::TokenTree> )
+                              -> Box<MacResult+'cx> {
     // these spans won't matter, anyways
     fn ms(m: Matcher_) -> Matcher {
         Spanned {
@@ -274,5 +273,5 @@ pub fn add_new_extension(cx: &mut ExtCtxt,
             name: token::get_ident(name).to_string(),
             ext: NormalTT(exp, Some(sp))
         }))
-    } as Box<MacResult>
+    } as Box<MacResult+'cx>
 }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4a0787aeb9e..be1c0d96711 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -227,15 +227,20 @@ pub trait Folder {
         noop_fold_variant_arg(va, self)
     }
 
-    fn fold_ty_param_bound(&mut self, tpb: &TyParamBound) -> TyParamBound {
-        noop_fold_ty_param_bound(tpb, self)
-    }
-
     fn fold_opt_bounds(&mut self, b: &Option<OwnedSlice<TyParamBound>>)
                        -> Option<OwnedSlice<TyParamBound>> {
         noop_fold_opt_bounds(b, self)
     }
 
+    fn fold_bounds(&mut self, b: &OwnedSlice<TyParamBound>)
+                       -> OwnedSlice<TyParamBound> {
+        noop_fold_bounds(b, self)
+    }
+
+    fn fold_ty_param_bound(&mut self, tpb: &TyParamBound) -> TyParamBound {
+        noop_fold_ty_param_bound(tpb, self)
+    }
+
     fn fold_mt(&mut self, mt: &MutTy) -> MutTy {
         noop_fold_mt(mt, self)
     }
@@ -349,20 +354,20 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
         TyRptr(ref region, ref mt) => {
             TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
         }
-        TyClosure(ref f, ref region) => {
+        TyClosure(ref f) => {
             TyClosure(box(GC) ClosureTy {
                 fn_style: f.fn_style,
                 onceness: f.onceness,
-                bounds: fld.fold_opt_bounds(&f.bounds),
+                bounds: fld.fold_bounds(&f.bounds),
                 decl: fld.fold_fn_decl(&*f.decl),
                 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
-            }, fld.fold_opt_lifetime(region))
+            })
         }
         TyProc(ref f) => {
             TyProc(box(GC) ClosureTy {
                 fn_style: f.fn_style,
                 onceness: f.onceness,
-                bounds: fld.fold_opt_bounds(&f.bounds),
+                bounds: fld.fold_bounds(&f.bounds),
                 decl: fld.fold_fn_decl(&*f.decl),
                 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
             })
@@ -648,14 +653,13 @@ pub fn noop_fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
                                            -> TyParamBound {
     match *tpb {
         TraitTyParamBound(ref ty) => TraitTyParamBound(fld.fold_trait_ref(ty)),
-        StaticRegionTyParamBound => StaticRegionTyParamBound,
+        RegionTyParamBound(ref lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
         UnboxedFnTyParamBound(ref unboxed_function_type) => {
             UnboxedFnTyParamBound(UnboxedFnTy {
                 decl: fld.fold_fn_decl(&*unboxed_function_type.decl),
                 kind: unboxed_function_type.kind,
             })
         }
-        OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
     }
 }
 
@@ -664,7 +668,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
     TyParam {
         ident: tp.ident,
         id: id,
-        bounds: tp.bounds.map(|x| fld.fold_ty_param_bound(x)),
+        bounds: fld.fold_bounds(&tp.bounds),
         unbound: tp.unbound.as_ref().map(|x| fld.fold_ty_param_bound(x)),
         default: tp.default.map(|x| fld.fold_ty(x)),
         span: tp.span
@@ -792,11 +796,12 @@ pub fn noop_fold_mt<T: Folder>(mt: &MutTy, folder: &mut T) -> MutTy {
 
 pub fn noop_fold_opt_bounds<T: Folder>(b: &Option<OwnedSlice<TyParamBound>>, folder: &mut T)
                               -> Option<OwnedSlice<TyParamBound>> {
-    b.as_ref().map(|bounds| {
-        bounds.map(|bound| {
-            folder.fold_ty_param_bound(bound)
-        })
-    })
+    b.as_ref().map(|bounds| folder.fold_bounds(bounds))
+}
+
+fn noop_fold_bounds<T: Folder>(bounds: &TyParamBounds, folder: &mut T)
+                          -> TyParamBounds {
+    bounds.map(|bound| folder.fold_ty_param_bound(bound))
 }
 
 pub fn noop_fold_variant_arg<T: Folder>(va: &VariantArg, folder: &mut T) -> VariantArg {
@@ -889,7 +894,8 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
                                }).collect()
             )
         }
-        ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
+        ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
+            let bounds = folder.fold_bounds(bounds);
             let methods = methods.iter().flat_map(|method| {
                 let r = match *method {
                     RequiredMethod(ref m) => {
@@ -911,7 +917,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
             }).collect();
             ItemTrait(folder.fold_generics(generics),
                       unbound.clone(),
-                      traits.iter().map(|p| folder.fold_trait_ref(p)).collect(),
+                      bounds,
                       methods)
         }
         ItemMac(ref m) => ItemMac(folder.fold_mac(m)),
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 291c876082f..9bbd6b2a36e 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -25,6 +25,7 @@
 
 #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
 #![feature(quote, struct_variant, unsafe_destructor, import_shadowing)]
+#![feature(issue_5723_bootstrap)]
 #![allow(deprecated)]
 
 // NOTE(stage0, pcwalton): Remove after snapshot.
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 816700681cf..37bda15ac2c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -12,7 +12,7 @@
 
 use abi;
 use ast::{BareFnTy, ClosureTy};
-use ast::{StaticRegionTyParamBound, OtherRegionTyParamBound, TraitTyParamBound};
+use ast::{RegionTyParamBound, TraitTyParamBound};
 use ast::{ProvidedMethod, Public, FnStyle};
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
@@ -70,7 +70,7 @@ use parse;
 use parse::attr::ParserAttr;
 use parse::classify;
 use parse::common::{SeqSep, seq_sep_none};
-use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed};
+use parse::common::{seq_sep_trailing_allowed};
 use parse::lexer::Reader;
 use parse::lexer::TokenAndSpan;
 use parse::obsolete::*;
@@ -120,7 +120,7 @@ pub enum PathParsingMode {
 /// A path paired with optional type bounds.
 pub struct PathAndBounds {
     pub path: ast::Path,
-    pub bounds: Option<OwnedSlice<TyParamBound>>,
+    pub bounds: Option<ast::TyParamBounds>,
 }
 
 enum ItemOrViewItem {
@@ -309,7 +309,7 @@ pub struct Parser<'a> {
     pub tokens_consumed: uint,
     pub restriction: restriction,
     pub quote_depth: uint, // not (yet) related to the quasiquoter
-    pub reader: Box<Reader>,
+    pub reader: Box<Reader+'a>,
     pub interner: Rc<token::IdentInterner>,
     /// The set of seen errors about obsolete syntax. Used to suppress
     /// extra detail when the same error is seen twice
@@ -346,8 +346,11 @@ fn real_token(rdr: &mut Reader) -> TokenAndSpan {
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(sess: &'a ParseSess, cfg: ast::CrateConfig,
-               mut rdr: Box<Reader>) -> Parser<'a> {
+    pub fn new(sess: &'a ParseSess,
+               cfg: ast::CrateConfig,
+               mut rdr: Box<Reader+'a>)
+               -> Parser<'a>
+    {
         let tok0 = real_token(rdr);
         let span = tok0.sp;
         let placeholder = TokenAndSpan {
@@ -1073,14 +1076,7 @@ impl<'a> Parser<'a> {
         };
 
         let (inputs, variadic) = self.parse_fn_args(false, false);
-        let bounds = {
-            if self.eat(&token::COLON) {
-                let (_, bounds) = self.parse_ty_param_bounds(false);
-                Some(bounds)
-            } else {
-                None
-            }
-        };
+        let bounds = self.parse_colon_then_ty_param_bounds();
         let (ret_style, ret_ty) = self.parse_ret_ty();
         let decl = P(FnDecl {
             inputs: inputs,
@@ -1168,14 +1164,7 @@ impl<'a> Parser<'a> {
             (optional_unboxed_closure_kind, inputs)
         };
 
-        let (region, bounds) = {
-            if self.eat(&token::COLON) {
-                let (region, bounds) = self.parse_ty_param_bounds(true);
-                (region, Some(bounds))
-            } else {
-                (None, None)
-            }
-        };
+        let bounds = self.parse_colon_then_ty_param_bounds();
 
         let (return_style, output) = self.parse_ret_ty();
         let decl = P(FnDecl {
@@ -1199,7 +1188,7 @@ impl<'a> Parser<'a> {
                     bounds: bounds,
                     decl: decl,
                     lifetimes: lifetime_defs,
-                }, region)
+                })
             }
         }
     }
@@ -1687,7 +1676,7 @@ impl<'a> Parser<'a> {
             Some(INTERPOLATED(token::NtPath(box path))) => {
                 return PathAndBounds {
                     path: path,
-                    bounds: None,
+                    bounds: None
                 }
             }
             _ => {}
@@ -1744,25 +1733,31 @@ impl<'a> Parser<'a> {
             }
         }
 
-        // Next, parse a plus and bounded type parameters, if applicable.
-        let bounds = if mode == LifetimeAndTypesAndBounds {
-            let bounds = {
-                if self.eat(&token::BINOP(token::PLUS)) {
-                    let (_, bounds) = self.parse_ty_param_bounds(false);
-                    if bounds.len() == 0 {
-                        let last_span = self.last_span;
-                        self.span_err(last_span,
-                                      "at least one type parameter bound \
-                                       must be specified after the `+`");
-                    }
-                    Some(bounds)
-                } else {
-                    None
+        // Next, parse a plus and bounded type parameters, if
+        // applicable. We need to remember whether the separate was
+        // present for later, because in some contexts it's a parse
+        // error.
+        let opt_bounds = {
+            if mode == LifetimeAndTypesAndBounds &&
+                self.eat(&token::BINOP(token::PLUS))
+            {
+                let bounds = self.parse_ty_param_bounds();
+
+                // For some reason that I do not fully understand, we
+                // do not permit an empty list in the case where it is
+                // introduced by a `+`, but we do for `:` and other
+                // separators. -nmatsakis
+                if bounds.len() == 0 {
+                    let last_span = self.last_span;
+                    self.span_err(last_span,
+                                  "at least one type parameter bound \
+                                   must be specified");
                 }
-            };
-            bounds
-        } else {
-            None
+
+                Some(bounds)
+            } else {
+                None
+            }
         };
 
         // Assemble the span.
@@ -1775,7 +1770,7 @@ impl<'a> Parser<'a> {
                 global: is_global,
                 segments: segments,
             },
-            bounds: bounds,
+            bounds: opt_bounds,
         }
     }
 
@@ -3604,45 +3599,34 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// matches optbounds = ( ( : ( boundseq )? )? )
-    /// where   boundseq  = ( bound + boundseq ) | bound
-    /// and     bound     = 'static | ty
-    /// Returns "None" if there's no colon (e.g. "T");
-    /// Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:")
-    /// Returns "Some(stuff)" otherwise (e.g. "T:stuff").
-    /// NB: The None/Some distinction is important for issue #7264.
-    ///
-    /// Note that the `allow_any_lifetime` argument is a hack for now while the
-    /// AST doesn't support arbitrary lifetimes in bounds on type parameters. In
-    /// the future, this flag should be removed, and the return value of this
-    /// function should be Option<~[TyParamBound]>
-    fn parse_ty_param_bounds(&mut self, allow_any_lifetime: bool)
-                             -> (Option<ast::Lifetime>,
-                                 OwnedSlice<TyParamBound>) {
-        let mut ret_lifetime = None;
+    // Parses a sequence of bounds if a `:` is found,
+    // otherwise returns empty list.
+    fn parse_colon_then_ty_param_bounds(&mut self)
+                                        -> OwnedSlice<TyParamBound>
+    {
+        if !self.eat(&token::COLON) {
+            OwnedSlice::empty()
+        } else {
+            self.parse_ty_param_bounds()
+        }
+    }
+
+    // matches bounds    = ( boundseq )?
+    // where   boundseq  = ( bound + boundseq ) | bound
+    // and     bound     = 'region | ty
+    // NB: The None/Some distinction is important for issue #7264.
+    fn parse_ty_param_bounds(&mut self)
+                             -> OwnedSlice<TyParamBound>
+    {
         let mut result = vec!();
         loop {
             match self.token {
                 token::LIFETIME(lifetime) => {
-                    let lifetime_interned_string = token::get_ident(lifetime);
-                    if lifetime_interned_string.equiv(&("'static")) {
-                        result.push(StaticRegionTyParamBound);
-                        if allow_any_lifetime && ret_lifetime.is_none() {
-                            ret_lifetime = Some(ast::Lifetime {
-                                id: ast::DUMMY_NODE_ID,
-                                span: self.span,
-                                name: lifetime.name
-                            });
-                        }
-                    } else if allow_any_lifetime && ret_lifetime.is_none() {
-                        ret_lifetime = Some(ast::Lifetime {
-                            id: ast::DUMMY_NODE_ID,
-                            span: self.span,
-                            name: lifetime.name
-                        });
-                    } else {
-                        result.push(OtherRegionTyParamBound(self.span));
-                    }
+                    result.push(RegionTyParamBound(ast::Lifetime {
+                        id: ast::DUMMY_NODE_ID,
+                        span: self.span,
+                        name: lifetime.name
+                    }));
                     self.bump();
                 }
                 token::MOD_SEP | token::IDENT(..) => {
@@ -3662,7 +3646,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        return (ret_lifetime, OwnedSlice::from_vec(result));
+        return OwnedSlice::from_vec(result);
     }
 
     fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef {
@@ -3699,16 +3683,7 @@ impl<'a> Parser<'a> {
             ident = self.parse_ident();
         }
 
-        let opt_bounds = {
-            if self.eat(&token::COLON) {
-                let (_, bounds) = self.parse_ty_param_bounds(false);
-                Some(bounds)
-            } else {
-                None
-            }
-        };
-        // For typarams we don't care about the difference b/w "<T>" and "<T:>".
-        let bounds = opt_bounds.unwrap_or_default();
+        let bounds = self.parse_colon_then_ty_param_bounds();
 
         let default = if self.token == token::EQ {
             self.bump();
@@ -3797,7 +3772,7 @@ impl<'a> Parser<'a> {
             };
             self.expect(&token::COLON);
 
-            let (_, bounds) = self.parse_ty_param_bounds(false);
+            let bounds = self.parse_ty_param_bounds();
             let hi = self.span.hi;
             let span = mk_sp(lo, hi);
 
@@ -4273,19 +4248,13 @@ impl<'a> Parser<'a> {
         let mut tps = self.parse_generics();
         let sized = self.parse_for_sized();
 
-        // Parse traits, if necessary.
-        let traits;
-        if self.token == token::COLON {
-            self.bump();
-            traits = self.parse_trait_ref_list(&token::LBRACE);
-        } else {
-            traits = Vec::new();
-        }
+        // Parse supertrait bounds.
+        let bounds = self.parse_colon_then_ty_param_bounds();
 
         self.parse_where_clause(&mut tps);
 
         let meths = self.parse_trait_methods();
-        (ident, ItemTrait(tps, sized, traits, meths), None)
+        (ident, ItemTrait(tps, sized, bounds, meths), None)
     }
 
     fn parse_impl_items(&mut self) -> (Vec<ImplItem>, Vec<Attribute>) {
@@ -4319,12 +4288,10 @@ impl<'a> Parser<'a> {
             // New-style trait. Reinterpret the type as a trait.
             let opt_trait_ref = match ty.node {
                 TyPath(ref path, None, node_id) => {
-                    Some(TraitRef {
-                        path: /* bad */ (*path).clone(),
-                        ref_id: node_id
-                    })
+                    Some(TraitRef { path: (*path).clone(),
+                                    ref_id: node_id })
                 }
-                TyPath(..) => {
+                TyPath(_, Some(_), _) => {
                     self.span_err(ty.span,
                                   "bounded traits are only valid in type position");
                     None
@@ -4359,15 +4326,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse B + C<String,int> + D
-    fn parse_trait_ref_list(&mut self, ket: &token::Token) -> Vec<TraitRef> {
-        self.parse_seq_to_before_end(
-            ket,
-            seq_sep_trailing_disallowed(token::BINOP(token::PLUS)),
-            |p| p.parse_trait_ref()
-        )
-    }
-
     /// Parse struct Foo { ... }
     fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
         let class_name = self.parse_ident();
diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs
index f28e6829b00..70da4e11961 100644
--- a/src/libsyntax/print/pp.rs
+++ b/src/libsyntax/print/pp.rs
@@ -155,7 +155,7 @@ pub struct PrintStackElem {
 
 static SIZE_INFINITY: int = 0xffff;
 
-pub fn mk_printer(out: Box<io::Writer>, linewidth: uint) -> Printer {
+pub fn mk_printer(out: Box<io::Writer+'static>, linewidth: uint) -> Printer {
     // Yes 3, it makes the ring buffers big enough to never
     // fall behind.
     let n: uint = 3 * linewidth;
@@ -260,7 +260,7 @@ pub fn mk_printer(out: Box<io::Writer>, linewidth: uint) -> Printer {
 /// the method called 'pretty_print', and the 'PRINT' process is the method
 /// called 'print'.
 pub struct Printer {
-    pub out: Box<io::Writer>,
+    pub out: Box<io::Writer+'static>,
     buf_len: uint,
     /// Width of lines we're constrained to
     margin: int,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 41f95fa75f5..da265d81250 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -10,8 +10,8 @@
 
 use abi;
 use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind};
-use ast::{FnUnboxedClosureKind, MethodImplItem, P, OtherRegionTyParamBound};
-use ast::{StaticRegionTyParamBound, TraitTyParamBound, UnboxedClosureKind};
+use ast::{FnUnboxedClosureKind, MethodImplItem, P};
+use ast::{RegionTyParamBound, TraitTyParamBound, UnboxedClosureKind};
 use ast::{UnboxedFnTyParamBound, RequiredMethod, ProvidedMethod};
 use ast;
 use ast_util;
@@ -60,16 +60,16 @@ pub struct State<'a> {
     literals: Option<Vec<comments::Literal> >,
     cur_cmnt_and_lit: CurrentCommentAndLiteral,
     boxes: Vec<pp::Breaks>,
-    ann: &'a PpAnn,
+    ann: &'a PpAnn+'a,
     encode_idents_with_hygiene: bool,
 }
 
-pub fn rust_printer(writer: Box<io::Writer>) -> State<'static> {
+pub fn rust_printer(writer: Box<io::Writer+'static>) -> State<'static> {
     static NO_ANN: NoAnn = NoAnn;
     rust_printer_annotated(writer, &NO_ANN)
 }
 
-pub fn rust_printer_annotated<'a>(writer: Box<io::Writer>,
+pub fn rust_printer_annotated<'a>(writer: Box<io::Writer+'static>,
                                   ann: &'a PpAnn) -> State<'a> {
     State {
         s: pp::mk_printer(writer, default_columns),
@@ -98,7 +98,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                        krate: &ast::Crate,
                        filename: String,
                        input: &mut io::Reader,
-                       out: Box<io::Writer>,
+                       out: Box<io::Writer+'static>,
                        ann: &'a PpAnn,
                        is_expanded: bool) -> IoResult<()> {
     let mut s = State::new_from_input(cm,
@@ -118,7 +118,7 @@ impl<'a> State<'a> {
                           span_diagnostic: &diagnostic::SpanHandler,
                           filename: String,
                           input: &mut io::Reader,
-                          out: Box<io::Writer>,
+                          out: Box<io::Writer+'static>,
                           ann: &'a PpAnn,
                           is_expanded: bool) -> State<'a> {
         let (cmnts, lits) = comments::gather_comments_and_literals(
@@ -138,7 +138,7 @@ impl<'a> State<'a> {
     }
 
     pub fn new(cm: &'a CodeMap,
-               out: Box<io::Writer>,
+               out: Box<io::Writer+'static>,
                ann: &'a PpAnn,
                comments: Option<Vec<comments::Comment>>,
                literals: Option<Vec<comments::Literal>>) -> State<'a> {
@@ -594,17 +594,16 @@ impl<'a> State<'a> {
                 };
                 try!(self.print_ty_fn(Some(f.abi),
                                       None,
-                                      &None,
                                       f.fn_style,
                                       ast::Many,
                                       &*f.decl,
                                       None,
-                                      &None,
+                                      &OwnedSlice::empty(),
                                       Some(&generics),
                                       None,
                                       None));
             }
-            ast::TyClosure(f, ref region) => {
+            ast::TyClosure(f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
                     ty_params: OwnedSlice::empty(),
@@ -615,7 +614,6 @@ impl<'a> State<'a> {
                 };
                 try!(self.print_ty_fn(None,
                                       Some('&'),
-                                      region,
                                       f.fn_style,
                                       f.onceness,
                                       &*f.decl,
@@ -636,7 +634,6 @@ impl<'a> State<'a> {
                 };
                 try!(self.print_ty_fn(None,
                                       Some('~'),
-                                      &None,
                                       f.fn_style,
                                       f.onceness,
                                       &*f.decl,
@@ -649,12 +646,11 @@ impl<'a> State<'a> {
             ast::TyUnboxedFn(f) => {
                 try!(self.print_ty_fn(None,
                                       None,
-                                      &None,
                                       ast::NormalFn,
                                       ast::Many,
                                       &*f.decl,
                                       None,
-                                      &None,
+                                      &OwnedSlice::empty(),
                                       None,
                                       None,
                                       Some(f.kind)));
@@ -837,7 +833,7 @@ impl<'a> State<'a> {
                 }
                 try!(self.bclose(item.span));
             }
-            ast::ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
+            ast::ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
                 try!(self.head(visibility_qualified(item.vis,
                                                     "trait").as_slice()));
                 try!(self.print_ident(item.ident));
@@ -851,16 +847,7 @@ impl<'a> State<'a> {
                     }
                     _ => {}
                 }
-                if traits.len() != 0u {
-                    try!(word(&mut self.s, ":"));
-                    for (i, trait_) in traits.iter().enumerate() {
-                        try!(self.nbsp());
-                        if i != 0 {
-                            try!(self.word_space("+"));
-                        }
-                        try!(self.print_path(&trait_.path, false));
-                    }
-                }
+                try!(self.print_bounds(":", bounds));
                 try!(self.print_where_clause(generics));
                 try!(word(&mut self.s, " "));
                 try!(self.bopen());
@@ -1073,12 +1060,11 @@ impl<'a> State<'a> {
         try!(self.print_outer_attributes(m.attrs.as_slice()));
         try!(self.print_ty_fn(None,
                               None,
-                              &None,
                               m.fn_style,
                               ast::Many,
                               &*m.decl,
                               Some(m.ident),
-                              &None,
+                              &OwnedSlice::empty(),
                               Some(&m.generics),
                               Some(m.explicit_self.node),
                               None));
@@ -1808,7 +1794,7 @@ impl<'a> State<'a> {
 
         match *opt_bounds {
             None => Ok(()),
-            Some(ref bounds) => self.print_bounds(&None, bounds, true, true),
+            Some(ref bounds) => self.print_bounds("+", bounds)
         }
     }
 
@@ -2132,30 +2118,12 @@ impl<'a> State<'a> {
     }
 
     pub fn print_bounds(&mut self,
-                        region: &Option<ast::Lifetime>,
-                        bounds: &OwnedSlice<ast::TyParamBound>,
-                        print_colon_anyway: bool,
-                        print_plus_before_bounds: bool)
+                        prefix: &str,
+                        bounds: &OwnedSlice<ast::TyParamBound>)
                         -> IoResult<()> {
-        let separator = if print_plus_before_bounds {
-            "+"
-        } else {
-            ":"
-        };
-        if !bounds.is_empty() || region.is_some() {
-            try!(word(&mut self.s, separator));
+        if !bounds.is_empty() {
+            try!(word(&mut self.s, prefix));
             let mut first = true;
-            match *region {
-                Some(ref lt) => {
-                    let token = token::get_name(lt.name);
-                    if token.get() != "'static" {
-                        try!(self.nbsp());
-                        first = false;
-                        try!(self.print_lifetime(lt));
-                    }
-                }
-                None => {}
-            }
             for bound in bounds.iter() {
                 try!(self.nbsp());
                 if first {
@@ -2165,27 +2133,27 @@ impl<'a> State<'a> {
                 }
 
                 try!(match *bound {
-                    TraitTyParamBound(ref tref) => self.print_trait_ref(tref),
-                    StaticRegionTyParamBound => word(&mut self.s, "'static"),
+                    TraitTyParamBound(ref tref) => {
+                        self.print_trait_ref(tref)
+                    }
+                    RegionTyParamBound(ref lt) => {
+                        self.print_lifetime(lt)
+                    }
                     UnboxedFnTyParamBound(ref unboxed_function_type) => {
                         self.print_ty_fn(None,
                                          None,
-                                         &None,
                                          ast::NormalFn,
                                          ast::Many,
                                          &*unboxed_function_type.decl,
                                          None,
-                                         &None,
+                                         &OwnedSlice::empty(),
                                          None,
                                          None,
                                          Some(unboxed_function_type.kind))
                     }
-                    OtherRegionTyParamBound(_) => Ok(())
                 })
             }
             Ok(())
-        } else if print_colon_anyway {
-            word(&mut self.s, separator)
         } else {
             Ok(())
         }
@@ -2212,23 +2180,29 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    fn print_type_parameters(&mut self,
-                             lifetimes: &[ast::LifetimeDef],
-                             ty_params: &[ast::TyParam])
-                             -> IoResult<()> {
-        let total = lifetimes.len() + ty_params.len();
+    pub fn print_generics(&mut self,
+                          generics: &ast::Generics)
+                          -> IoResult<()>
+    {
+        let total = generics.lifetimes.len() + generics.ty_params.len();
+        if total == 0 {
+            return Ok(());
+        }
+
+        try!(word(&mut self.s, "<"));
+
         let mut ints = Vec::new();
         for i in range(0u, total) {
             ints.push(i);
         }
 
-        self.commasep(Inconsistent, ints.as_slice(), |s, &idx| {
-            if idx < lifetimes.len() {
-                let lifetime = &lifetimes[idx];
+        try!(self.commasep(Inconsistent, ints.as_slice(), |s, &idx| {
+            if idx < generics.lifetimes.len() {
+                let lifetime = generics.lifetimes.get(idx);
                 s.print_lifetime_def(lifetime)
             } else {
-                let idx = idx - lifetimes.len();
-                let param = &ty_params[idx];
+                let idx = idx - generics.lifetimes.len();
+                let param = generics.ty_params.get(idx);
                 match param.unbound {
                     Some(TraitTyParamBound(ref tref)) => {
                         try!(s.print_trait_ref(tref));
@@ -2237,10 +2211,7 @@ impl<'a> State<'a> {
                     _ => {}
                 }
                 try!(s.print_ident(param.ident));
-                try!(s.print_bounds(&None,
-                                    &param.bounds,
-                                    false,
-                                    false));
+                try!(s.print_bounds(":", &param.bounds));
                 match param.default {
                     Some(ref default) => {
                         try!(space(&mut s.s));
@@ -2250,19 +2221,10 @@ impl<'a> State<'a> {
                     _ => Ok(())
                 }
             }
-        })
-    }
+        }));
 
-    pub fn print_generics(&mut self, generics: &ast::Generics)
-                          -> IoResult<()> {
-        if generics.lifetimes.len() + generics.ty_params.len() > 0 {
-            try!(word(&mut self.s, "<"));
-            try!(self.print_type_parameters(generics.lifetimes.as_slice(),
-                                            generics.ty_params.as_slice()));
-            word(&mut self.s, ">")
-        } else {
-            Ok(())
-        }
+        try!(word(&mut self.s, ">"));
+        Ok(())
     }
 
     pub fn print_where_clause(&mut self, generics: &ast::Generics)
@@ -2283,7 +2245,7 @@ impl<'a> State<'a> {
             }
 
             try!(self.print_ident(predicate.ident));
-            try!(self.print_bounds(&None, &predicate.bounds, false, false));
+            try!(self.print_bounds(":", &predicate.bounds));
         }
 
         Ok(())
@@ -2421,12 +2383,11 @@ impl<'a> State<'a> {
     pub fn print_ty_fn(&mut self,
                        opt_abi: Option<abi::Abi>,
                        opt_sigil: Option<char>,
-                       opt_region: &Option<ast::Lifetime>,
                        fn_style: ast::FnStyle,
                        onceness: ast::Onceness,
                        decl: &ast::FnDecl,
                        id: Option<ast::Ident>,
-                       opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
+                       bounds: &OwnedSlice<ast::TyParamBound>,
                        generics: Option<&ast::Generics>,
                        opt_explicit_self: Option<ast::ExplicitSelf_>,
                        opt_unboxed_closure_kind:
@@ -2495,9 +2456,7 @@ impl<'a> State<'a> {
             try!(self.pclose());
         }
 
-        opt_bounds.as_ref().map(|bounds| {
-            self.print_bounds(opt_region, bounds, true, false)
-        });
+        try!(self.print_bounds(":", bounds));
 
         try!(self.maybe_print_comment(decl.output.span.lo));
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 6c6f59f0df6..7a35d82b0e4 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -298,13 +298,9 @@ pub fn walk_item<E: Clone, V: Visitor<E>>(visitor: &mut V, item: &Item, env: E)
                                      item.id,
                                      env.clone())
         }
-        ItemTrait(ref generics, _, ref trait_paths, ref methods) => {
+        ItemTrait(ref generics, _, ref bounds, ref methods) => {
             visitor.visit_generics(generics, env.clone());
-            for trait_path in trait_paths.iter() {
-                visitor.visit_path(&trait_path.path,
-                                   trait_path.ref_id,
-                                   env.clone())
-            }
+            walk_ty_param_bounds(visitor, bounds, env.clone());
             for method in methods.iter() {
                 visitor.visit_trait_item(method, env.clone())
             }
@@ -375,18 +371,13 @@ pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
                 visitor.visit_ty(&*tuple_element_type, env.clone())
             }
         }
-        TyClosure(ref function_declaration, ref region) => {
+        TyClosure(ref function_declaration) => {
             for argument in function_declaration.decl.inputs.iter() {
                 visitor.visit_ty(&*argument.ty, env.clone())
             }
             visitor.visit_ty(&*function_declaration.decl.output, env.clone());
-            for bounds in function_declaration.bounds.iter() {
-                walk_ty_param_bounds(visitor, bounds, env.clone())
-            }
-            visitor.visit_opt_lifetime_ref(
-                typ.span,
-                region,
-                env.clone());
+            walk_ty_param_bounds(visitor, &function_declaration.bounds,
+                                 env.clone());
             walk_lifetime_decls(visitor, &function_declaration.lifetimes,
                                 env.clone());
         }
@@ -395,9 +386,8 @@ pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
                 visitor.visit_ty(&*argument.ty, env.clone())
             }
             visitor.visit_ty(&*function_declaration.decl.output, env.clone());
-            for bounds in function_declaration.bounds.iter() {
-                walk_ty_param_bounds(visitor, bounds, env.clone())
-            }
+            walk_ty_param_bounds(visitor, &function_declaration.bounds,
+                                 env.clone());
             walk_lifetime_decls(visitor, &function_declaration.lifetimes,
                                 env.clone());
         }
@@ -415,10 +405,13 @@ pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
             }
             visitor.visit_ty(&*function_declaration.decl.output, env.clone());
         }
-        TyPath(ref path, ref bounds, id) => {
+        TyPath(ref path, ref opt_bounds, id) => {
             visitor.visit_path(path, id, env.clone());
-            for bounds in bounds.iter() {
-                walk_ty_param_bounds(visitor, bounds, env.clone())
+            match *opt_bounds {
+                Some(ref bounds) => {
+                    walk_ty_param_bounds(visitor, bounds, env.clone());
+                }
+                None => { }
             }
         }
         TyFixedLengthVec(ref ty, ref expression) => {
@@ -532,7 +525,6 @@ pub fn walk_ty_param_bounds<E: Clone, V: Visitor<E>>(visitor: &mut V,
             TraitTyParamBound(ref typ) => {
                 walk_trait_ref_helper(visitor, typ, env.clone())
             }
-            StaticRegionTyParamBound => {}
             UnboxedFnTyParamBound(ref function_declaration) => {
                 for argument in function_declaration.decl.inputs.iter() {
                     visitor.visit_ty(&*argument.ty, env.clone())
@@ -540,7 +532,9 @@ pub fn walk_ty_param_bounds<E: Clone, V: Visitor<E>>(visitor: &mut V,
                 visitor.visit_ty(&*function_declaration.decl.output,
                                  env.clone());
             }
-            OtherRegionTyParamBound(..) => {}
+            RegionTyParamBound(ref lifetime) => {
+                visitor.visit_lifetime_ref(lifetime, env.clone());
+            }
         }
     }
 }
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index f4b162f0dd8..4790e3833b7 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -135,10 +135,10 @@ pub trait TDynBenchFn {
 pub enum TestFn {
     StaticTestFn(fn()),
     StaticBenchFn(fn(&mut Bencher)),
-    StaticMetricFn(proc(&mut MetricMap)),
+    StaticMetricFn(proc(&mut MetricMap):'static),
     DynTestFn(proc():Send),
-    DynMetricFn(proc(&mut MetricMap)),
-    DynBenchFn(Box<TDynBenchFn>)
+    DynMetricFn(proc(&mut MetricMap):'static),
+    DynBenchFn(Box<TDynBenchFn+'static>)
 }
 
 impl TestFn {
diff --git a/src/test/auxiliary/issue-2380.rs b/src/test/auxiliary/issue-2380.rs
index c617c1b2d03..1cba738c564 100644
--- a/src/test/auxiliary/issue-2380.rs
+++ b/src/test/auxiliary/issue-2380.rs
@@ -14,8 +14,8 @@
 
 pub trait i<T> { }
 
-pub fn f<T>() -> Box<i<T>> {
+pub fn f<T>() -> Box<i<T>+'static> {
     impl<T> i<T> for () { }
 
-    box() () as Box<i<T>>
+    box() () as Box<i<T>+'static>
 }
diff --git a/src/test/auxiliary/issue-7178.rs b/src/test/auxiliary/issue-7178.rs
index fe3842ef174..18b464bd924 100644
--- a/src/test/auxiliary/issue-7178.rs
+++ b/src/test/auxiliary/issue-7178.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct Foo<'a, A>(&'a A);
+pub struct Foo<'a, A:'a>(&'a A);
 
 impl<'a, A> Foo<'a, A> {
     pub fn new(a: &'a A) -> Foo<'a, A> {
diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs
index b6283206676..0a9cfb5884f 100644
--- a/src/test/auxiliary/macro_crate_test.rs
+++ b/src/test/auxiliary/macro_crate_test.rs
@@ -40,7 +40,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
 }
 
 fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
-                   -> Box<MacResult> {
+                   -> Box<MacResult+'static> {
     if !tts.is_empty() {
         cx.span_fatal(sp, "make_a_1 takes no arguments");
     }
@@ -49,7 +49,7 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
 
 // See Issue #15750
 fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
-                   -> Box<MacResult> {
+                   -> Box<MacResult+'static> {
     // Parse an expression and emit it unchanged.
     let mut parser = parse::new_parser_from_tts(cx.parse_sess(),
         cx.cfg(), Vec::from_slice(tts));
@@ -65,7 +65,7 @@ fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: Gc<MetaItem>, it: Gc<Item>)
     }
 }
 
-fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
+fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
     use syntax::ext::quote::rt::*;
 
     if !tts.is_empty() {
diff --git a/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs
new file mode 100644
index 00000000000..a7429ca534b
--- /dev/null
+++ b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs
@@ -0,0 +1,33 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that method bounds declared on traits/impls in a cross-crate
+// scenario work. This is the libary portion of the test.
+
+pub enum MaybeOwned<'a> {
+    Owned(int),
+    Borrowed(&'a int)
+}
+
+struct Inv<'a> { // invariant w/r/t 'a
+    x: &'a mut &'a int
+}
+
+// I encountered a bug at some point with encoding the IntoMaybeOwned
+// trait, so I'll use that as the template for this test.
+pub trait IntoMaybeOwned<'a> {
+    fn into_maybe_owned(self) -> MaybeOwned<'a>;
+    fn bigger_region<'b:'a>(self, b: Inv<'b>);
+}
+
+impl<'a> IntoMaybeOwned<'a> for Inv<'a> {
+    fn into_maybe_owned(self) -> MaybeOwned<'a> { fail!() }
+    fn bigger_region<'b:'a>(self, b: Inv<'b>) { fail!() }
+}
diff --git a/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs b/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs
index b5d13d15493..7a4339aa9f0 100644
--- a/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs
+++ b/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs
@@ -29,7 +29,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
 }
 
 fn expand_foo(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
-              -> Box<MacResult> {
+              -> Box<MacResult+'static> {
     let answer = other::the_answer();
     MacExpr::new(quote_expr!(cx, $answer))
 }
diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs
index adec9d31afe..03f98686324 100644
--- a/src/test/bench/shootout-fasta-redux.rs
+++ b/src/test/bench/shootout-fasta-redux.rs
@@ -77,7 +77,7 @@ struct AminoAcid {
     p: f32,
 }
 
-struct RepeatFasta<'a, W> {
+struct RepeatFasta<'a, W:'a> {
     alu: &'static str,
     out: &'a mut W
 }
@@ -126,7 +126,7 @@ fn make_lookup(a: &[AminoAcid]) -> [AminoAcid, ..LOOKUP_SIZE] {
     lookup
 }
 
-struct RandomFasta<'a, W> {
+struct RandomFasta<'a, W:'a> {
     seed: u32,
     lookup: [AminoAcid, ..LOOKUP_SIZE],
     out: &'a mut W,
diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs
index 9be111f55ae..c46c44abcd4 100644
--- a/src/test/bench/shootout-meteor.rs
+++ b/src/test/bench/shootout-meteor.rs
@@ -69,11 +69,11 @@ impl<'a, T> Iterator<T> for Iterate<'a, T> {
 }
 
 // a linked list using borrowed next.
-enum List<'a, T> {
+enum List<'a, T:'a> {
     Nil,
     Cons(T, &'a List<'a, T>)
 }
-struct ListIterator<'a, T> {
+struct ListIterator<'a, T:'a> {
     cur: &'a List<'a, T>
 }
 impl<'a, T> List<'a, T> {
diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs
index db6db02ded5..b63ecc6b66f 100644
--- a/src/test/compile-fail/bad-method-typaram-kind.rs
+++ b/src/test/compile-fail/bad-method-typaram-kind.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn foo<T>() {
+fn foo<T:'static>() {
     1u.bar::<T>(); //~ ERROR: does not fulfill `Send`
 }
 
diff --git a/src/test/compile-fail/borrowck-call-sendfn.rs b/src/test/compile-fail/borrowck-call-sendfn.rs
index 57c0deb178d..eb2ea6b3de4 100644
--- a/src/test/compile-fail/borrowck-call-sendfn.rs
+++ b/src/test/compile-fail/borrowck-call-sendfn.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 struct Foo {
-    f: proc()
+    f: proc():'static
 }
 
 fn call(x: Foo) {
diff --git a/src/test/compile-fail/borrowck-object-lifetime.rs b/src/test/compile-fail/borrowck-object-lifetime.rs
index c55a5a30538..bbb58e21198 100644
--- a/src/test/compile-fail/borrowck-object-lifetime.rs
+++ b/src/test/compile-fail/borrowck-object-lifetime.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,17 +8,22 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test that borrows that occur due to calls to object methods
+// properly "claim" the object path.
 
 trait Foo {
     fn borrowed(&self) -> &();
+    fn mut_borrowed(&mut self) -> &();
 }
 
-fn borrowed_receiver(x: &Foo) -> &() {
-    x.borrowed()
+fn borrowed_receiver(x: &Foo) {
+    let _y = x.borrowed();
+    let _z = x.borrowed();
 }
 
-fn owned_receiver(x: Box<Foo>) -> &'static () {
-    x.borrowed() //~ ERROR `*x` does not live long enough
+fn mut_borrowed_receiver(x: &mut Foo) {
+    let _y = x.borrowed();
+    let _z = x.mut_borrowed(); //~ ERROR cannot borrow
 }
 
 fn mut_owned_receiver(mut x: Box<Foo>) {
diff --git a/src/test/compile-fail/box-static-bound.rs b/src/test/compile-fail/box-static-bound.rs
index 5ef52ab6645..29ee79b0079 100644
--- a/src/test/compile-fail/box-static-bound.rs
+++ b/src/test/compile-fail/box-static-bound.rs
@@ -12,7 +12,7 @@
 use std::gc::{Gc, GC};
 
 fn f<T>(x: T) -> Gc<T> {
-    box(GC) x  //~ ERROR value may contain references
+    box(GC) x  //~ ERROR the parameter type `T` may not live long enough
 }
 
 fn g<T:'static>(x: T) -> Gc<T> {
diff --git a/src/test/compile-fail/builtin-superkinds-self-type.rs b/src/test/compile-fail/builtin-superkinds-self-type.rs
index 67222bdafbf..726413981a5 100644
--- a/src/test/compile-fail/builtin-superkinds-self-type.rs
+++ b/src/test/compile-fail/builtin-superkinds-self-type.rs
@@ -11,7 +11,7 @@
 // Tests (negatively) the ability for the Self type in default methods
 // to use capabilities granted by builtin kinds as supertraits.
 
-trait Foo : Sync {
+trait Foo : Sync+'static {
     fn foo(self, mut chan: Sender<Self>) {
         chan.send(self); //~ ERROR does not fulfill `Send`
     }
diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs
index 951354d964d..1ff9dc9dac4 100644
--- a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs
+++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs
@@ -13,7 +13,7 @@ struct X {
 }
 
 fn foo(blk: ||:'static) -> X {
-    return X { field: blk }; //~ ERROR expected bounds `'static+Send`
+    return X { field: blk }; //~ ERROR expected bounds `Send`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs
index 9176412cd79..c0b463535d4 100644
--- a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs
+++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs
@@ -12,8 +12,8 @@ fn bar(blk: ||:'static) {
 }
 
 fn foo(x: &()) {
-    bar(|| { //~ ERROR cannot infer an appropriate lifetime
-        let _ = x;
+    bar(|| {
+        let _ = x; //~ ERROR captured variable `x` does not outlive
     })
 }
 
diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs
index d69a56b76b0..5bd9f20dd83 100644
--- a/src/test/compile-fail/closure-bounds-subtype.rs
+++ b/src/test/compile-fail/closure-bounds-subtype.rs
@@ -9,13 +9,13 @@
 // except according to those terms.
 
 
-fn take_any(_: ||:) {
+fn take_any(_: ||) {
 }
 
 fn take_const_owned(_: ||:Sync+Send) {
 }
 
-fn give_any(f: ||:) {
+fn give_any(f: ||) {
     take_any(f);
 }
 
diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs
index bf501ecfb70..af4c12c754b 100644
--- a/src/test/compile-fail/drop-on-non-struct.rs
+++ b/src/test/compile-fail/drop-on-non-struct.rs
@@ -14,7 +14,6 @@ type Foo = Vec<u8>;
 
 impl Drop for Foo {
 //~^ ERROR cannot provide an extension implementation
-//~^^ ERROR multiple applicable methods
     fn drop(&mut self) {
         println!("kaboom");
     }
diff --git a/src/test/compile-fail/isuue-12470.rs b/src/test/compile-fail/issue-12470.rs
index bf13b7ebbdb..aa7e3cd3739 100644
--- a/src/test/compile-fail/isuue-12470.rs
+++ b/src/test/compile-fail/issue-12470.rs
@@ -24,7 +24,7 @@ impl X for B {
 }
 
 struct A<'a> {
-    p: &'a X
+    p: &'a X+'a
 }
 
 fn make_a<'a>(p: &'a X) -> A<'a> {
diff --git a/src/test/compile-fail/issue-14285.rs b/src/test/compile-fail/issue-14285.rs
index d5e608ecae3..624ddf0c8bb 100644
--- a/src/test/compile-fail/issue-14285.rs
+++ b/src/test/compile-fail/issue-14285.rs
@@ -14,7 +14,7 @@ struct A;
 
 impl Foo for A {}
 
-struct B<'a>(&'a Foo);
+struct B<'a>(&'a Foo+'a);
 
 fn foo<'a>(a: &Foo) -> B<'a> {
     B(a)    //~ ERROR cannot infer an appropriate lifetime
diff --git a/src/test/compile-fail/issue-3154.rs b/src/test/compile-fail/issue-3154.rs
index 141bf2b4279..5f55c550aeb 100644
--- a/src/test/compile-fail/issue-3154.rs
+++ b/src/test/compile-fail/issue-3154.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct thing<'a, Q> {
+struct thing<'a, Q:'a> {
     x: &'a Q
 }
 
diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs
index ab9f7a84530..71f91050256 100644
--- a/src/test/compile-fail/issue-3907-2.rs
+++ b/src/test/compile-fail/issue-3907-2.rs
@@ -11,12 +11,12 @@
 // aux-build:issue_3907.rs
 extern crate issue_3907;
 
-type Foo = issue_3907::Foo;
+type Foo = issue_3907::Foo+'static;
 
 struct S {
     name: int
 }
 
-fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type `issue_3907::Foo`
+fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-3953.rs b/src/test/compile-fail/issue-3953.rs
index 4484a004251..ab2018af999 100644
--- a/src/test/compile-fail/issue-3953.rs
+++ b/src/test/compile-fail/issue-3953.rs
@@ -12,15 +12,9 @@
 
 use std::cmp::PartialEq;
 
-trait Hahaha: PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + //~ ERROR duplicate supertrait
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq +
-              PartialEq {}
+trait Hahaha: PartialEq + PartialEq {
+    //~^ ERROR trait `PartialEq` already appears in the list of bounds
+}
 
 struct Lol(int);
 
diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs
index 199bc3f5c29..bff167fa391 100644
--- a/src/test/compile-fail/issue-4972.rs
+++ b/src/test/compile-fail/issue-4972.rs
@@ -12,12 +12,12 @@
 trait MyTrait { }
 
 pub enum TraitWrapper {
-    A(Box<MyTrait>),
+    A(Box<MyTrait+'static>),
 }
 
 fn get_tw_map(tw: &TraitWrapper) -> &MyTrait {
     match *tw {
-        A(box ref map) => map, //~ ERROR type `Box<MyTrait>` cannot be dereferenced
+        A(box ref map) => map, //~ ERROR cannot be dereferenced
     }
 }
 
diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs
index 689b8f7c613..0251a06c5bd 100644
--- a/src/test/compile-fail/issue-5035-2.rs
+++ b/src/test/compile-fail/issue-5035-2.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 trait I {}
-type K = I;
+type K = I+'static;
 
-fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type `I`
+fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs
index ec9ec9565c4..18af9736ed9 100644
--- a/src/test/compile-fail/issue-5216.rs
+++ b/src/test/compile-fail/issue-5216.rs
@@ -9,12 +9,12 @@
 // except according to those terms.
 
 fn f() { }
-struct S(||); //~ ERROR missing lifetime specifier
+struct S(||); //~ ERROR explicit lifetime bound required
 pub static C: S = S(f);
 
 
 fn g() { }
-type T = ||;  //~ ERROR missing lifetime specifier
+type T = ||;  //~ ERROR explicit lifetime bound required
 pub static D: T = g;
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs
index 14136d96c2d..f3bbb8051b7 100644
--- a/src/test/compile-fail/issue-5883.rs
+++ b/src/test/compile-fail/issue-5883.rs
@@ -11,14 +11,14 @@
 trait A {}
 
 struct Struct {
-    r: A
+    r: A+'static
 }
 
-fn new_struct(r: A) -> Struct {
-    //~^ ERROR variable `r` has dynamically sized type `A`
+fn new_struct(r: A+'static) -> Struct {
+    //~^ ERROR variable `r` has dynamically sized type
     Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct
 }
 
 trait Curve {}
-enum E {X(Curve)}
+enum E {X(Curve+'static)}
 fn main() {}
diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs
index 48e1bdd671a..4cc03ee3dcd 100644
--- a/src/test/compile-fail/kindck-impl-type-params.rs
+++ b/src/test/compile-fail/kindck-impl-type-params.rs
@@ -28,7 +28,7 @@ fn f<T>(val: T) {
 fn main() {
     let t: S<&int> = S;
     let a = &t as &Gettable<&int>;
-    //~^ ERROR instantiating a type parameter with an incompatible type `&int`
+    //~^ ERROR instantiating a type parameter with an incompatible type
     let t: Box<S<String>> = box S;
     let a = t as Box<Gettable<String>>;
     //~^ ERROR instantiating a type parameter with an incompatible type
diff --git a/src/test/compile-fail/proc-bounds.rs b/src/test/compile-fail/kindck-proc-bounds.rs
index e8c6a3ba191..57c8cc3da8a 100644
--- a/src/test/compile-fail/proc-bounds.rs
+++ b/src/test/compile-fail/kindck-proc-bounds.rs
@@ -10,16 +10,13 @@
 
 fn is_send<T: Send>() {}
 fn is_freeze<T: Sync>() {}
-fn is_static<T: 'static>() {}
 
-fn main() {
+fn foo<'a>() {
     is_send::<proc()>();
     //~^ ERROR: instantiating a type parameter with an incompatible type
 
     is_freeze::<proc()>();
     //~^ ERROR: instantiating a type parameter with an incompatible type
-
-    is_static::<proc()>();
-    //~^ ERROR: instantiating a type parameter with an incompatible type
 }
 
+fn main() { }
diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs
new file mode 100644
index 00000000000..99519263923
--- /dev/null
+++ b/src/test/compile-fail/kindck-send-object.rs
@@ -0,0 +1,44 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test which of the builtin types are considered sendable. The tests
+// in this file all test the "kind" violates detected during kindck.
+// See all `regions-bounded-by-send.rs`
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+trait Message : Send { }
+
+// careful with object types, who knows what they close over...
+
+fn object_ref_with_static_bound_not_ok() {
+    assert_send::<&'static Dummy+'static>(); //~ ERROR does not fulfill
+}
+
+fn box_object_with_no_bound_not_ok<'a>() {
+    assert_send::<Box<Dummy>>(); //~ ERROR does not fulfill
+}
+
+fn proc_with_no_bound_not_ok<'a>() {
+    assert_send::<proc()>(); //~ ERROR does not fulfill
+}
+
+fn closure_with_no_bound_not_ok<'a>() {
+    assert_send::<||:'static>(); //~ ERROR does not fulfill
+}
+
+fn object_with_send_bound_ok() {
+    assert_send::<&'static Dummy+Send>();
+    assert_send::<Box<Dummy+Send>>();
+    assert_send::<proc():Send>;
+    assert_send::<||:Send>;
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/kindck-send.rs b/src/test/compile-fail/kindck-send.rs
deleted file mode 100644
index 424c7a4e430..00000000000
--- a/src/test/compile-fail/kindck-send.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2012 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.
-
-// Test which of the builtin types are considered sendable.
-
-
-fn assert_send<T:Send>() { }
-trait Dummy { }
-
-fn test<'a,T,U:Send>(_: &'a int) {
-    // lifetime pointers with 'static lifetime are ok
-    assert_send::<&'static int>();
-    assert_send::<&'static str>();
-    assert_send::<&'static [int]>();
-
-    // whether or not they are mutable
-    assert_send::<&'static mut int>();
-
-    // otherwise lifetime pointers are not ok
-    assert_send::<&'a int>(); //~ ERROR does not fulfill `Send`
-    assert_send::<&'a str>(); //~ ERROR does not fulfill `Send`
-    assert_send::<&'a [int]>(); //~ ERROR does not fulfill `Send`
-
-    // boxes are ok
-    assert_send::<Box<int>>();
-    assert_send::<String>();
-    assert_send::<Vec<int> >();
-
-    // but not if they own a bad thing
-    assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill `Send`
-
-    // careful with object types, who knows what they close over...
-    assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send`
-    assert_send::<&'a Dummy>(); //~ ERROR does not fulfill `Send`
-    assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill `Send`
-    assert_send::<Box<Dummy>>(); //~ ERROR does not fulfill `Send`
-
-    // ...unless they are properly bounded
-    assert_send::<&'static Dummy+Send>();
-    assert_send::<Box<Dummy+Send>>();
-
-    // but closure and object types can have lifetime bounds which make
-    // them not ok (FIXME #5121)
-    // assert_send::<proc:'a()>(); // ERROR does not fulfill `Send`
-    // assert_send::<Box<Dummy+'a>>(); // ERROR does not fulfill `Send`
-
-    // unsafe ptrs are ok unless they point at unsendable things
-    assert_send::<*const int>();
-    assert_send::<*const &'a int>(); //~ ERROR does not fulfill `Send`
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs
new file mode 100644
index 00000000000..21bd676a225
--- /dev/null
+++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int }
+fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) {
+//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int)
+    (x.bar, &x.baz, &x.baz)
+    //~^ ERROR: cannot infer
+    //~^^ ERROR: cannot infer
+    //~^^^ ERROR: cannot infer
+}
+
+fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) {
+//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int)
+    (x.bar, &x.baz, &x.baz)
+    //~^ ERROR: cannot infer
+    //~^^ ERROR: cannot infer
+    //~^^^ ERROR: cannot infer
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs
index 481fb3dee73..b7da4d73489 100644
--- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs
+++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs
@@ -33,21 +33,6 @@ fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) {
     //~^ ERROR: cannot infer
 }
 
-struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int }
-fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int)
-    (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer
-    //~^ ERROR: cannot infer
-    //~^^ ERROR: cannot infer
-}
-
-fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int)
-    (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer
-    //~^ ERROR: cannot infer
-    //~^^ ERROR: cannot infer
-}
-
 struct Cat<'x, T> { cat: &'x int, t: T }
 struct Dog<'y> { dog: &'y int }
 
diff --git a/src/test/compile-fail/moves-sru-moved-field.rs b/src/test/compile-fail/moves-sru-moved-field.rs
index 8b02740497d..74e5e6b1202 100644
--- a/src/test/compile-fail/moves-sru-moved-field.rs
+++ b/src/test/compile-fail/moves-sru-moved-field.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-type Noncopyable = proc();
+type Noncopyable = proc():'static;
 
 struct Foo {
     copied: int,
diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
new file mode 100644
index 00000000000..40cff3e466b
--- /dev/null
+++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs
@@ -0,0 +1,44 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test related to when a region bound is required to be specified.
+
+trait IsStatic : 'static { }
+trait IsSend : Send { }
+trait Is<'a> : 'a { }
+trait Is2<'a> : 'a { }
+trait SomeTrait { }
+
+// Bounds on object types:
+
+struct Foo<'a,'b,'c> {
+    // All of these are ok, because we can derive exactly one bound:
+    a: Box<IsStatic>,
+    b: Box<Is<'static>>,
+    c: Box<Is<'a>>,
+    d: Box<IsSend>,
+    e: Box<Is<'a>+Send>, // we can derive two bounds, but one is 'static, so ok
+    f: Box<SomeTrait>, //~ ERROR explicit lifetime bound required
+    g: Box<SomeTrait+'a>,
+
+    z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted
+}
+
+fn test<
+    'a,
+    'b,
+    A:IsStatic,
+    B:Is<'a>+Is2<'b>,    //~ ERROR ambiguous lifetime bound
+    C:'b+Is<'a>+Is2<'b>,
+    D:Is<'a>+Is2<'static>,
+    E:'a+'b //~ ERROR only a single explicit lifetime bound is permitted
+>() { }
+
+fn main() { }
diff --git a/src/test/compile-fail/region-object-lifetime-1.rs b/src/test/compile-fail/region-object-lifetime-1.rs
new file mode 100644
index 00000000000..01daeb628ef
--- /dev/null
+++ b/src/test/compile-fail/region-object-lifetime-1.rs
@@ -0,0 +1,49 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Various tests related to testing how region inference works
+// with respect to the object receivers.
+
+trait Foo {
+    fn borrowed<'a>(&'a self) -> &'a ();
+}
+
+// Here the receiver and return value all have the same lifetime,
+// so no error results.
+fn borrowed_receiver_same_lifetime<'a>(x: &'a Foo) -> &'a () {
+    x.borrowed()
+}
+
+// Borrowed receiver but two distinct lifetimes, we get an error.
+fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
+    x.borrowed() //~ ERROR cannot infer
+}
+
+// Borrowed receiver with two distinct lifetimes, but we know that
+// 'b:'a, hence &'a () is permitted.
+fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a Foo+'b) -> &'a () {
+    x.borrowed()
+}
+
+// Here we have two distinct lifetimes, but we try to return a pointer
+// with the longer lifetime when (from the signature) we only know
+// that it lives as long as the shorter lifetime. Therefore, error.
+fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a Foo+'b) -> &'b () {
+    x.borrowed() //~ ERROR cannot infer
+}
+
+// Here, the object is bounded by an anonymous lifetime and returned
+// as `&'static`, so you get an error.
+fn owned_receiver(x: Box<Foo>) -> &'static () {
+    x.borrowed() //~ ERROR cannot infer
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/regionck-closure-lifetimes.rs b/src/test/compile-fail/regionck-closure-lifetimes.rs
index 846e03d57c3..bb895a318ff 100644
--- a/src/test/compile-fail/regionck-closure-lifetimes.rs
+++ b/src/test/compile-fail/regionck-closure-lifetimes.rs
@@ -15,7 +15,7 @@ fn env<'a>(blk: |p: ||: 'a|) {
 
     let mut state = 0i;
     let statep = &mut state;
-    blk(|| *statep = 1i); //~ ERROR cannot infer
+    blk(|| *statep = 1i); //~ ERROR captured variable `statep` does not outlive
 }
 
 fn no_env_no_for<'a>(blk: |p: |||: 'a) {
diff --git a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
index 1c590db11e3..7520a4c125a 100644
--- a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
+++ b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
@@ -16,9 +16,8 @@ fn main() {
     let mut f;
     {
         let c = 1;
-        let c_ref = &c;
+        let c_ref = &c; //~ ERROR `c` does not live long enough
         f = |&mut: a: int, b: int| { a + b + *c_ref };
-        //~^ ERROR cannot infer an appropriate lifetime
     }
 }
 
diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
new file mode 100644
index 00000000000..0c9f5004f57
--- /dev/null
+++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
@@ -0,0 +1,57 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+#![no_std]
+
+struct Inv<'a> { // invariant w/r/t 'a
+    x: &'a mut &'a int
+}
+
+pub trait Foo<'a> {
+    fn no_bound<'b>(self, b: Inv<'b>);
+    fn has_bound<'b:'a>(self, b: Inv<'b>);
+    fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+    fn wrong_bound2<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+}
+
+
+impl<'a> Foo<'a> for &'a int {
+    fn no_bound<'b:'a>(self, b: Inv<'b>) {
+        //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
+    }
+
+    fn has_bound<'b>(self, b: Inv<'b>) {
+        //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
+    }
+
+    fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+        //~^ ERROR method `wrong_bound1` has an incompatible type for trait
+        //
+        // Note: This is a terrible error message. It is caused
+        // because, in the trait, 'b is early bound, and in the impl,
+        // 'c is early bound, so -- after substitution -- the
+        // lifetimes themselves look isomorphic.  We fail because the
+        // lifetimes that appear in the types are in the wrong
+        // order. This should really be fixed by keeping more
+        // information about the lifetime declarations in the trait so
+        // that we can compare better to the impl, even in cross-crate
+        // cases.
+    }
+
+    fn wrong_bound2<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
+        //~^ ERROR distinct set of bounds from its counterpart
+    }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs
new file mode 100644
index 00000000000..3c7ffbc8d1f
--- /dev/null
+++ b/src/test/compile-fail/regions-bounded-by-send.rs
@@ -0,0 +1,91 @@
+// Copyright 2012 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.
+
+// Test which of the builtin types are considered sendable. The tests
+// in this file all test region bound and lifetime violations that are
+// detected during type check.
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+
+// lifetime pointers with 'static lifetime are ok
+
+fn static_lifime_ok<'a,T,U:Send>(_: &'a int) {
+    assert_send::<&'static int>();
+    assert_send::<&'static str>();
+    assert_send::<&'static [int]>();
+
+    // whether or not they are mutable
+    assert_send::<&'static mut int>();
+}
+
+// otherwise lifetime pointers are not ok
+
+fn param_not_ok<'a>(x: &'a int) {
+    assert_send::<&'a int>(); //~ ERROR does not fulfill
+}
+
+fn param_not_ok1<'a>(_: &'a int) {
+    assert_send::<&'a str>(); //~ ERROR does not fulfill
+}
+
+fn param_not_ok2<'a>(_: &'a int) {
+    assert_send::<&'a [int]>(); //~ ERROR does not fulfill
+}
+
+// boxes are ok
+
+fn box_ok() {
+    assert_send::<Box<int>>();
+    assert_send::<String>();
+    assert_send::<Vec<int>>();
+}
+
+// but not if they own a bad thing
+
+fn box_with_region_not_ok<'a>() {
+    assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill
+}
+
+// objects with insufficient bounds no ok
+
+fn object_with_random_bound_not_ok<'a>() {
+    assert_send::<&'a Dummy+'a>(); //~ ERROR does not fulfill
+}
+
+fn object_with_send_bound_not_ok<'a>() {
+    assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill
+}
+
+fn proc_with_lifetime_not_ok<'a>() {
+    assert_send::<proc():'a>(); //~ ERROR does not fulfill
+}
+
+fn closure_with_lifetime_not_ok<'a>() {
+    assert_send::<||:'a>(); //~ ERROR does not fulfill
+}
+
+// unsafe pointers are ok unless they point at unsendable things
+
+fn unsafe_ok1<'a>(_: &'a int) {
+    assert_send::<*const int>();
+    assert_send::<*mut int>();
+}
+
+fn unsafe_ok2<'a>(_: &'a int) {
+    assert_send::<*const &'a int>(); //~ ERROR does not fulfill
+}
+
+fn unsafe_ok3<'a>(_: &'a int) {
+    assert_send::<*mut &'a int>(); //~ ERROR does not fulfill
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs
new file mode 100644
index 00000000000..04a94b75215
--- /dev/null
+++ b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs
@@ -0,0 +1,73 @@
+// Copyright 2012 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.
+
+// Test which of the builtin types are considered sendable. The tests
+// in this file all test region bound and lifetime violations that are
+// detected during type check.
+
+trait Dummy : 'static { }
+fn assert_send<T:'static>() { }
+
+// lifetime pointers with 'static lifetime are ok
+
+fn static_lifime_ok<'a,T,U:Send>(_: &'a int) {
+    assert_send::<&'static int>();
+    assert_send::<&'static str>();
+    assert_send::<&'static [int]>();
+
+    // whether or not they are mutable
+    assert_send::<&'static mut int>();
+}
+
+// otherwise lifetime pointers are not ok
+
+fn param_not_ok<'a>(x: &'a int) {
+    assert_send::<&'a int>(); //~ ERROR does not fulfill
+}
+
+fn param_not_ok1<'a>(_: &'a int) {
+    assert_send::<&'a str>(); //~ ERROR does not fulfill
+}
+
+fn param_not_ok2<'a>(_: &'a int) {
+    assert_send::<&'a [int]>(); //~ ERROR does not fulfill
+}
+
+// boxes are ok
+
+fn box_ok() {
+    assert_send::<Box<int>>();
+    assert_send::<String>();
+    assert_send::<Vec<int>>();
+}
+
+// but not if they own a bad thing
+
+fn box_with_region_not_ok<'a>() {
+    assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill
+}
+
+// unsafe pointers are ok unless they point at unsendable things
+
+fn unsafe_ok1<'a>(_: &'a int) {
+    assert_send::<*const int>();
+    assert_send::<*mut int>();
+}
+
+fn unsafe_ok2<'a>(_: &'a int) {
+    assert_send::<*const &'a int>(); //~ ERROR does not fulfill
+}
+
+fn unsafe_ok3<'a>(_: &'a int) {
+    assert_send::<*mut &'a int>(); //~ ERROR does not fulfill
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs
new file mode 100644
index 00000000000..ab97bad5bc2
--- /dev/null
+++ b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs
@@ -0,0 +1,33 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:regions-bounded-method-type-parameters-cross-crate-lib.rs
+
+// Check explicit region bounds on methods in the cross crate case.
+
+extern crate lib = "regions-bounded-method-type-parameters-cross-crate-lib";
+
+use lib::Inv;
+use lib::MaybeOwned;
+use lib::IntoMaybeOwned;
+
+fn call_into_maybe_owned<'a,F:IntoMaybeOwned<'a>>(f: F) {
+    // Exercise a code path I found to be buggy. We were not encoding
+    // the region parameters from the receiver correctly on trait
+    // methods.
+    f.into_maybe_owned();
+}
+
+fn call_bigger_region<'a, 'b>(a: Inv<'a>, b: Inv<'b>) {
+    // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
+    a.bigger_region(b) //~ ERROR cannot infer
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs b/src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs
new file mode 100644
index 00000000000..e628eb3285a
--- /dev/null
+++ b/src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs
@@ -0,0 +1,44 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![no_std]
+#![feature(lang_items)]
+
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+#[lang="sized"]
+trait Sized { }
+
+struct Inv<'a> { // invariant w/r/t 'a
+    x: &'a mut &'a int
+}
+
+trait Foo<'x> {
+    fn method<'y:'x>(self, y: Inv<'y>);
+}
+
+fn caller1<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+    // Here the value provided for 'y is 'a, and hence 'a:'a holds.
+    f.method(a);
+}
+
+fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+    // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
+    f.method(b); //~ ERROR cannot infer
+}
+
+fn caller3<'a,'b:'a,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+    // Here the value provided for 'y is 'b, and hence 'b:'a holds.
+    f.method(b);
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/proc-static-bound.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs
index f11ddc0151f..ba1993686d5 100644
--- a/src/test/compile-fail/proc-static-bound.rs
+++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs
@@ -8,19 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn main() {
-    let mut x = Some(1);
-    let mut p: proc(&mut Option<int>) = proc(_) {};
-    match x {
-        Some(ref y) => {
-            p = proc(z: &mut Option<int>) {
-                *z = None;
-                let _ = y;
-                //~^ ERROR cannot capture variable of type `&int`, which does not fulfill `'static`
-            };
-        }
-        None => {}
-    }
-    p(&mut x);
+#![no_std]
+
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+struct Foo;
+
+impl Foo {
+    fn some_method<A:'static>(self) { }
+}
+
+fn caller<'a>(x: &int) {
+    Foo.some_method::<&'a int>();
+    //~^ ERROR does not fulfill the required lifetime
 }
 
+fn main() { }
diff --git a/src/test/compile-fail/owned-ptr-static-bound.rs b/src/test/compile-fail/regions-close-object-into-object.rs
index dc6e8b1d6be..a45c8e1db54 100644
--- a/src/test/compile-fail/owned-ptr-static-bound.rs
+++ b/src/test/compile-fail/regions-close-object-into-object.rs
@@ -10,21 +10,25 @@
 
 
 trait A<T> {}
-struct B<'a, T>(&'a A<T>);
+struct B<'a, T>(&'a A<T>+'a);
 
 trait X {}
 impl<'a, T> X for B<'a, T> {}
 
-fn f<'a, T, U>(v: Box<A<T>>) -> Box<X> {
-    box B(v) as Box<X> //~ ERROR value may contain references; add `'static` bound to `T`
+fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+    box B(v) as Box<X>
 }
 
-fn g<'a, T, U>(v: Box<A<U>>) -> Box<X> {
-    box B(v) as Box<X> //~ ERROR value may contain references; add `'static` bound to `U`
+fn g<'a, T: 'static>(v: Box<A<T>>) -> Box<X+'static> {
+    box B(v) as Box<X> //~ ERROR cannot infer
 }
 
-fn h<'a, T: 'static>(v: Box<A<T>>) -> Box<X> {
-    box B(v) as Box<X> // ok
+fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
+    box B(v) as Box<X>
+}
+
+fn i<'a, T, U>(v: Box<A<U>>) -> Box<X+'static> {
+    box B(v) as Box<X> //~ ERROR cannot infer
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs b/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs
index 0f79716f370..037514f45c7 100644
--- a/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs
+++ b/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs
@@ -8,11 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-pretty
-
 trait Foo { }
 
-fn foo<'a, 'b:'a>() { //~ ERROR region bounds require `issue_5723_bootstrap`
-}
+impl<'a> Foo for &'a int { }
 
-pub fn main() { }
+fn main() {
+    let blah;
+    {
+        let ss: &int = &1; //~ ERROR borrowed value does not live long enough
+        blah = box ss as Box<Foo>;
+    }
+}
diff --git a/src/test/compile-fail/regions-close-over-type-parameter-1.rs b/src/test/compile-fail/regions-close-over-type-parameter-1.rs
new file mode 100644
index 00000000000..5465f199f40
--- /dev/null
+++ b/src/test/compile-fail/regions-close-over-type-parameter-1.rs
@@ -0,0 +1,31 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test for what happens when a type parameter `A` is closed over into
+// an object. This should yield errors unless `A` (and the object)
+// both have suitable bounds.
+
+trait SomeTrait { fn get(&self) -> int; }
+
+fn make_object1<A:SomeTrait>(v: A) -> Box<SomeTrait+'static> {
+    box v as Box<SomeTrait+'static>
+        //~^ ERROR the parameter type `A` may not live long enough
+}
+
+fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'a> {
+    box v as Box<SomeTrait+'a>
+}
+
+fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'b> {
+    box v as Box<SomeTrait+'b>
+        //~^ ERROR the parameter type `A` may not live long enough
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/regions-close-over-type-parameter-2.rs
index 50704a1afbf..0ee349aaebf 100644
--- a/src/test/compile-fail/kindck-owned-trait-contains.rs
+++ b/src/test/compile-fail/regions-close-over-type-parameter-2.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,25 +8,27 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test for what happens when a type parameter `A` is closed over into
+// an object. This should yield errors unless `A` (and the object)
+// both have suitable bounds.
 
-trait Repeat<A> { fn get(&self) -> A; }
+trait Foo { fn get(&self); }
 
-impl<A:Clone> Repeat<A> for A {
-    fn get(&self) -> A { self.clone() }
+impl<A> Foo for A {
+    fn get(&self) { }
 }
 
-fn repeater<A:Clone>(v: A) -> Box<Repeat<A>> {
-    box v as Box<Repeat<A>> // No
+fn repeater3<'a,A:'a>(v: A) -> Box<Foo+'a> {
+    box v as Box<Foo+'a>
 }
 
 fn main() {
     // Error results because the type of is inferred to be
     // ~Repeat<&'blk int> where blk is the lifetime of the block below.
 
-    let y = {
+    let _ = {
         let tmp0 = 3i;
         let tmp1 = &tmp0; //~ ERROR `tmp0` does not live long enough
-        repeater(tmp1)
+        repeater3(tmp1)
     };
-    assert!(3 == *(y.get()));
 }
diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs
index 25016c104ad..5da281d93dd 100644
--- a/src/test/compile-fail/regions-early-bound-error.rs
+++ b/src/test/compile-fail/regions-early-bound-error.rs
@@ -15,7 +15,7 @@ trait GetRef<'a, T> {
     fn get(&self) -> &'a T;
 }
 
-struct Box<'a, T> {
+struct Box<'a, T:'a> {
     t: &'a T
 }
 
diff --git a/src/test/compile-fail/regions-enum-not-wf.rs b/src/test/compile-fail/regions-enum-not-wf.rs
new file mode 100644
index 00000000000..6395ee62f16
--- /dev/null
+++ b/src/test/compile-fail/regions-enum-not-wf.rs
@@ -0,0 +1,37 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Various examples of structs whose fields are not well-formed.
+
+#![no_std]
+#![allow(dead_code)]
+
+enum Ref1<'a, T> { //~ ERROR the parameter type `T` may not live long enough
+    Ref1Variant1(&'a T)
+}
+
+enum Ref2<'a, T> { //~ ERROR the parameter type `T` may not live long enough
+    Ref2Variant1,
+    Ref2Variant2(int, &'a T),
+}
+
+enum RefOk<'a, T:'a> {
+    RefOkVariant1(&'a T)
+}
+
+enum RefIndirect<'a, T> { //~ ERROR the parameter type `T` may not live long enough
+    RefIndirectVariant1(int, RefOk<'a,T>)
+}
+
+enum RefDouble<'a, 'b, T> { //~ ERROR reference has a longer lifetime than the data
+    RefDoubleVariant1(&'a &'b T)
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/compile-fail/regions-escape-bound-fn-2.rs
index d2551ec4fed..d752bc97cac 100644
--- a/src/test/compile-fail/regions-escape-bound-fn-2.rs
+++ b/src/test/compile-fail/regions-escape-bound-fn-2.rs
@@ -16,5 +16,6 @@ fn with_int(f: |x: &int|) {
 fn main() {
     let mut x = None;
          //~^ ERROR lifetime of variable does not enclose its declaration
+         //~^^ ERROR type of expression contains references that are not valid during the expression
     with_int(|y| x = Some(y));
 }
diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs
index 980a4aed34f..adef1f901fd 100644
--- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs
+++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs
@@ -8,17 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-trait deref {
+#![no_std]
+
+#![allow(dead_code)]
+
+trait Deref {
     fn get(self) -> int;
 }
 
-impl<'a> deref for &'a int {
+impl<'a> Deref for &'a int {
     fn get(self) -> int {
         *self
     }
 }
 
-fn with<R:deref>(f: |x: &int| -> R) -> int {
+fn with<R:Deref>(f: |x: &int| -> R) -> int {
     f(&3).get()
 }
 
diff --git a/src/test/compile-fail/regions-free-region-ordering-callee.rs b/src/test/compile-fail/regions-free-region-ordering-callee.rs
index 9762e5c4690..26cf3be429b 100644
--- a/src/test/compile-fail/regions-free-region-ordering-callee.rs
+++ b/src/test/compile-fail/regions-free-region-ordering-callee.rs
@@ -31,6 +31,12 @@ fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint {
 }
 
 fn ordering4<'a, 'b>(a: &'a uint, b: &'b uint, x: |&'a &'b uint|) {
+    // Do not infer ordering from closure argument types.
+    let z: Option<&'a &'b uint> = None;
+    //~^ ERROR reference has a longer lifetime than the data it references
+}
+
+fn ordering5<'a, 'b>(a: &'a uint, b: &'b uint, x: Option<&'a &'b uint>) {
     let z: Option<&'a &'b uint> = None;
 }
 
diff --git a/src/test/compile-fail/regions-free-region-ordering-caller.rs b/src/test/compile-fail/regions-free-region-ordering-caller.rs
index 2f8caabb7f8..55c0cf3bb26 100644
--- a/src/test/compile-fail/regions-free-region-ordering-caller.rs
+++ b/src/test/compile-fail/regions-free-region-ordering-caller.rs
@@ -16,18 +16,18 @@ struct Paramd<'a> { x: &'a uint }
 
 fn call2<'a, 'b>(a: &'a uint, b: &'b uint) {
     let z: Option<&'b &'a uint> = None;
-    //~^ ERROR pointer has a longer lifetime than the data it references
+    //~^ ERROR reference has a longer lifetime than the data it references
 }
 
 fn call3<'a, 'b>(a: &'a uint, b: &'b uint) {
     let y: Paramd<'a> = Paramd { x: a };
     let z: Option<&'b Paramd<'a>> = None;
-    //~^ ERROR pointer has a longer lifetime than the data it references
+    //~^ ERROR reference has a longer lifetime than the data it references
 }
 
 fn call4<'a, 'b>(a: &'a uint, b: &'b uint) {
-    let z: Option<|&'a &'b uint|> = None;
-    //~^ ERROR pointer has a longer lifetime than the data it references
+    let z: Option<&'a &'b uint> = None;
+    //~^ ERROR reference has a longer lifetime than the data it references
 }
 
 
diff --git a/src/test/compile-fail/regions-free-region-ordering-incorrect.rs b/src/test/compile-fail/regions-free-region-ordering-incorrect.rs
index 6f6b6761735..9cb61c24922 100644
--- a/src/test/compile-fail/regions-free-region-ordering-incorrect.rs
+++ b/src/test/compile-fail/regions-free-region-ordering-incorrect.rs
@@ -15,7 +15,7 @@
 //
 // This test began its life as a test for issue #4325.
 
-struct Node<'b, T> {
+struct Node<'b, T:'b> {
   val: T,
   next: Option<&'b Node<'b, T>>
 }
diff --git a/src/test/compile-fail/regions-freevar.rs b/src/test/compile-fail/regions-freevar.rs
index cef3b525997..76bbe71cf75 100644
--- a/src/test/compile-fail/regions-freevar.rs
+++ b/src/test/compile-fail/regions-freevar.rs
@@ -12,7 +12,7 @@ fn wants_static_fn(_x: ||: 'static) {}
 
 fn main() {
     let i = 3i;
-    wants_static_fn(|| { //~ ERROR cannot infer
-        println!("i={}", i);
+    wants_static_fn(|| {
+        println!("i={}", i); //~ ERROR captured variable `i` does not outlive
     })
 }
diff --git a/src/test/compile-fail/regions-infer-bound-from-trait-self.rs b/src/test/compile-fail/regions-infer-bound-from-trait-self.rs
new file mode 100644
index 00000000000..25fd20b6ec5
--- /dev/null
+++ b/src/test/compile-fail/regions-infer-bound-from-trait-self.rs
@@ -0,0 +1,61 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can derive lifetime bounds on `Self` from trait
+// inheritance.
+
+trait Static : 'static { }
+
+trait Is<'a> : 'a { }
+
+struct Inv<'a> {
+    x: Option<&'a mut &'a int>
+}
+
+fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+
+// In these case, `Self` inherits `'static`.
+
+trait InheritsFromStatic : 'static {
+    fn foo1<'a>(self, x: Inv<'a>) {
+        check_bound(x, self)
+    }
+}
+trait InheritsFromStaticIndirectly : Static {
+    fn foo1<'a>(self, x: Inv<'a>) {
+        check_bound(x, self)
+    }
+}
+
+
+// In these case, `Self` inherits `'a`.
+
+trait InheritsFromIs<'a> : 'a {
+    fn foo(self, x: Inv<'a>) {
+        check_bound(x, self)
+    }
+}
+
+trait InheritsFromIsIndirectly<'a> : Is<'a> {
+    fn foo(self, x: Inv<'a>) {
+        check_bound(x, self)
+    }
+}
+
+// In this case, `Self` inherits nothing.
+
+trait InheritsFromNothing<'a> {
+    fn foo(self, x: Inv<'a>) {
+        check_bound(x, self)
+            //~^ ERROR parameter type `Self` may not live long enough
+    }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-infer-bound-from-trait.rs b/src/test/compile-fail/regions-infer-bound-from-trait.rs
new file mode 100644
index 00000000000..d1111377f1e
--- /dev/null
+++ b/src/test/compile-fail/regions-infer-bound-from-trait.rs
@@ -0,0 +1,50 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can derive lifetime bounds on type parameters
+// from trait inheritance.
+
+trait Static : 'static { }
+
+trait Is<'a> : 'a { }
+
+struct Inv<'a> {
+    x: Option<&'a mut &'a int>
+}
+
+fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+
+// In all of these cases, we can derive a bound for A that is longer
+// than 'a based on the trait bound of A:
+
+fn foo1<'a,A:Static>(x: Inv<'a>, a: A) {
+    check_bound(x, a)
+}
+
+fn foo2<'a,A:Static>(x: Inv<'static>, a: A) {
+    check_bound(x, a)
+}
+
+fn foo3<'a,A:Is<'a>>(x: Inv<'a>, a: A) {
+    check_bound(x, a)
+}
+
+// In these cases, there is no trait bound, so we cannot derive any
+// bound for A and we get an error:
+
+fn bar1<'a,A>(x: Inv<'a>, a: A) {
+    check_bound(x, a) //~ ERROR parameter type `A` may not live long enough
+}
+
+fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
+    check_bound(x, a) //~ ERROR parameter type `A` may not live long enough
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs
index a743ff81b30..0fa4969b54c 100644
--- a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs
+++ b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs
@@ -11,7 +11,7 @@
 
 // check that the &int here does not cause us to think that `foo`
 // contains region pointers
-struct foo(proc(x: &int));
+struct foo(proc(x: &int):'static);
 
 fn take_foo(x: foo<'static>) {} //~ ERROR wrong number of lifetime parameters
 
diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
new file mode 100644
index 00000000000..a52d2f9f9a0
--- /dev/null
+++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
@@ -0,0 +1,41 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![no_std]
+
+fn a<'a, 'b:'a>(x: &mut &'a int, y: &mut &'b int) {
+    // Note: this is legal because of the `'b:'a` declaration.
+    *x = *y;
+}
+
+fn b<'a, 'b>(x: &mut &'a int, y: &mut &'b int) {
+    // Illegal now because there is no `'b:'a` declaration.
+    *x = *y; //~ ERROR mismatched types
+}
+
+fn c<'a,'b>(x: &mut &'a int, y: &mut &'b int) {
+    // Here we try to call `foo` but do not know that `'a` and `'b` are
+    // related as required.
+    a(x, y); //~ ERROR cannot infer
+}
+
+fn d() {
+    // 'a and 'b are early bound in the function `a` because they appear
+    // inconstraints:
+    let _: fn(&mut &int, &mut &int) = a; //~ ERROR mismatched types
+}
+
+fn e() {
+    // 'a and 'b are late bound in the function `b` because there are
+    // no constraints:
+    let _: fn(&mut &int, &mut &int) = b;
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs
new file mode 100644
index 00000000000..e32ef275256
--- /dev/null
+++ b/src/test/compile-fail/regions-proc-bound-capture.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn borrowed_proc<'a>(x: &'a int) -> proc():'a -> int {
+    // This is legal, because the region bound on `proc`
+    // states that it captures `x`.
+    proc() {
+        *x
+    }
+}
+
+fn static_proc<'a>(x: &'a int) -> proc():'static -> int {
+    // This is illegal, because the region bound on `proc` is 'static.
+    proc() { //~ ERROR captured variable `x` outlives the `proc()`
+        *x
+    }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-bound-lists-feature-gate.rs b/src/test/compile-fail/regions-proc-bounds.rs
index de3b2faef86..db71bc4e15c 100644
--- a/src/test/compile-fail/regions-bound-lists-feature-gate.rs
+++ b/src/test/compile-fail/regions-proc-bounds.rs
@@ -8,13 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+fn is_static<T: 'static>() {}
 
-trait Foo { }
+fn foo<'a>() {
+    is_static::<proc():'a>();
+    //~^ ERROR does not fulfill the required lifetime
 
-fn foo<'a>(x: Box<Foo + 'a>) { //~ ERROR only the 'static lifetime is accepted here
-}
-
-fn bar<'a, T:'a>() { //~ ERROR only the 'static lifetime is accepted here
+    is_static::<proc():'static>();
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs b/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs
index d3e0740a0fe..50ea8b1f2ed 100644
--- a/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs
+++ b/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs
@@ -11,7 +11,7 @@
 // Issue #8624. Test for reborrowing with 3 levels, not just two.
 
 fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut int) -> &'b mut int {
-    &mut ***p //~ ERROR cannot infer an appropriate lifetime
+    &mut ***p //~ ERROR lifetime of `p` is too short to guarantee its contents
 }
 
 fn main() {
diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs
index df46b2aaac0..aac81a2af6b 100644
--- a/src/test/compile-fail/regions-ret-borrowed-1.rs
+++ b/src/test/compile-fail/regions-ret-borrowed-1.rs
@@ -18,8 +18,9 @@ fn with<R>(f: <'a>|x: &'a int| -> R) -> R {
 
 fn return_it<'a>() -> &'a int {
     with(|o| o)
-        //~^ ERROR lifetime of return value does not outlive the function call
-        //~^^ ERROR cannot infer
+        //~^ ERROR cannot infer
+        //~^^ ERROR not valid during the expression
+        //~^^^ ERROR not valid at this point
 }
 
 fn main() {
diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs
index 507a48fb741..dd9421ee2ef 100644
--- a/src/test/compile-fail/regions-ret-borrowed.rs
+++ b/src/test/compile-fail/regions-ret-borrowed.rs
@@ -21,8 +21,9 @@ fn with<R>(f: |x: &int| -> R) -> R {
 
 fn return_it<'a>() -> &'a int {
     with(|o| o)
-        //~^ ERROR lifetime of return value does not outlive the function call
-        //~^^ ERROR cannot infer
+        //~^ ERROR cannot infer
+        //~^^ ERROR not valid during the expression
+        //~^^^ ERROR not valid at this point
 }
 
 fn main() {
diff --git a/src/test/compile-fail/regions-struct-not-wf.rs b/src/test/compile-fail/regions-struct-not-wf.rs
new file mode 100644
index 00000000000..3de137a9efb
--- /dev/null
+++ b/src/test/compile-fail/regions-struct-not-wf.rs
@@ -0,0 +1,32 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Various examples of structs whose fields are not well-formed.
+
+#![no_std]
+#![allow(dead_code)]
+
+struct Ref<'a, T> { //~ ERROR the parameter type `T` may not live long enough
+    field: &'a T
+}
+
+struct RefOk<'a, T:'a> {
+    field: &'a T
+}
+
+struct RefIndirect<'a, T> { //~ ERROR the parameter type `T` may not live long enough
+    field: RefOk<'a, T>
+}
+
+struct DoubleRef<'a, 'b, T> { //~ ERROR reference has a longer lifetime than the data it references
+    field: &'a &'b T
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-trait-variance.rs b/src/test/compile-fail/regions-trait-variance.rs
index 53cfd4e0324..3ceb4e3fef6 100644
--- a/src/test/compile-fail/regions-trait-variance.rs
+++ b/src/test/compile-fail/regions-trait-variance.rs
@@ -31,7 +31,7 @@ impl Drop for B {
 }
 
 struct A<'r> {
-    p: &'r X
+    p: &'r X+'r
 }
 
 fn make_a(p:&X) -> A {
diff --git a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
index 5cc3f1bdc37..7dcdc9875e3 100644
--- a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
+++ b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
@@ -31,7 +31,7 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // contravariant with respect to its parameter 'a.
 
     let _: Covariant<'short> = c; //~ ERROR mismatched types
-    //~^ ERROR  cannot infer an appropriate lifetime
+    //~^ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
index 0790c3f956a..d09e6babe09 100644
--- a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
+++ b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs
@@ -15,7 +15,7 @@
 // variance inference works in the first place.
 
 struct Invariant<'a> {
-    f: &'static mut &'a int
+    f: &'a mut &'a int
 }
 
 fn use_<'short,'long>(c: Invariant<'long>,
diff --git a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs
index 9cdd05f8ebe..861668ad50d 100644
--- a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs
+++ b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs
@@ -15,7 +15,7 @@
 // variance inference works in the first place.
 
 struct Invariant<'a> {
-    f: &'static mut &'a int
+    f: &'a mut &'a int
 }
 
 fn use_<'b>(c: Invariant<'b>) {
diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs
index 3bf547e3aff..bf7c3b261fd 100644
--- a/src/test/compile-fail/selftype-traittype.rs
+++ b/src/test/compile-fail/selftype-traittype.rs
@@ -13,7 +13,7 @@ trait add {
     fn plus(&self, x: Self) -> Self;
 }
 
-fn do_add(x: Box<add>, y: Box<add>) -> Box<add> {
+fn do_add(x: Box<add+'static>, y: Box<add+'static>) -> Box<add+'static> {
     x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object
 }
 
diff --git a/src/test/compile-fail/static-region-bound.rs b/src/test/compile-fail/static-region-bound.rs
index c36610fc79e..2cb1f462e1d 100644
--- a/src/test/compile-fail/static-region-bound.rs
+++ b/src/test/compile-fail/static-region-bound.rs
@@ -16,6 +16,6 @@ fn f<T:'static>(_: T) {}
 fn main() {
     let x = box(GC) 3i;
     f(x);
-    let x = &3i;
-    f(x);   //~ ERROR instantiating a type parameter with an incompatible type
+    let x = &3i; //~ ERROR borrowed value does not live long enough
+    f(x);
 }
diff --git a/src/test/compile-fail/trailing-plus-in-bounds.rs b/src/test/compile-fail/trailing-plus-in-bounds.rs
index e8f9ed4d2cf..b189acb685a 100644
--- a/src/test/compile-fail/trailing-plus-in-bounds.rs
+++ b/src/test/compile-fail/trailing-plus-in-bounds.rs
@@ -11,7 +11,7 @@
 use std::fmt::Show;
 
 fn main() {
-    let x: Box<Show+> = box 3 as Box<Show+>;
+    let x: Box<Show+> = box 3i as Box<Show+>;
     //~^ ERROR at least one type parameter bound must be specified
     //~^^ ERROR at least one type parameter bound must be specified
 }
diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs
index c3d608b48f3..7ed8db4fcd2 100644
--- a/src/test/compile-fail/trait-bounds-sugar.rs
+++ b/src/test/compile-fail/trait-bounds-sugar.rs
@@ -16,15 +16,16 @@ trait Foo {}
 fn a(_x: Box<Foo+Send>) {
 }
 
-fn b(_x: &'static Foo) { // should be same as &'static Foo+'static
+fn b(_x: &'static Foo+'static) {
 }
 
 fn c(x: Box<Foo+Sync>) {
-    a(x); //~ ERROR expected bounds `Send`
+    a(x); //~ ERROR mismatched types
 }
 
 fn d(x: &'static Foo+Sync) {
-    b(x); //~ ERROR expected bounds `'static`
+    b(x); //~ ERROR cannot infer
+    //~^ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs
index 0f9cfab7b8a..9694c1d9f98 100644
--- a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs
+++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs
@@ -11,7 +11,7 @@
 // This test checks that the `_` type placeholder does not react
 // badly if put as a lifetime parameter.
 
-struct Foo<'a, T> {
+struct Foo<'a, T:'a> {
     r: &'a T
 }
 
diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs
index e9671b353b9..365b786cc1a 100644
--- a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs
+++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs
@@ -11,7 +11,7 @@
 // This test checks that the `_` type placeholder does not react
 // badly if put as a lifetime parameter.
 
-struct Foo<'a, T> {
+struct Foo<'a, T:'a> {
     r: &'a T
 }
 
diff --git a/src/test/compile-fail/unconstrained-ref.rs b/src/test/compile-fail/unconstrained-ref.rs
index a4125f94cd2..87647cdb546 100644
--- a/src/test/compile-fail/unconstrained-ref.rs
+++ b/src/test/compile-fail/unconstrained-ref.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct S<'a, T> {
+struct S<'a, T:'a> {
     o: &'a Option<T>
 }
 
diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs
index e377c9d5f41..a66c1d85009 100644
--- a/src/test/compile-fail/unsized4.rs
+++ b/src/test/compile-fail/unsized4.rs
@@ -12,7 +12,7 @@
 
 trait T {}
 fn f<Sized? Y: T>() {
-//~^ERROR incompatible bounds on type parameter Y, bound T does not allow unsized type
+//~^ERROR incompatible bounds on type parameter `Y`, bound `T` does not allow unsized type
 }
 
 pub fn main() {
diff --git a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs
index 043f3a233a6..3f2f43b0c9b 100644
--- a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs
+++ b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs
@@ -23,10 +23,10 @@ impl fmt::Show for Number {
 }
 
 struct List {
-    list: Vec<Box<ToString>> }
+    list: Vec<Box<ToString+'static>> }
 
 impl List {
-    fn push(&mut self, n: Box<ToString>) {
+    fn push(&mut self, n: Box<ToString+'static>) {
         self.list.push(n);
     }
 }
diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs
index da4f9846187..fa38482b21c 100644
--- a/src/test/compile-fail/variance-regions-direct.rs
+++ b/src/test/compile-fail/variance-regions-direct.rs
@@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]]
 // Mutability induces invariance:
 
 #[rustc_variance]
-struct Test4<'a, 'b> { //~ ERROR regions=[[-, o];[];[]]
+struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]]
     x: &'a mut &'b int,
 }
 
@@ -64,7 +64,7 @@ struct Test7<'a> { //~ ERROR regions=[[*];[];[]]
 // Try enums too.
 
 #[rustc_variance]
-enum Test8<'a, 'b, 'c> { //~ ERROR regions=[[+, -, o];[];[]]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]]
     Test8A(extern "Rust" fn(&'a int)),
     Test8B(&'b [int]),
     Test8C(&'b mut &'c str),
diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs
index 0d20f652496..c049fbc0fed 100644
--- a/src/test/compile-fail/variance-regions-indirect.rs
+++ b/src/test/compile-fail/variance-regions-indirect.rs
@@ -13,29 +13,29 @@
 // Try enums too.
 
 #[rustc_variance]
-enum Base<'a, 'b, 'c, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]]
     Test8A(extern "Rust" fn(&'a int)),
     Test8B(&'b [int]),
     Test8C(&'b mut &'c str),
 }
 
 #[rustc_variance]
-struct Derived1<'w, 'x, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]]
     f: Base<'z, 'y, 'x, 'w>
 }
 
 #[rustc_variance] // Combine - and + to yield o
-struct Derived2<'a, 'b, 'c> { //~ ERROR regions=[[o, o, *];[];[]]
+struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]]
     f: Base<'a, 'a, 'b, 'c>
 }
 
 #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]]
     f: Base<'a, 'b, 'a, 'c>
 }
 
 #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c> { //~ ERROR regions=[[+, -, o];[];[]]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]]
     f: Base<'a, 'b, 'c, 'a>
 }
 
diff --git a/src/test/pretty/closure-reform-pretty.rs b/src/test/pretty/closure-reform-pretty.rs
index 92fa8124d68..eb20a09477d 100644
--- a/src/test/pretty/closure-reform-pretty.rs
+++ b/src/test/pretty/closure-reform-pretty.rs
@@ -17,7 +17,7 @@ fn call_it(f: proc(String) -> String) { }
 
 fn call_this(f: |&str|: Send) { }
 
-fn call_that(f: <'a>|&'a int, &'a int|: -> int) { }
+fn call_that(f: <'a>|&'a int, &'a int| -> int) { }
 
 fn call_extern(f: fn() -> int) { }
 
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index ddf79d1d750..86e394e5408 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -48,8 +48,8 @@ pub fn bar() {
                        as core::fmt::rt::Piece<'static>)] as
                      [core::fmt::rt::Piece<'static>, .. 1]);
              let __args_vec =
-                 (&([] as [core::fmt::Argument<'static>, .. 0]) as
-                     &'static [core::fmt::Argument<'static>, .. 0]);
+                 (&([] as [core::fmt::Argument<'_>, .. 0]) as
+                     &[core::fmt::Argument<'_>, .. 0]);
              let __args =
                  (unsafe {
                       ((::std::fmt::Arguments::new as
@@ -58,9 +58,9 @@ pub fn bar() {
                                                                                                                                                [core::fmt::rt::Piece<'static>, .. 1]),
                                                                                                                                            (__args_vec
                                                                                                                                                as
-                                                                                                                                               &'static [core::fmt::Argument<'static>, .. 0]))
-                          as core::fmt::Arguments<'static>)
-                  } as core::fmt::Arguments<'static>);
+                                                                                                                                               &[core::fmt::Argument<'_>, .. 0]))
+                          as core::fmt::Arguments<'_>)
+                  } as core::fmt::Arguments<'_>);
 
 
 
@@ -72,9 +72,9 @@ pub fn bar() {
              ((::std::fmt::format as
                   fn(&core::fmt::Arguments<'_>) -> collections::string::String)((&(__args
                                                                                       as
-                                                                                      core::fmt::Arguments<'static>)
+                                                                                      core::fmt::Arguments<'_>)
                                                                                     as
-                                                                                    &core::fmt::Arguments<'static>))
+                                                                                    &core::fmt::Arguments<'_>))
                  as collections::string::String)
          }
      } as collections::string::String);
diff --git a/src/test/pretty/path-type-bounds.rs b/src/test/pretty/path-type-bounds.rs
index 7c05e6d6065..f575fb32924 100644
--- a/src/test/pretty/path-type-bounds.rs
+++ b/src/test/pretty/path-type-bounds.rs
@@ -14,7 +14,7 @@
 trait Tr { }
 impl Tr for int { }
 
-fn foo(x: Box<Tr+ Sync>) -> Box<Tr+ Sync> { x }
+fn foo<'a>(x: Box<Tr+ Sync + 'a>) -> Box<Tr+ Sync + 'a> { x }
 
 fn main() {
     let x: Box<Tr+ Sync>;
diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
index a5239a6cc66..c5455ab90dc 100644
--- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
@@ -2,8 +2,10 @@ digraph block {
     N0[label="entry"];
     N1[label="exit"];
     N2[label="expr 1i"];
-    N3[label="block { 1i; }"];
+    N3[label="stmt 1i;"];
+    N4[label="block { 1i; }"];
     N0 -> N2;
     N2 -> N3;
-    N3 -> N1;
+    N3 -> N4;
+    N4 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
index ada3f091808..230dcbaeb98 100644
--- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
@@ -2,8 +2,10 @@ digraph block {
     N0[label="entry"];
     N1[label="exit"];
     N2[label="local _x"];
-    N3[label="block { let _x: int; }"];
+    N3[label="stmt let _x: int;"];
+    N4[label="block { let _x: int; }"];
     N0 -> N2;
     N2 -> N3;
-    N3 -> N1;
+    N3 -> N4;
+    N4 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
index 43462862f6e..e60d349ad14 100644
--- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
@@ -4,10 +4,12 @@ digraph block {
     N2[label="expr 3i"];
     N3[label="expr 33i"];
     N4[label="expr 3i + 33i"];
-    N5[label="block { 3i + 33i; }"];
+    N5[label="stmt 3i + 33i;"];
+    N6[label="block { 3i + 33i; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
-    N5 -> N1;
+    N5 -> N6;
+    N6 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
index 26c858a0828..82cdcb39fbf 100644
--- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
@@ -3,9 +3,11 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 4i"];
     N3[label="local _x"];
-    N4[label="block { let _x = 4i; }"];
+    N4[label="stmt let _x = 4i;"];
+    N5[label="block { let _x = 4i; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
-    N4 -> N1;
+    N4 -> N5;
+    N5 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
index 850d04f430f..8a27d536ffc 100644
--- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
@@ -7,7 +7,8 @@ digraph block {
     N5[label="local _x"];
     N6[label="local _y"];
     N7[label="pat (_x, _y)"];
-    N8[label="block { let (_x, _y) = (5i, 55i); }"];
+    N8[label="stmt let (_x, _y) = (5i, 55i);"];
+    N9[label="block { let (_x, _y) = (5i, 55i); }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -15,5 +16,6 @@ digraph block {
     N5 -> N6;
     N6 -> N7;
     N7 -> N8;
-    N8 -> N1;
+    N8 -> N9;
+    N9 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
index b431476f84a..54e9d89d3fb 100644
--- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
@@ -5,11 +5,13 @@ digraph block {
     N3[label="expr S6{val: 6,}"];
     N4[label="local _x"];
     N5[label="pat S6 { val: _x }"];
-    N6[label="block { let S6 { val: _x } = S6{val: 6,}; }"];
+    N6[label="stmt let S6 { val: _x } = S6{val: 6,};"];
+    N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
-    N6 -> N1;
+    N6 -> N7;
+    N7 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
index 2b7088fbc33..4c6383324e5 100644
--- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
@@ -15,7 +15,8 @@ digraph block {
     N13[label="expr x"];
     N14[label="expr y"];
     N15[label="expr x + y"];
-    N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"];
+    N16[label="stmt match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, };"];
+    N17[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -31,5 +32,6 @@ digraph block {
     N14 -> N15;
     N15 -> N7;
     N7 -> N16;
-    N16 -> N1;
+    N16 -> N17;
+    N17 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
index f43beb025e3..27a240ed182 100644
--- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
@@ -3,16 +3,19 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 8i"];
     N3[label="local x"];
-    N4[label="local _y"];
-    N5[label="expr x"];
-    N6[label="expr 88i"];
-    N7[label="expr x > 88i"];
-    N8[label="expr 888i"];
-    N9[label="expr _y"];
-    N10[label="expr _y = 888i"];
-    N11[label="block { _y = 888i; }"];
-    N12[label="expr if x > 88i { _y = 888i; }"];
-    N13[label="block { let x = 8i; let _y; if x > 88i { _y = 888i; } }"];
+    N4[label="stmt let x = 8i;"];
+    N5[label="local _y"];
+    N6[label="stmt let _y;"];
+    N7[label="expr x"];
+    N8[label="expr 88i"];
+    N9[label="expr x > 88i"];
+    N10[label="expr 888i"];
+    N11[label="expr _y"];
+    N12[label="expr _y = 888i"];
+    N13[label="stmt _y = 888i;"];
+    N14[label="block { _y = 888i; }"];
+    N15[label="expr if x > 88i { _y = 888i; }"];
+    N16[label="block { let x = 8i; let _y; if x > 88i { _y = 888i; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -23,8 +26,11 @@ digraph block {
     N8 -> N9;
     N9 -> N10;
     N10 -> N11;
-    N7 -> N12;
     N11 -> N12;
     N12 -> N13;
-    N13 -> N1;
+    N13 -> N14;
+    N9 -> N15;
+    N14 -> N15;
+    N15 -> N16;
+    N16 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
index a3576b9c36b..d2c58c6d59a 100644
--- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
@@ -3,23 +3,27 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 91i"];
     N3[label="local x"];
-    N4[label="local _y"];
-    N5[label="expr x"];
-    N6[label="expr 92i"];
-    N7[label="expr x > 92i"];
-    N8[label="expr 93i"];
-    N9[label="expr _y"];
-    N10[label="expr _y = 93i"];
-    N11[label="block { _y = 93i; }"];
-    N12[label="expr 94i"];
-    N13[label="expr 95i"];
-    N14[label="expr 94i + 95i"];
-    N15[label="expr _y"];
-    N16[label="expr _y = 94i + 95i"];
-    N17[label="block { _y = 94i + 95i; }"];
-    N18[label="expr { _y = 94i + 95i; }"];
-    N19[label="expr if x > 92i { _y = 93i; } else { _y = 94i + 95i; }"];
-    N20[label="block { let x = 91i; let _y; if x > 92i { _y = 93i; } else { _y = 94i + 95i; } }"];
+    N4[label="stmt let x = 91i;"];
+    N5[label="local _y"];
+    N6[label="stmt let _y;"];
+    N7[label="expr x"];
+    N8[label="expr 92i"];
+    N9[label="expr x > 92i"];
+    N10[label="expr 93i"];
+    N11[label="expr _y"];
+    N12[label="expr _y = 93i"];
+    N13[label="stmt _y = 93i;"];
+    N14[label="block { _y = 93i; }"];
+    N15[label="expr 94i"];
+    N16[label="expr 95i"];
+    N17[label="expr 94i + 95i"];
+    N18[label="expr _y"];
+    N19[label="expr _y = 94i + 95i"];
+    N20[label="stmt _y = 94i + 95i;"];
+    N21[label="block { _y = 94i + 95i; }"];
+    N22[label="expr { _y = 94i + 95i; }"];
+    N23[label="expr if x > 92i { _y = 93i; } else { _y = 94i + 95i; }"];
+    N24[label="block { let x = 91i; let _y; if x > 92i { _y = 93i; } else { _y = 94i + 95i; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -30,15 +34,19 @@ digraph block {
     N8 -> N9;
     N9 -> N10;
     N10 -> N11;
-    N7 -> N12;
+    N11 -> N12;
     N12 -> N13;
     N13 -> N14;
-    N14 -> N15;
+    N9 -> N15;
     N15 -> N16;
     N16 -> N17;
     N17 -> N18;
-    N11 -> N19;
     N18 -> N19;
     N19 -> N20;
-    N20 -> N1;
+    N20 -> N21;
+    N21 -> N22;
+    N14 -> N23;
+    N22 -> N23;
+    N23 -> N24;
+    N24 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
index 69b5bd6f58c..421a79fd136 100644
--- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
@@ -3,16 +3,18 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 10i"];
     N3[label="local mut x"];
-    N4[label="(dummy_node)"];
-    N5[label="expr x"];
-    N6[label="expr 0i"];
-    N7[label="expr x > 0i"];
-    N8[label="expr while x > 0i { x -= 1i; }"];
-    N9[label="expr 1i"];
-    N10[label="expr x"];
-    N11[label="expr x -= 1i"];
-    N12[label="block { x -= 1i; }"];
-    N13[label="block { let mut x = 10i; while x > 0i { x -= 1i; } }"];
+    N4[label="stmt let mut x = 10i;"];
+    N5[label="(dummy_node)"];
+    N6[label="expr x"];
+    N7[label="expr 0i"];
+    N8[label="expr x > 0i"];
+    N9[label="expr while x > 0i { x -= 1i; }"];
+    N10[label="expr 1i"];
+    N11[label="expr x"];
+    N12[label="expr x -= 1i"];
+    N13[label="stmt x -= 1i;"];
+    N14[label="block { x -= 1i; }"];
+    N15[label="block { let mut x = 10i; while x > 0i { x -= 1i; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -20,11 +22,13 @@ digraph block {
     N5 -> N6;
     N6 -> N7;
     N7 -> N8;
-    N7 -> N9;
-    N9 -> N10;
+    N8 -> N9;
+    N8 -> N10;
     N10 -> N11;
     N11 -> N12;
-    N12 -> N4;
-    N8 -> N13;
-    N13 -> N1;
+    N12 -> N13;
+    N13 -> N14;
+    N14 -> N5;
+    N9 -> N15;
+    N15 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
index 44024cf76f3..b928058fed9 100644
--- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
@@ -3,23 +3,31 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 11i"];
     N3[label="local mut _x"];
-    N4[label="(dummy_node)"];
-    N5[label="expr loop  { _x -= 1i; }"];
-    N6[label="expr 1i"];
-    N7[label="expr _x"];
-    N8[label="expr _x -= 1i"];
-    N9[label="block { _x -= 1i; }"];
-    N10[label="expr \"unreachable\""];
-    N11[label="block { let mut _x = 11i; loop  { _x -= 1i; } \"unreachable\"; }"];
+    N4[label="stmt let mut _x = 11i;"];
+    N5[label="(dummy_node)"];
+    N6[label="expr loop  { _x -= 1i; }"];
+    N7[label="expr 1i"];
+    N8[label="expr _x"];
+    N9[label="expr _x -= 1i"];
+    N10[label="stmt _x -= 1i;"];
+    N11[label="block { _x -= 1i; }"];
+    N12[label="stmt loop  { _x -= 1i; }"];
+    N13[label="expr \"unreachable\""];
+    N14[label="stmt \"unreachable\";"];
+    N15[label="block { let mut _x = 11i; loop  { _x -= 1i; } \"unreachable\"; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
-    N4 -> N6;
-    N6 -> N7;
+    N4 -> N5;
+    N5 -> N7;
     N7 -> N8;
     N8 -> N9;
-    N9 -> N4;
-    N5 -> N10;
+    N9 -> N10;
     N10 -> N11;
-    N11 -> N1;
+    N11 -> N5;
+    N6 -> N12;
+    N12 -> N13;
+    N13 -> N14;
+    N14 -> N15;
+    N15 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
index ad257c19741..d89a37308de 100644
--- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
@@ -3,38 +3,46 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 12i"];
     N3[label="local mut x"];
-    N4[label="(dummy_node)"];
-    N5[label="expr loop  { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"];
-    N6[label="expr 1i"];
-    N7[label="expr x"];
-    N8[label="expr x -= 1i"];
-    N9[label="expr x"];
-    N10[label="expr 2i"];
-    N11[label="expr x == 2i"];
-    N12[label="expr break"];
-    N13[label="(dummy_node)"];
-    N14[label="expr \"unreachable\""];
-    N15[label="block { break ; \"unreachable\"; }"];
-    N16[label="expr if x == 2i { break ; \"unreachable\"; }"];
-    N17[label="block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"];
-    N18[label="block { let mut x = 12i; loop  { x -= 1i; if x == 2i { break ; \"unreachable\"; } } }"];
+    N4[label="stmt let mut x = 12i;"];
+    N5[label="(dummy_node)"];
+    N6[label="expr loop  { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"];
+    N7[label="expr 1i"];
+    N8[label="expr x"];
+    N9[label="expr x -= 1i"];
+    N10[label="stmt x -= 1i;"];
+    N11[label="expr x"];
+    N12[label="expr 2i"];
+    N13[label="expr x == 2i"];
+    N14[label="expr break"];
+    N15[label="(dummy_node)"];
+    N16[label="stmt break ;"];
+    N17[label="expr \"unreachable\""];
+    N18[label="stmt \"unreachable\";"];
+    N19[label="block { break ; \"unreachable\"; }"];
+    N20[label="expr if x == 2i { break ; \"unreachable\"; }"];
+    N21[label="block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"];
+    N22[label="block { let mut x = 12i; loop  { x -= 1i; if x == 2i { break ; \"unreachable\"; } } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
-    N4 -> N6;
-    N6 -> N7;
+    N4 -> N5;
+    N5 -> N7;
     N7 -> N8;
     N8 -> N9;
     N9 -> N10;
     N10 -> N11;
     N11 -> N12;
-    N12 -> N5[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2i { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"];
+    N12 -> N13;
     N13 -> N14;
-    N14 -> N15;
-    N11 -> N16;
+    N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2i { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"];
     N15 -> N16;
     N16 -> N17;
-    N17 -> N4;
-    N5 -> N18;
-    N18 -> N1;
+    N17 -> N18;
+    N18 -> N19;
+    N13 -> N20;
+    N19 -> N20;
+    N20 -> N21;
+    N21 -> N5;
+    N6 -> N22;
+    N22 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
index 5d1d1253b22..aa43ef51534 100644
--- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
@@ -5,44 +5,48 @@ digraph block {
     N3[label="expr 13"];
     N4[label="expr E13b(13)"];
     N5[label="local x"];
-    N6[label="local _y"];
-    N7[label="expr x"];
-    N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1, }"];
-    N9[label="(dummy_node)"];
-    N10[label="local E13a"];
-    N11[label="expr 1"];
-    N12[label="expr _y"];
-    N13[label="expr _y = 1"];
-    N14[label="(dummy_node)"];
-    N15[label="local v"];
-    N16[label="pat E13b(v)"];
-    N17[label="expr v"];
-    N18[label="expr 1"];
-    N19[label="expr v + 1"];
-    N20[label="expr _y"];
-    N21[label="expr _y = v + 1"];
-    N22[label="block {\l    let x = E13b(13);\l    let _y;\l    match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"];
+    N6[label="stmt let x = E13b(13);"];
+    N7[label="local _y"];
+    N8[label="stmt let _y;"];
+    N9[label="expr x"];
+    N10[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1, }"];
+    N11[label="(dummy_node)"];
+    N12[label="local E13a"];
+    N13[label="expr 1"];
+    N14[label="expr _y"];
+    N15[label="expr _y = 1"];
+    N16[label="(dummy_node)"];
+    N17[label="local v"];
+    N18[label="pat E13b(v)"];
+    N19[label="expr v"];
+    N20[label="expr 1"];
+    N21[label="expr v + 1"];
+    N22[label="expr _y"];
+    N23[label="expr _y = v + 1"];
+    N24[label="block {\l    let x = E13b(13);\l    let _y;\l    match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
     N6 -> N7;
-    N7 -> N9;
-    N9 -> N10;
-    N10 -> N11;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N11;
     N11 -> N12;
     N12 -> N13;
-    N13 -> N8;
-    N9 -> N14;
+    N13 -> N14;
     N14 -> N15;
-    N15 -> N16;
+    N15 -> N10;
+    N11 -> N16;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
     N20 -> N21;
-    N21 -> N8;
-    N8 -> N22;
-    N22 -> N1;
+    N21 -> N22;
+    N22 -> N23;
+    N23 -> N10;
+    N10 -> N24;
+    N24 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
index f8e4bd12bb0..bdb2c133bad 100644
--- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
@@ -3,26 +3,32 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 14i"];
     N3[label="local x"];
-    N4[label="expr x"];
-    N5[label="expr 1i"];
-    N6[label="expr x > 1i"];
-    N7[label="expr return"];
-    N8[label="(dummy_node)"];
-    N9[label="expr \"unreachable\""];
-    N10[label="block { return; \"unreachable\"; }"];
-    N11[label="expr if x > 1i { return; \"unreachable\"; }"];
-    N12[label="block { let x = 14i; if x > 1i { return; \"unreachable\"; } }"];
+    N4[label="stmt let x = 14i;"];
+    N5[label="expr x"];
+    N6[label="expr 1i"];
+    N7[label="expr x > 1i"];
+    N8[label="expr return"];
+    N9[label="(dummy_node)"];
+    N10[label="stmt return;"];
+    N11[label="expr \"unreachable\""];
+    N12[label="stmt \"unreachable\";"];
+    N13[label="block { return; \"unreachable\"; }"];
+    N14[label="expr if x > 1i { return; \"unreachable\"; }"];
+    N15[label="block { let x = 14i; if x > 1i { return; \"unreachable\"; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
     N6 -> N7;
-    N7 -> N1;
-    N8 -> N9;
+    N7 -> N8;
+    N8 -> N1;
     N9 -> N10;
-    N6 -> N11;
     N10 -> N11;
     N11 -> N12;
-    N12 -> N1;
+    N12 -> N13;
+    N7 -> N14;
+    N13 -> N14;
+    N14 -> N15;
+    N15 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
index 77ee0df5512..4bd9fc9ec1a 100644
--- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
@@ -3,77 +3,101 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 15i"];
     N3[label="local mut x"];
-    N4[label="expr 151i"];
-    N5[label="local mut y"];
-    N6[label="(dummy_node)"];
-    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { break \'outer ; \"unreachable\"; }\l                if y >= 2i { break ; \"unreachable\"; }\l                y -= 3i;\l            }\l        y -= 4i;\l        x -= 5i;\l    }\l"];
+    N4[label="stmt let mut x = 15i;"];
+    N5[label="expr 151i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 151i;"];
     N8[label="(dummy_node)"];
-    N9[label="expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l"];
-    N10[label="expr x"];
-    N11[label="expr 1i"];
-    N12[label="expr x == 1i"];
-    N13[label="expr break \'outer"];
-    N14[label="(dummy_node)"];
-    N15[label="expr \"unreachable\""];
-    N16[label="block { break \'outer ; \"unreachable\"; }"];
-    N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"];
-    N18[label="expr y"];
-    N19[label="expr 2i"];
-    N20[label="expr y >= 2i"];
-    N21[label="expr break"];
-    N22[label="(dummy_node)"];
-    N23[label="expr \"unreachable\""];
-    N24[label="block { break ; \"unreachable\"; }"];
-    N25[label="expr if y >= 2i { break ; \"unreachable\"; }"];
-    N26[label="expr 3i"];
-    N27[label="expr y"];
-    N28[label="expr y -= 3i"];
-    N29[label="block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { break ; \"unreachable\"; }\l    y -= 3i;\l}\l"];
-    N30[label="expr 4i"];
-    N31[label="expr y"];
-    N32[label="expr y -= 4i"];
-    N33[label="expr 5i"];
-    N34[label="expr x"];
-    N35[label="expr x -= 5i"];
-    N36[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { break ; \"unreachable\"; }\l            y -= 3i;\l        }\l    y -= 4i;\l    x -= 5i;\l}\l"];
-    N37[label="block {\l    let mut x = 15i;\l    let mut y = 151i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { break \'outer ; \"unreachable\"; }\l                    if y >= 2i { break ; \"unreachable\"; }\l                    y -= 3i;\l                }\l            y -= 4i;\l            x -= 5i;\l        }\l}\l"];
+    N9[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { break \'outer ; \"unreachable\"; }\l                if y >= 2i { break ; \"unreachable\"; }\l                y -= 3i;\l            }\l        y -= 4i;\l        x -= 5i;\l    }\l"];
+    N10[label="(dummy_node)"];
+    N11[label="expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l"];
+    N12[label="expr x"];
+    N13[label="expr 1i"];
+    N14[label="expr x == 1i"];
+    N15[label="expr break \'outer"];
+    N16[label="(dummy_node)"];
+    N17[label="stmt break \'outer ;"];
+    N18[label="expr \"unreachable\""];
+    N19[label="stmt \"unreachable\";"];
+    N20[label="block { break \'outer ; \"unreachable\"; }"];
+    N21[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"];
+    N22[label="stmt if x == 1i { break \'outer ; \"unreachable\"; }"];
+    N23[label="expr y"];
+    N24[label="expr 2i"];
+    N25[label="expr y >= 2i"];
+    N26[label="expr break"];
+    N27[label="(dummy_node)"];
+    N28[label="stmt break ;"];
+    N29[label="expr \"unreachable\""];
+    N30[label="stmt \"unreachable\";"];
+    N31[label="block { break ; \"unreachable\"; }"];
+    N32[label="expr if y >= 2i { break ; \"unreachable\"; }"];
+    N33[label="stmt if y >= 2i { break ; \"unreachable\"; }"];
+    N34[label="expr 3i"];
+    N35[label="expr y"];
+    N36[label="expr y -= 3i"];
+    N37[label="stmt y -= 3i;"];
+    N38[label="block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { break ; \"unreachable\"; }\l    y -= 3i;\l}\l"];
+    N39[label="stmt \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l"];
+    N40[label="expr 4i"];
+    N41[label="expr y"];
+    N42[label="expr y -= 4i"];
+    N43[label="stmt y -= 4i;"];
+    N44[label="expr 5i"];
+    N45[label="expr x"];
+    N46[label="expr x -= 5i"];
+    N47[label="stmt x -= 5i;"];
+    N48[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { break ; \"unreachable\"; }\l            y -= 3i;\l        }\l    y -= 4i;\l    x -= 5i;\l}\l"];
+    N49[label="block {\l    let mut x = 15i;\l    let mut y = 151i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { break \'outer ; \"unreachable\"; }\l                    if y >= 2i { break ; \"unreachable\"; }\l                    y -= 3i;\l                }\l            y -= 4i;\l            x -= 5i;\l        }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
-    N6 -> N8;
+    N6 -> N7;
+    N7 -> N8;
     N8 -> N10;
-    N10 -> N11;
-    N11 -> N12;
+    N10 -> N12;
     N12 -> N13;
-    N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { break ; \"unreachable\"; }\l    y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { break ; \"unreachable\"; }\l            y -= 3i;\l        }\l    y -= 4i;\l    x -= 5i;\l}\l"];
+    N13 -> N14;
     N14 -> N15;
-    N15 -> N16;
-    N12 -> N17;
+    N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { break ; \"unreachable\"; }\l    y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { break ; \"unreachable\"; }\l        y -= 3i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { break ; \"unreachable\"; }\l            y -= 3i;\l        }\l    y -= 4i;\l    x -= 5i;\l}\l"];
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
+    N14 -> N21;
     N20 -> N21;
-    N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { break ; \"unreachable\"; }\l    y -= 3i;\l}\l"];
+    N21 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N20 -> N25;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N27;
+    N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { break ; \"unreachable\"; }\l    y -= 3i;\l}\l"];
     N27 -> N28;
     N28 -> N29;
-    N29 -> N8;
-    N9 -> N30;
+    N29 -> N30;
     N30 -> N31;
+    N25 -> N32;
     N31 -> N32;
     N32 -> N33;
     N33 -> N34;
     N34 -> N35;
     N35 -> N36;
-    N36 -> N6;
-    N7 -> N37;
-    N37 -> N1;
+    N36 -> N37;
+    N37 -> N38;
+    N38 -> N10;
+    N11 -> N39;
+    N39 -> N40;
+    N40 -> N41;
+    N41 -> N42;
+    N42 -> N43;
+    N43 -> N44;
+    N44 -> N45;
+    N45 -> N46;
+    N46 -> N47;
+    N47 -> N48;
+    N48 -> N8;
+    N9 -> N49;
+    N49 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
index b5a867e6029..16b871bd844 100644
--- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
@@ -3,79 +3,107 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 16i"];
     N3[label="local mut x"];
-    N4[label="expr 16i"];
-    N5[label="local mut y"];
-    N6[label="(dummy_node)"];
-    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 1i { break ; \"unreachable\"; }\l                y -= 1i;\l            }\l        y -= 1i;\l        x -= 1i;\l    }\l"];
+    N4[label="stmt let mut x = 16i;"];
+    N5[label="expr 16i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 16i;"];
     N8[label="(dummy_node)"];
-    N9[label="expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l"];
-    N10[label="expr x"];
-    N11[label="expr 1i"];
-    N12[label="expr x == 1i"];
-    N13[label="expr continue \'outer"];
-    N14[label="(dummy_node)"];
-    N15[label="expr \"unreachable\""];
-    N16[label="block { continue \'outer ; \"unreachable\"; }"];
-    N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"];
-    N18[label="expr y"];
-    N19[label="expr 1i"];
-    N20[label="expr y >= 1i"];
-    N21[label="expr break"];
-    N22[label="(dummy_node)"];
-    N23[label="expr \"unreachable\""];
-    N24[label="block { break ; \"unreachable\"; }"];
-    N25[label="expr if y >= 1i { break ; \"unreachable\"; }"];
-    N26[label="expr 1i"];
-    N27[label="expr y"];
-    N28[label="expr y -= 1i"];
-    N29[label="block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 1i { break ; \"unreachable\"; }\l    y -= 1i;\l}\l"];
-    N30[label="expr 1i"];
-    N31[label="expr y"];
-    N32[label="expr y -= 1i"];
-    N33[label="expr 1i"];
-    N34[label="expr x"];
-    N35[label="expr x -= 1i"];
-    N36[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 1i { break ; \"unreachable\"; }\l            y -= 1i;\l        }\l    y -= 1i;\l    x -= 1i;\l}\l"];
-    N37[label="expr \"unreachable\""];
-    N38[label="block {\l    let mut x = 16i;\l    let mut y = 16i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { continue \'outer ; \"unreachable\"; }\l                    if y >= 1i { break ; \"unreachable\"; }\l                    y -= 1i;\l                }\l            y -= 1i;\l            x -= 1i;\l        }\l    \"unreachable\";\l}\l"];
+    N9[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 1i { break ; \"unreachable\"; }\l                y -= 1i;\l            }\l        y -= 1i;\l        x -= 1i;\l    }\l"];
+    N10[label="(dummy_node)"];
+    N11[label="expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l"];
+    N12[label="expr x"];
+    N13[label="expr 1i"];
+    N14[label="expr x == 1i"];
+    N15[label="expr continue \'outer"];
+    N16[label="(dummy_node)"];
+    N17[label="stmt continue \'outer ;"];
+    N18[label="expr \"unreachable\""];
+    N19[label="stmt \"unreachable\";"];
+    N20[label="block { continue \'outer ; \"unreachable\"; }"];
+    N21[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"];
+    N22[label="stmt if x == 1i { continue \'outer ; \"unreachable\"; }"];
+    N23[label="expr y"];
+    N24[label="expr 1i"];
+    N25[label="expr y >= 1i"];
+    N26[label="expr break"];
+    N27[label="(dummy_node)"];
+    N28[label="stmt break ;"];
+    N29[label="expr \"unreachable\""];
+    N30[label="stmt \"unreachable\";"];
+    N31[label="block { break ; \"unreachable\"; }"];
+    N32[label="expr if y >= 1i { break ; \"unreachable\"; }"];
+    N33[label="stmt if y >= 1i { break ; \"unreachable\"; }"];
+    N34[label="expr 1i"];
+    N35[label="expr y"];
+    N36[label="expr y -= 1i"];
+    N37[label="stmt y -= 1i;"];
+    N38[label="block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 1i { break ; \"unreachable\"; }\l    y -= 1i;\l}\l"];
+    N39[label="stmt \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l"];
+    N40[label="expr 1i"];
+    N41[label="expr y"];
+    N42[label="expr y -= 1i"];
+    N43[label="stmt y -= 1i;"];
+    N44[label="expr 1i"];
+    N45[label="expr x"];
+    N46[label="expr x -= 1i"];
+    N47[label="stmt x -= 1i;"];
+    N48[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 1i { break ; \"unreachable\"; }\l            y -= 1i;\l        }\l    y -= 1i;\l    x -= 1i;\l}\l"];
+    N49[label="stmt \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 1i { break ; \"unreachable\"; }\l                y -= 1i;\l            }\l        y -= 1i;\l        x -= 1i;\l    }\l"];
+    N50[label="expr \"unreachable\""];
+    N51[label="stmt \"unreachable\";"];
+    N52[label="block {\l    let mut x = 16i;\l    let mut y = 16i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { continue \'outer ; \"unreachable\"; }\l                    if y >= 1i { break ; \"unreachable\"; }\l                    y -= 1i;\l                }\l            y -= 1i;\l            x -= 1i;\l        }\l    \"unreachable\";\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
-    N6 -> N8;
+    N6 -> N7;
+    N7 -> N8;
     N8 -> N10;
-    N10 -> N11;
-    N11 -> N12;
+    N10 -> N12;
     N12 -> N13;
-    N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 1i { break ; \"unreachable\"; }\l    y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 1i { break ; \"unreachable\"; }\l            y -= 1i;\l        }\l    y -= 1i;\l    x -= 1i;\l}\l"];
+    N13 -> N14;
     N14 -> N15;
-    N15 -> N16;
-    N12 -> N17;
+    N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 1i { break ; \"unreachable\"; }\l    y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 1i { break ; \"unreachable\"; }\l        y -= 1i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 1i { break ; \"unreachable\"; }\l            y -= 1i;\l        }\l    y -= 1i;\l    x -= 1i;\l}\l"];
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
+    N14 -> N21;
     N20 -> N21;
-    N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 1i { break ; \"unreachable\"; }\l    y -= 1i;\l}\l"];
+    N21 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N20 -> N25;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N27;
+    N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 1i { break ; \"unreachable\"; }\l    y -= 1i;\l}\l"];
     N27 -> N28;
     N28 -> N29;
-    N29 -> N8;
-    N9 -> N30;
+    N29 -> N30;
     N30 -> N31;
+    N25 -> N32;
     N31 -> N32;
     N32 -> N33;
     N33 -> N34;
     N34 -> N35;
     N35 -> N36;
-    N36 -> N6;
-    N7 -> N37;
+    N36 -> N37;
     N37 -> N38;
-    N38 -> N1;
+    N38 -> N10;
+    N11 -> N39;
+    N39 -> N40;
+    N40 -> N41;
+    N41 -> N42;
+    N42 -> N43;
+    N43 -> N44;
+    N44 -> N45;
+    N45 -> N46;
+    N46 -> N47;
+    N47 -> N48;
+    N48 -> N8;
+    N9 -> N49;
+    N49 -> N50;
+    N50 -> N51;
+    N51 -> N52;
+    N52 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
index d3e098a71f2..c78224c00df 100644
--- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
@@ -6,12 +6,14 @@ digraph block {
     N4[label="expr 17i"];
     N5[label="expr [1i, 7i, 17i]"];
     N6[label="local _v"];
-    N7[label="block { let _v = [1i, 7i, 17i]; }"];
+    N7[label="stmt let _v = [1i, 7i, 17i];"];
+    N8[label="block { let _v = [1i, 7i, 17i]; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
     N6 -> N7;
-    N7 -> N1;
+    N7 -> N8;
+    N8 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
index 6345b4effaf..c4a39a519ed 100644
--- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
@@ -1,17 +1,21 @@
 digraph block {
     N0[label="entry"];
     N1[label="exit"];
-    N2[label="expr inner"];
+    N2[label="stmt fn inner(x: int) -> int { x + x }"];
     N3[label="expr inner"];
-    N4[label="expr 18"];
-    N5[label="expr inner(18)"];
-    N6[label="expr inner(inner(18))"];
-    N7[label="block {\l    fn inner(x: int) -> int { x + x }\l    inner(inner(18));\l}\l"];
+    N4[label="expr inner"];
+    N5[label="expr 18"];
+    N6[label="expr inner(18)"];
+    N7[label="expr inner(inner(18))"];
+    N8[label="stmt inner(inner(18));"];
+    N9[label="block {\l    fn inner(x: int) -> int { x + x }\l    inner(inner(18));\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
     N6 -> N7;
-    N7 -> N1;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
index 5fad18536e5..8d21ef80917 100644
--- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
@@ -1,13 +1,17 @@
 digraph block {
     N0[label="entry"];
     N1[label="exit"];
-    N2[label="expr 19"];
-    N3[label="expr S19{x: 19,}"];
-    N4[label="local s"];
-    N5[label="expr s"];
-    N6[label="expr s.inner()"];
-    N7[label="expr s.inner().inner()"];
-    N8[label="block {\l    struct S19 {\l        x: int,\l    }\l    impl S19 {\l        fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l    }\l    let s = S19{x: 19,};\l    s.inner().inner();\l}\l"];
+    N2[label="stmt struct S19 {\l    x: int,\l}\l"];
+    N3[label="stmt impl S19 {\l    fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l}\l"];
+    N4[label="expr 19"];
+    N5[label="expr S19{x: 19,}"];
+    N6[label="local s"];
+    N7[label="stmt let s = S19{x: 19,};"];
+    N8[label="expr s"];
+    N9[label="expr s.inner()"];
+    N10[label="expr s.inner().inner()"];
+    N11[label="stmt s.inner().inner();"];
+    N12[label="block {\l    struct S19 {\l        x: int,\l    }\l    impl S19 {\l        fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l    }\l    let s = S19{x: 19,};\l    s.inner().inner();\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -15,5 +19,9 @@ digraph block {
     N5 -> N6;
     N6 -> N7;
     N7 -> N8;
-    N8 -> N1;
+    N8 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
index 716ec469fb0..a625a1a0026 100644
--- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
@@ -6,10 +6,12 @@ digraph block {
     N4[label="expr 20u"];
     N5[label="expr [2u, 0u, 20u]"];
     N6[label="local v"];
-    N7[label="expr v"];
-    N8[label="expr 20u"];
-    N9[label="expr v[20u]"];
-    N10[label="block { let v = [2u, 0u, 20u]; v[20u]; }"];
+    N7[label="stmt let v = [2u, 0u, 20u];"];
+    N8[label="expr v"];
+    N9[label="expr 20u"];
+    N10[label="expr v[20u]"];
+    N11[label="stmt v[20u];"];
+    N12[label="block { let v = [2u, 0u, 20u]; v[20u]; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -19,5 +21,7 @@ digraph block {
     N7 -> N8;
     N8 -> N9;
     N9 -> N10;
-    N10 -> N1;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
index 2bbc3e7e5c8..ad2ef60ce29 100644
--- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
@@ -3,73 +3,97 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 15i"];
     N3[label="local mut x"];
-    N4[label="expr 151i"];
-    N5[label="local mut y"];
-    N6[label="(dummy_node)"];
-    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { break \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                y -= 3i;\l                x -= 5i;\l            }\l        \"unreachable\";\l    }\l"];
+    N4[label="stmt let mut x = 15i;"];
+    N5[label="expr 151i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 151i;"];
     N8[label="(dummy_node)"];
-    N9[label="expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l"];
-    N10[label="expr x"];
-    N11[label="expr 1i"];
-    N12[label="expr x == 1i"];
-    N13[label="expr break \'outer"];
-    N14[label="(dummy_node)"];
-    N15[label="expr \"unreachable\""];
-    N16[label="block { break \'outer ; \"unreachable\"; }"];
-    N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"];
-    N18[label="expr y"];
-    N19[label="expr 2i"];
-    N20[label="expr y >= 2i"];
-    N21[label="expr return"];
-    N22[label="(dummy_node)"];
-    N23[label="expr \"unreachable\""];
-    N24[label="block { return; \"unreachable\"; }"];
-    N25[label="expr if y >= 2i { return; \"unreachable\"; }"];
-    N26[label="expr 3i"];
-    N27[label="expr y"];
-    N28[label="expr y -= 3i"];
-    N29[label="expr 5i"];
-    N30[label="expr x"];
-    N31[label="expr x -= 5i"];
-    N32[label="block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    y -= 3i;\l    x -= 5i;\l}\l"];
-    N33[label="expr \"unreachable\""];
-    N34[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            y -= 3i;\l            x -= 5i;\l        }\l    \"unreachable\";\l}\l"];
-    N35[label="block {\l    let mut x = 15i;\l    let mut y = 151i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { break \'outer ; \"unreachable\"; }\l                    if y >= 2i { return; \"unreachable\"; }\l                    y -= 3i;\l                    x -= 5i;\l                }\l            \"unreachable\";\l        }\l}\l"];
+    N9[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { break \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                y -= 3i;\l                x -= 5i;\l            }\l        \"unreachable\";\l    }\l"];
+    N10[label="(dummy_node)"];
+    N11[label="expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l"];
+    N12[label="expr x"];
+    N13[label="expr 1i"];
+    N14[label="expr x == 1i"];
+    N15[label="expr break \'outer"];
+    N16[label="(dummy_node)"];
+    N17[label="stmt break \'outer ;"];
+    N18[label="expr \"unreachable\""];
+    N19[label="stmt \"unreachable\";"];
+    N20[label="block { break \'outer ; \"unreachable\"; }"];
+    N21[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"];
+    N22[label="stmt if x == 1i { break \'outer ; \"unreachable\"; }"];
+    N23[label="expr y"];
+    N24[label="expr 2i"];
+    N25[label="expr y >= 2i"];
+    N26[label="expr return"];
+    N27[label="(dummy_node)"];
+    N28[label="stmt return;"];
+    N29[label="expr \"unreachable\""];
+    N30[label="stmt \"unreachable\";"];
+    N31[label="block { return; \"unreachable\"; }"];
+    N32[label="expr if y >= 2i { return; \"unreachable\"; }"];
+    N33[label="stmt if y >= 2i { return; \"unreachable\"; }"];
+    N34[label="expr 3i"];
+    N35[label="expr y"];
+    N36[label="expr y -= 3i"];
+    N37[label="stmt y -= 3i;"];
+    N38[label="expr 5i"];
+    N39[label="expr x"];
+    N40[label="expr x -= 5i"];
+    N41[label="stmt x -= 5i;"];
+    N42[label="block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    y -= 3i;\l    x -= 5i;\l}\l"];
+    N43[label="stmt \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l"];
+    N44[label="expr \"unreachable\""];
+    N45[label="stmt \"unreachable\";"];
+    N46[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            y -= 3i;\l            x -= 5i;\l        }\l    \"unreachable\";\l}\l"];
+    N47[label="block {\l    let mut x = 15i;\l    let mut y = 151i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { break \'outer ; \"unreachable\"; }\l                    if y >= 2i { return; \"unreachable\"; }\l                    y -= 3i;\l                    x -= 5i;\l                }\l            \"unreachable\";\l        }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
-    N6 -> N8;
+    N6 -> N7;
+    N7 -> N8;
     N8 -> N10;
-    N10 -> N11;
-    N11 -> N12;
+    N10 -> N12;
     N12 -> N13;
-    N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    y -= 3i;\l    x -= 5i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            y -= 3i;\l            x -= 5i;\l        }\l    \"unreachable\";\l}\l"];
+    N13 -> N14;
     N14 -> N15;
-    N15 -> N16;
-    N12 -> N17;
+    N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { break \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    y -= 3i;\l    x -= 5i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { break \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            y -= 3i;\l            x -= 5i;\l        }\l    \"unreachable\";\l}\l"];
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
+    N14 -> N21;
     N20 -> N21;
-    N21 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { break \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                y -= 3i;\l                x -= 5i;\l            }\l        \"unreachable\";\l    }\l"];
+    N21 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N20 -> N25;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N27;
+    N26 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1i { break \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        y -= 3i;\l        x -= 5i;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { break \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                y -= 3i;\l                x -= 5i;\l            }\l        \"unreachable\";\l    }\l"];
     N27 -> N28;
     N28 -> N29;
     N29 -> N30;
     N30 -> N31;
+    N25 -> N32;
     N31 -> N32;
-    N32 -> N8;
-    N9 -> N33;
+    N32 -> N33;
     N33 -> N34;
-    N34 -> N6;
-    N7 -> N35;
-    N35 -> N1;
+    N34 -> N35;
+    N35 -> N36;
+    N36 -> N37;
+    N37 -> N38;
+    N38 -> N39;
+    N39 -> N40;
+    N40 -> N41;
+    N41 -> N42;
+    N42 -> N10;
+    N11 -> N43;
+    N43 -> N44;
+    N44 -> N45;
+    N45 -> N46;
+    N46 -> N8;
+    N9 -> N47;
+    N47 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
index 8ecddba21fc..dcceb5bb937 100644
--- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
@@ -3,75 +3,103 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 15i"];
     N3[label="local mut x"];
-    N4[label="expr 151i"];
-    N5[label="local mut y"];
-    N6[label="(dummy_node)"];
-    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                x -= 1i;\l                y -= 3i;\l            }\l        \"unreachable\";\l    }\l"];
+    N4[label="stmt let mut x = 15i;"];
+    N5[label="expr 151i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 151i;"];
     N8[label="(dummy_node)"];
-    N9[label="expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l"];
-    N10[label="expr x"];
-    N11[label="expr 1i"];
-    N12[label="expr x == 1i"];
-    N13[label="expr continue \'outer"];
-    N14[label="(dummy_node)"];
-    N15[label="expr \"unreachable\""];
-    N16[label="block { continue \'outer ; \"unreachable\"; }"];
-    N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"];
-    N18[label="expr y"];
-    N19[label="expr 2i"];
-    N20[label="expr y >= 2i"];
-    N21[label="expr return"];
-    N22[label="(dummy_node)"];
-    N23[label="expr \"unreachable\""];
-    N24[label="block { return; \"unreachable\"; }"];
-    N25[label="expr if y >= 2i { return; \"unreachable\"; }"];
-    N26[label="expr 1i"];
-    N27[label="expr x"];
-    N28[label="expr x -= 1i"];
-    N29[label="expr 3i"];
-    N30[label="expr y"];
-    N31[label="expr y -= 3i"];
-    N32[label="block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    x -= 1i;\l    y -= 3i;\l}\l"];
-    N33[label="expr \"unreachable\""];
-    N34[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            x -= 1i;\l            y -= 3i;\l        }\l    \"unreachable\";\l}\l"];
-    N35[label="expr \"unreachable\""];
-    N36[label="block {\l    let mut x = 15i;\l    let mut y = 151i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { continue \'outer ; \"unreachable\"; }\l                    if y >= 2i { return; \"unreachable\"; }\l                    x -= 1i;\l                    y -= 3i;\l                }\l            \"unreachable\";\l        }\l    \"unreachable\";\l}\l"];
+    N9[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                x -= 1i;\l                y -= 3i;\l            }\l        \"unreachable\";\l    }\l"];
+    N10[label="(dummy_node)"];
+    N11[label="expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l"];
+    N12[label="expr x"];
+    N13[label="expr 1i"];
+    N14[label="expr x == 1i"];
+    N15[label="expr continue \'outer"];
+    N16[label="(dummy_node)"];
+    N17[label="stmt continue \'outer ;"];
+    N18[label="expr \"unreachable\""];
+    N19[label="stmt \"unreachable\";"];
+    N20[label="block { continue \'outer ; \"unreachable\"; }"];
+    N21[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"];
+    N22[label="stmt if x == 1i { continue \'outer ; \"unreachable\"; }"];
+    N23[label="expr y"];
+    N24[label="expr 2i"];
+    N25[label="expr y >= 2i"];
+    N26[label="expr return"];
+    N27[label="(dummy_node)"];
+    N28[label="stmt return;"];
+    N29[label="expr \"unreachable\""];
+    N30[label="stmt \"unreachable\";"];
+    N31[label="block { return; \"unreachable\"; }"];
+    N32[label="expr if y >= 2i { return; \"unreachable\"; }"];
+    N33[label="stmt if y >= 2i { return; \"unreachable\"; }"];
+    N34[label="expr 1i"];
+    N35[label="expr x"];
+    N36[label="expr x -= 1i"];
+    N37[label="stmt x -= 1i;"];
+    N38[label="expr 3i"];
+    N39[label="expr y"];
+    N40[label="expr y -= 3i"];
+    N41[label="stmt y -= 3i;"];
+    N42[label="block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    x -= 1i;\l    y -= 3i;\l}\l"];
+    N43[label="stmt \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l"];
+    N44[label="expr \"unreachable\""];
+    N45[label="stmt \"unreachable\";"];
+    N46[label="block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            x -= 1i;\l            y -= 3i;\l        }\l    \"unreachable\";\l}\l"];
+    N47[label="stmt \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                x -= 1i;\l                y -= 3i;\l            }\l        \"unreachable\";\l    }\l"];
+    N48[label="expr \"unreachable\""];
+    N49[label="stmt \"unreachable\";"];
+    N50[label="block {\l    let mut x = 15i;\l    let mut y = 151i;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1i { continue \'outer ; \"unreachable\"; }\l                    if y >= 2i { return; \"unreachable\"; }\l                    x -= 1i;\l                    y -= 3i;\l                }\l            \"unreachable\";\l        }\l    \"unreachable\";\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
-    N6 -> N8;
+    N6 -> N7;
+    N7 -> N8;
     N8 -> N10;
-    N10 -> N11;
-    N11 -> N12;
+    N10 -> N12;
     N12 -> N13;
-    N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    x -= 1i;\l    y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            x -= 1i;\l            y -= 3i;\l        }\l    \"unreachable\";\l}\l"];
+    N13 -> N14;
     N14 -> N15;
-    N15 -> N16;
-    N12 -> N17;
+    N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1i { continue \'outer ; \"unreachable\"; }\l    if y >= 2i { return; \"unreachable\"; }\l    x -= 1i;\l    y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1i { continue \'outer ; \"unreachable\"; }\l            if y >= 2i { return; \"unreachable\"; }\l            x -= 1i;\l            y -= 3i;\l        }\l    \"unreachable\";\l}\l"];
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
+    N14 -> N21;
     N20 -> N21;
-    N21 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                x -= 1i;\l                y -= 3i;\l            }\l        \"unreachable\";\l    }\l"];
+    N21 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N20 -> N25;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N27;
+    N26 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1i { continue \'outer ; \"unreachable\"; }\l        if y >= 2i { return; \"unreachable\"; }\l        x -= 1i;\l        y -= 3i;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1i { continue \'outer ; \"unreachable\"; }\l                if y >= 2i { return; \"unreachable\"; }\l                x -= 1i;\l                y -= 3i;\l            }\l        \"unreachable\";\l    }\l"];
     N27 -> N28;
     N28 -> N29;
     N29 -> N30;
     N30 -> N31;
+    N25 -> N32;
     N31 -> N32;
-    N32 -> N8;
-    N9 -> N33;
+    N32 -> N33;
     N33 -> N34;
-    N34 -> N6;
-    N7 -> N35;
+    N34 -> N35;
     N35 -> N36;
-    N36 -> N1;
+    N36 -> N37;
+    N37 -> N38;
+    N38 -> N39;
+    N39 -> N40;
+    N40 -> N41;
+    N41 -> N42;
+    N42 -> N10;
+    N11 -> N43;
+    N43 -> N44;
+    N44 -> N45;
+    N45 -> N46;
+    N46 -> N8;
+    N9 -> N47;
+    N47 -> N48;
+    N48 -> N49;
+    N49 -> N50;
+    N50 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
index 718d4687ef9..034ecfb7f20 100644
--- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
@@ -3,46 +3,55 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 23i"];
     N3[label="local mut x"];
-    N4[label="expr 23i"];
-    N5[label="local mut y"];
-    N6[label="expr 23i"];
-    N7[label="local mut z"];
-    N8[label="(dummy_node)"];
-    N9[label="expr x"];
-    N10[label="expr 0i"];
-    N11[label="expr x > 0i"];
-    N12[label="expr while x > 0i {\l    x -= 1i;\l    while y > 0i {\l        y -= 1i;\l        while z > 0i { z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
-    N13[label="expr 1i"];
-    N14[label="expr x"];
-    N15[label="expr x -= 1i"];
-    N16[label="(dummy_node)"];
-    N17[label="expr y"];
-    N18[label="expr 0i"];
-    N19[label="expr y > 0i"];
-    N20[label="expr while y > 0i {\l    y -= 1i;\l    while z > 0i { z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
-    N21[label="expr 1i"];
-    N22[label="expr y"];
-    N23[label="expr y -= 1i"];
-    N24[label="(dummy_node)"];
-    N25[label="expr z"];
-    N26[label="expr 0i"];
-    N27[label="expr z > 0i"];
-    N28[label="expr while z > 0i { z -= 1i; }"];
-    N29[label="expr 1i"];
+    N4[label="stmt let mut x = 23i;"];
+    N5[label="expr 23i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 23i;"];
+    N8[label="expr 23i"];
+    N9[label="local mut z"];
+    N10[label="stmt let mut z = 23i;"];
+    N11[label="(dummy_node)"];
+    N12[label="expr x"];
+    N13[label="expr 0i"];
+    N14[label="expr x > 0i"];
+    N15[label="expr while x > 0i {\l    x -= 1i;\l    while y > 0i {\l        y -= 1i;\l        while z > 0i { z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N16[label="expr 1i"];
+    N17[label="expr x"];
+    N18[label="expr x -= 1i"];
+    N19[label="stmt x -= 1i;"];
+    N20[label="(dummy_node)"];
+    N21[label="expr y"];
+    N22[label="expr 0i"];
+    N23[label="expr y > 0i"];
+    N24[label="expr while y > 0i {\l    y -= 1i;\l    while z > 0i { z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
+    N25[label="expr 1i"];
+    N26[label="expr y"];
+    N27[label="expr y -= 1i"];
+    N28[label="stmt y -= 1i;"];
+    N29[label="(dummy_node)"];
     N30[label="expr z"];
-    N31[label="expr z -= 1i"];
-    N32[label="block { z -= 1i; }"];
-    N33[label="expr x"];
-    N34[label="expr 10i"];
-    N35[label="expr x > 10i"];
-    N36[label="expr return"];
-    N37[label="(dummy_node)"];
-    N38[label="expr \"unreachable\""];
-    N39[label="block { return; \"unreachable\"; }"];
-    N40[label="expr if x > 10i { return; \"unreachable\"; }"];
-    N41[label="block { y -= 1i; while z > 0i { z -= 1i; } if x > 10i { return; \"unreachable\"; } }"];
-    N42[label="block {\l    x -= 1i;\l    while y > 0i {\l        y -= 1i;\l        while z > 0i { z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
-    N43[label="block {\l    let mut x = 23i;\l    let mut y = 23i;\l    let mut z = 23i;\l    while x > 0i {\l        x -= 1i;\l        while y > 0i {\l            y -= 1i;\l            while z > 0i { z -= 1i; }\l            if x > 10i { return; \"unreachable\"; }\l        }\l    }\l}\l"];
+    N31[label="expr 0i"];
+    N32[label="expr z > 0i"];
+    N33[label="expr while z > 0i { z -= 1i; }"];
+    N34[label="expr 1i"];
+    N35[label="expr z"];
+    N36[label="expr z -= 1i"];
+    N37[label="stmt z -= 1i;"];
+    N38[label="block { z -= 1i; }"];
+    N39[label="stmt while z > 0i { z -= 1i; }"];
+    N40[label="expr x"];
+    N41[label="expr 10i"];
+    N42[label="expr x > 10i"];
+    N43[label="expr return"];
+    N44[label="(dummy_node)"];
+    N45[label="stmt return;"];
+    N46[label="expr \"unreachable\""];
+    N47[label="stmt \"unreachable\";"];
+    N48[label="block { return; \"unreachable\"; }"];
+    N49[label="expr if x > 10i { return; \"unreachable\"; }"];
+    N50[label="block { y -= 1i; while z > 0i { z -= 1i; } if x > 10i { return; \"unreachable\"; } }"];
+    N51[label="block {\l    x -= 1i;\l    while y > 0i {\l        y -= 1i;\l        while z > 0i { z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N52[label="block {\l    let mut x = 23i;\l    let mut y = 23i;\l    let mut z = 23i;\l    while x > 0i {\l        x -= 1i;\l        while y > 0i {\l            y -= 1i;\l            while z > 0i { z -= 1i; }\l            if x > 10i { return; \"unreachable\"; }\l        }\l    }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -54,40 +63,49 @@ digraph block {
     N9 -> N10;
     N10 -> N11;
     N11 -> N12;
-    N11 -> N13;
+    N12 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N16;
+    N14 -> N16;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
-    N19 -> N21;
+    N20 -> N21;
     N21 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N24 -> N25;
+    N23 -> N25;
     N25 -> N26;
     N26 -> N27;
     N27 -> N28;
-    N27 -> N29;
+    N28 -> N29;
     N29 -> N30;
     N30 -> N31;
     N31 -> N32;
-    N32 -> N24;
-    N28 -> N33;
-    N33 -> N34;
+    N32 -> N33;
+    N32 -> N34;
     N34 -> N35;
     N35 -> N36;
-    N36 -> N1[label="exiting scope_0 expr while y > 0i {\l    y -= 1i;\l    while z > 0i { z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0i {\l    x -= 1i;\l    while y > 0i {\l        y -= 1i;\l        while z > 0i { z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N36 -> N37;
     N37 -> N38;
-    N38 -> N39;
-    N35 -> N40;
+    N38 -> N29;
+    N33 -> N39;
     N39 -> N40;
     N40 -> N41;
-    N41 -> N16;
-    N20 -> N42;
-    N42 -> N8;
-    N12 -> N43;
-    N43 -> N1;
+    N41 -> N42;
+    N42 -> N43;
+    N43 -> N1[label="exiting scope_0 expr while y > 0i {\l    y -= 1i;\l    while z > 0i { z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0i {\l    x -= 1i;\l    while y > 0i {\l        y -= 1i;\l        while z > 0i { z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N44 -> N45;
+    N45 -> N46;
+    N46 -> N47;
+    N47 -> N48;
+    N42 -> N49;
+    N48 -> N49;
+    N49 -> N50;
+    N50 -> N20;
+    N24 -> N51;
+    N51 -> N11;
+    N15 -> N52;
+    N52 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
index 646d98a54a7..ddb5b865c2e 100644
--- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
@@ -3,61 +3,79 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 24i"];
     N3[label="local mut x"];
-    N4[label="expr 24i"];
-    N5[label="local mut y"];
-    N6[label="expr 24i"];
-    N7[label="local mut z"];
-    N8[label="(dummy_node)"];
-    N9[label="expr loop  {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
-    N10[label="expr x"];
-    N11[label="expr 0i"];
-    N12[label="expr x == 0i"];
-    N13[label="expr break"];
-    N14[label="(dummy_node)"];
-    N15[label="expr \"unreachable\""];
-    N16[label="block { break ; \"unreachable\"; }"];
-    N17[label="expr if x == 0i { break ; \"unreachable\"; }"];
-    N18[label="expr 1i"];
-    N19[label="expr x"];
-    N20[label="expr x -= 1i"];
-    N21[label="(dummy_node)"];
-    N22[label="expr loop  {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
-    N23[label="expr y"];
-    N24[label="expr 0i"];
-    N25[label="expr y == 0i"];
-    N26[label="expr break"];
-    N27[label="(dummy_node)"];
-    N28[label="expr \"unreachable\""];
-    N29[label="block { break ; \"unreachable\"; }"];
-    N30[label="expr if y == 0i { break ; \"unreachable\"; }"];
-    N31[label="expr 1i"];
-    N32[label="expr y"];
-    N33[label="expr y -= 1i"];
+    N4[label="stmt let mut x = 24i;"];
+    N5[label="expr 24i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 24i;"];
+    N8[label="expr 24i"];
+    N9[label="local mut z"];
+    N10[label="stmt let mut z = 24i;"];
+    N11[label="(dummy_node)"];
+    N12[label="expr loop  {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N13[label="expr x"];
+    N14[label="expr 0i"];
+    N15[label="expr x == 0i"];
+    N16[label="expr break"];
+    N17[label="(dummy_node)"];
+    N18[label="stmt break ;"];
+    N19[label="expr \"unreachable\""];
+    N20[label="stmt \"unreachable\";"];
+    N21[label="block { break ; \"unreachable\"; }"];
+    N22[label="expr if x == 0i { break ; \"unreachable\"; }"];
+    N23[label="stmt if x == 0i { break ; \"unreachable\"; }"];
+    N24[label="expr 1i"];
+    N25[label="expr x"];
+    N26[label="expr x -= 1i"];
+    N27[label="stmt x -= 1i;"];
+    N28[label="(dummy_node)"];
+    N29[label="expr loop  {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
+    N30[label="expr y"];
+    N31[label="expr 0i"];
+    N32[label="expr y == 0i"];
+    N33[label="expr break"];
     N34[label="(dummy_node)"];
-    N35[label="expr loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
-    N36[label="expr z"];
-    N37[label="expr 0i"];
-    N38[label="expr z == 0i"];
-    N39[label="expr break"];
-    N40[label="(dummy_node)"];
-    N41[label="expr \"unreachable\""];
-    N42[label="block { break ; \"unreachable\"; }"];
-    N43[label="expr if z == 0i { break ; \"unreachable\"; }"];
-    N44[label="expr 1i"];
-    N45[label="expr z"];
-    N46[label="expr z -= 1i"];
-    N47[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
-    N48[label="expr x"];
-    N49[label="expr 10i"];
-    N50[label="expr x > 10i"];
-    N51[label="expr return"];
-    N52[label="(dummy_node)"];
+    N35[label="stmt break ;"];
+    N36[label="expr \"unreachable\""];
+    N37[label="stmt \"unreachable\";"];
+    N38[label="block { break ; \"unreachable\"; }"];
+    N39[label="expr if y == 0i { break ; \"unreachable\"; }"];
+    N40[label="stmt if y == 0i { break ; \"unreachable\"; }"];
+    N41[label="expr 1i"];
+    N42[label="expr y"];
+    N43[label="expr y -= 1i"];
+    N44[label="stmt y -= 1i;"];
+    N45[label="(dummy_node)"];
+    N46[label="expr loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N47[label="expr z"];
+    N48[label="expr 0i"];
+    N49[label="expr z == 0i"];
+    N50[label="expr break"];
+    N51[label="(dummy_node)"];
+    N52[label="stmt break ;"];
     N53[label="expr \"unreachable\""];
-    N54[label="block { return; \"unreachable\"; }"];
-    N55[label="expr if x > 10i { return; \"unreachable\"; }"];
-    N56[label="block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
-    N57[label="block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
-    N58[label="block {\l    let mut x = 24i;\l    let mut y = 24i;\l    let mut z = 24i;\l    loop  {\l        if x == 0i { break ; \"unreachable\"; }\l        x -= 1i;\l        loop  {\l            if y == 0i { break ; \"unreachable\"; }\l            y -= 1i;\l            loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l            if x > 10i { return; \"unreachable\"; }\l        }\l    }\l}\l"];
+    N54[label="stmt \"unreachable\";"];
+    N55[label="block { break ; \"unreachable\"; }"];
+    N56[label="expr if z == 0i { break ; \"unreachable\"; }"];
+    N57[label="stmt if z == 0i { break ; \"unreachable\"; }"];
+    N58[label="expr 1i"];
+    N59[label="expr z"];
+    N60[label="expr z -= 1i"];
+    N61[label="stmt z -= 1i;"];
+    N62[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N63[label="stmt loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N64[label="expr x"];
+    N65[label="expr 10i"];
+    N66[label="expr x > 10i"];
+    N67[label="expr return"];
+    N68[label="(dummy_node)"];
+    N69[label="stmt return;"];
+    N70[label="expr \"unreachable\""];
+    N71[label="stmt \"unreachable\";"];
+    N72[label="block { return; \"unreachable\"; }"];
+    N73[label="expr if x > 10i { return; \"unreachable\"; }"];
+    N74[label="block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
+    N75[label="block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N76[label="block {\l    let mut x = 24i;\l    let mut y = 24i;\l    let mut z = 24i;\l    loop  {\l        if x == 0i { break ; \"unreachable\"; }\l        x -= 1i;\l        loop  {\l            if y == 0i { break ; \"unreachable\"; }\l            y -= 1i;\l            loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l            if x > 10i { return; \"unreachable\"; }\l        }\l    }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -65,59 +83,77 @@ digraph block {
     N5 -> N6;
     N6 -> N7;
     N7 -> N8;
-    N8 -> N10;
+    N8 -> N9;
+    N9 -> N10;
     N10 -> N11;
-    N11 -> N12;
-    N12 -> N13;
-    N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N11 -> N13;
+    N13 -> N14;
     N14 -> N15;
     N15 -> N16;
-    N12 -> N17;
-    N16 -> N17;
+    N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
     N20 -> N21;
-    N21 -> N23;
+    N15 -> N22;
+    N21 -> N22;
+    N22 -> N23;
     N23 -> N24;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
+    N26 -> N27;
     N27 -> N28;
-    N28 -> N29;
-    N25 -> N30;
-    N29 -> N30;
+    N28 -> N30;
     N30 -> N31;
     N31 -> N32;
     N32 -> N33;
-    N33 -> N34;
-    N34 -> N36;
+    N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l"];
+    N34 -> N35;
+    N35 -> N36;
     N36 -> N37;
     N37 -> N38;
+    N32 -> N39;
     N38 -> N39;
-    N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N39 -> N40;
     N40 -> N41;
     N41 -> N42;
-    N38 -> N43;
     N42 -> N43;
     N43 -> N44;
     N44 -> N45;
-    N45 -> N46;
-    N46 -> N47;
-    N47 -> N34;
-    N35 -> N48;
+    N45 -> N47;
+    N47 -> N48;
     N48 -> N49;
     N49 -> N50;
-    N50 -> N51;
-    N51 -> N1[label="exiting scope_0 expr loop  {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop  {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N51 -> N52;
     N52 -> N53;
     N53 -> N54;
-    N50 -> N55;
     N54 -> N55;
+    N49 -> N56;
     N55 -> N56;
-    N56 -> N21;
-    N22 -> N57;
-    N57 -> N8;
-    N9 -> N58;
-    N58 -> N1;
+    N56 -> N57;
+    N57 -> N58;
+    N58 -> N59;
+    N59 -> N60;
+    N60 -> N61;
+    N61 -> N62;
+    N62 -> N45;
+    N46 -> N63;
+    N63 -> N64;
+    N64 -> N65;
+    N65 -> N66;
+    N66 -> N67;
+    N67 -> N1[label="exiting scope_0 expr loop  {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop  {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { return; \"unreachable\"; }\l    }\l}\l"];
+    N68 -> N69;
+    N69 -> N70;
+    N70 -> N71;
+    N71 -> N72;
+    N66 -> N73;
+    N72 -> N73;
+    N73 -> N74;
+    N74 -> N28;
+    N29 -> N75;
+    N75 -> N11;
+    N12 -> N76;
+    N76 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
index 11b9c7ef05e..9fd4dbfc395 100644
--- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
@@ -3,61 +3,79 @@ digraph block {
     N1[label="exit"];
     N2[label="expr 25i"];
     N3[label="local mut x"];
-    N4[label="expr 25i"];
-    N5[label="local mut y"];
-    N6[label="expr 25i"];
-    N7[label="local mut z"];
-    N8[label="(dummy_node)"];
-    N9[label="expr \'a:\l    loop  {\l        if x == 0i { break ; \"unreachable\"; }\l        x -= 1i;\l        \'a:\l            loop  {\l                if y == 0i { break ; \"unreachable\"; }\l                y -= 1i;\l                \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l                if x > 10i { continue \'a ; \"unreachable\"; }\l            }\l    }\l"];
-    N10[label="expr x"];
-    N11[label="expr 0i"];
-    N12[label="expr x == 0i"];
-    N13[label="expr break"];
-    N14[label="(dummy_node)"];
-    N15[label="expr \"unreachable\""];
-    N16[label="block { break ; \"unreachable\"; }"];
-    N17[label="expr if x == 0i { break ; \"unreachable\"; }"];
-    N18[label="expr 1i"];
-    N19[label="expr x"];
-    N20[label="expr x -= 1i"];
-    N21[label="(dummy_node)"];
-    N22[label="expr \'a:\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { continue \'a ; \"unreachable\"; }\l    }\l"];
-    N23[label="expr y"];
-    N24[label="expr 0i"];
-    N25[label="expr y == 0i"];
-    N26[label="expr break"];
-    N27[label="(dummy_node)"];
-    N28[label="expr \"unreachable\""];
-    N29[label="block { break ; \"unreachable\"; }"];
-    N30[label="expr if y == 0i { break ; \"unreachable\"; }"];
-    N31[label="expr 1i"];
-    N32[label="expr y"];
-    N33[label="expr y -= 1i"];
+    N4[label="stmt let mut x = 25i;"];
+    N5[label="expr 25i"];
+    N6[label="local mut y"];
+    N7[label="stmt let mut y = 25i;"];
+    N8[label="expr 25i"];
+    N9[label="local mut z"];
+    N10[label="stmt let mut z = 25i;"];
+    N11[label="(dummy_node)"];
+    N12[label="expr \'a:\l    loop  {\l        if x == 0i { break ; \"unreachable\"; }\l        x -= 1i;\l        \'a:\l            loop  {\l                if y == 0i { break ; \"unreachable\"; }\l                y -= 1i;\l                \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l                if x > 10i { continue \'a ; \"unreachable\"; }\l            }\l    }\l"];
+    N13[label="expr x"];
+    N14[label="expr 0i"];
+    N15[label="expr x == 0i"];
+    N16[label="expr break"];
+    N17[label="(dummy_node)"];
+    N18[label="stmt break ;"];
+    N19[label="expr \"unreachable\""];
+    N20[label="stmt \"unreachable\";"];
+    N21[label="block { break ; \"unreachable\"; }"];
+    N22[label="expr if x == 0i { break ; \"unreachable\"; }"];
+    N23[label="stmt if x == 0i { break ; \"unreachable\"; }"];
+    N24[label="expr 1i"];
+    N25[label="expr x"];
+    N26[label="expr x -= 1i"];
+    N27[label="stmt x -= 1i;"];
+    N28[label="(dummy_node)"];
+    N29[label="expr \'a:\l    loop  {\l        if y == 0i { break ; \"unreachable\"; }\l        y -= 1i;\l        \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l        if x > 10i { continue \'a ; \"unreachable\"; }\l    }\l"];
+    N30[label="expr y"];
+    N31[label="expr 0i"];
+    N32[label="expr y == 0i"];
+    N33[label="expr break"];
     N34[label="(dummy_node)"];
-    N35[label="expr \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
-    N36[label="expr z"];
-    N37[label="expr 0i"];
-    N38[label="expr z == 0i"];
-    N39[label="expr break"];
-    N40[label="(dummy_node)"];
-    N41[label="expr \"unreachable\""];
-    N42[label="block { break ; \"unreachable\"; }"];
-    N43[label="expr if z == 0i { break ; \"unreachable\"; }"];
-    N44[label="expr 1i"];
-    N45[label="expr z"];
-    N46[label="expr z -= 1i"];
-    N47[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
-    N48[label="expr x"];
-    N49[label="expr 10i"];
-    N50[label="expr x > 10i"];
-    N51[label="expr continue \'a"];
-    N52[label="(dummy_node)"];
+    N35[label="stmt break ;"];
+    N36[label="expr \"unreachable\""];
+    N37[label="stmt \"unreachable\";"];
+    N38[label="block { break ; \"unreachable\"; }"];
+    N39[label="expr if y == 0i { break ; \"unreachable\"; }"];
+    N40[label="stmt if y == 0i { break ; \"unreachable\"; }"];
+    N41[label="expr 1i"];
+    N42[label="expr y"];
+    N43[label="expr y -= 1i"];
+    N44[label="stmt y -= 1i;"];
+    N45[label="(dummy_node)"];
+    N46[label="expr \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N47[label="expr z"];
+    N48[label="expr 0i"];
+    N49[label="expr z == 0i"];
+    N50[label="expr break"];
+    N51[label="(dummy_node)"];
+    N52[label="stmt break ;"];
     N53[label="expr \"unreachable\""];
-    N54[label="block { continue \'a ; \"unreachable\"; }"];
-    N55[label="expr if x > 10i { continue \'a ; \"unreachable\"; }"];
-    N56[label="block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"];
-    N57[label="block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    \'a:\l        loop  {\l            if y == 0i { break ; \"unreachable\"; }\l            y -= 1i;\l            \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l            if x > 10i { continue \'a ; \"unreachable\"; }\l        }\l}\l"];
-    N58[label="block {\l    let mut x = 25i;\l    let mut y = 25i;\l    let mut z = 25i;\l    \'a:\l        loop  {\l            if x == 0i { break ; \"unreachable\"; }\l            x -= 1i;\l            \'a:\l                loop  {\l                    if y == 0i { break ; \"unreachable\"; }\l                    y -= 1i;\l                    \'a:\l                        loop  {\l                            if z == 0i { break ; \"unreachable\"; }\l                            z -= 1i;\l                        }\l                    if x > 10i { continue \'a ; \"unreachable\"; }\l                }\l        }\l}\l"];
+    N54[label="stmt \"unreachable\";"];
+    N55[label="block { break ; \"unreachable\"; }"];
+    N56[label="expr if z == 0i { break ; \"unreachable\"; }"];
+    N57[label="stmt if z == 0i { break ; \"unreachable\"; }"];
+    N58[label="expr 1i"];
+    N59[label="expr z"];
+    N60[label="expr z -= 1i"];
+    N61[label="stmt z -= 1i;"];
+    N62[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N63[label="stmt \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N64[label="expr x"];
+    N65[label="expr 10i"];
+    N66[label="expr x > 10i"];
+    N67[label="expr continue \'a"];
+    N68[label="(dummy_node)"];
+    N69[label="stmt continue \'a ;"];
+    N70[label="expr \"unreachable\""];
+    N71[label="stmt \"unreachable\";"];
+    N72[label="block { continue \'a ; \"unreachable\"; }"];
+    N73[label="expr if x > 10i { continue \'a ; \"unreachable\"; }"];
+    N74[label="block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"];
+    N75[label="block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    \'a:\l        loop  {\l            if y == 0i { break ; \"unreachable\"; }\l            y -= 1i;\l            \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l            if x > 10i { continue \'a ; \"unreachable\"; }\l        }\l}\l"];
+    N76[label="block {\l    let mut x = 25i;\l    let mut y = 25i;\l    let mut z = 25i;\l    \'a:\l        loop  {\l            if x == 0i { break ; \"unreachable\"; }\l            x -= 1i;\l            \'a:\l                loop  {\l                    if y == 0i { break ; \"unreachable\"; }\l                    y -= 1i;\l                    \'a:\l                        loop  {\l                            if z == 0i { break ; \"unreachable\"; }\l                            z -= 1i;\l                        }\l                    if x > 10i { continue \'a ; \"unreachable\"; }\l                }\l        }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -65,59 +83,77 @@ digraph block {
     N5 -> N6;
     N6 -> N7;
     N7 -> N8;
-    N8 -> N10;
+    N8 -> N9;
+    N9 -> N10;
     N10 -> N11;
-    N11 -> N12;
-    N12 -> N13;
-    N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    \'a:\l        loop  {\l            if y == 0i { break ; \"unreachable\"; }\l            y -= 1i;\l            \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l            if x > 10i { continue \'a ; \"unreachable\"; }\l        }\l}\l"];
+    N11 -> N13;
+    N13 -> N14;
     N14 -> N15;
     N15 -> N16;
-    N12 -> N17;
-    N16 -> N17;
+    N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 0i { break ; \"unreachable\"; }\l    x -= 1i;\l    \'a:\l        loop  {\l            if y == 0i { break ; \"unreachable\"; }\l            y -= 1i;\l            \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l            if x > 10i { continue \'a ; \"unreachable\"; }\l        }\l}\l"];
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
     N20 -> N21;
-    N21 -> N23;
+    N15 -> N22;
+    N21 -> N22;
+    N22 -> N23;
     N23 -> N24;
     N24 -> N25;
     N25 -> N26;
-    N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"];
+    N26 -> N27;
     N27 -> N28;
-    N28 -> N29;
-    N25 -> N30;
-    N29 -> N30;
+    N28 -> N30;
     N30 -> N31;
     N31 -> N32;
     N32 -> N33;
-    N33 -> N34;
-    N34 -> N36;
+    N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"];
+    N34 -> N35;
+    N35 -> N36;
     N36 -> N37;
     N37 -> N38;
+    N32 -> N39;
     N38 -> N39;
-    N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N39 -> N40;
     N40 -> N41;
     N41 -> N42;
-    N38 -> N43;
     N42 -> N43;
     N43 -> N44;
     N44 -> N45;
-    N45 -> N46;
-    N46 -> N47;
-    N47 -> N34;
-    N35 -> N48;
+    N45 -> N47;
+    N47 -> N48;
     N48 -> N49;
     N49 -> N50;
-    N50 -> N51;
-    N51 -> N21[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10i { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"];
+    N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"];
+    N51 -> N52;
     N52 -> N53;
     N53 -> N54;
-    N50 -> N55;
     N54 -> N55;
+    N49 -> N56;
     N55 -> N56;
-    N56 -> N21;
-    N22 -> N57;
-    N57 -> N8;
-    N9 -> N58;
-    N58 -> N1;
+    N56 -> N57;
+    N57 -> N58;
+    N58 -> N59;
+    N59 -> N60;
+    N60 -> N61;
+    N61 -> N62;
+    N62 -> N45;
+    N46 -> N63;
+    N63 -> N64;
+    N64 -> N65;
+    N65 -> N66;
+    N66 -> N67;
+    N67 -> N28[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10i { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l    if y == 0i { break ; \"unreachable\"; }\l    y -= 1i;\l    \'a: loop  { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l    if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"];
+    N68 -> N69;
+    N69 -> N70;
+    N70 -> N71;
+    N71 -> N72;
+    N66 -> N73;
+    N72 -> N73;
+    N73 -> N74;
+    N74 -> N28;
+    N29 -> N75;
+    N75 -> N11;
+    N12 -> N76;
+    N76 -> N1;
 }
diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs
index dec53672d87..6e67b3f6add 100644
--- a/src/test/run-pass/alignment-gep-tup-like-1.rs
+++ b/src/test/run-pass/alignment-gep-tup-like-1.rs
@@ -29,11 +29,11 @@ impl<A:Clone> Invokable<A> for Invoker<A> {
     }
 }
 
-fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>> {
+fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>+'static> {
     box Invoker {
         a: a,
         b: b,
-    } as (Box<Invokable<A>>)
+    } as (Box<Invokable<A>+'static>)
 }
 
 pub fn main() {
diff --git a/src/test/run-pass/borrowck-freeze-frozen-mut.rs b/src/test/run-pass/borrowck-freeze-frozen-mut.rs
index 4044e9f06af..f224042bc79 100644
--- a/src/test/run-pass/borrowck-freeze-frozen-mut.rs
+++ b/src/test/run-pass/borrowck-freeze-frozen-mut.rs
@@ -10,7 +10,7 @@
 
 // Test that a `&mut` inside of an `&` is freezable.
 
-struct MutSlice<'a, T> {
+struct MutSlice<'a, T:'a> {
     data: &'a mut [T]
 }
 
diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs
index 59d532a40e7..69878d4a06b 100644
--- a/src/test/run-pass/close-over-big-then-small-data.rs
+++ b/src/test/run-pass/close-over-big-then-small-data.rs
@@ -33,11 +33,11 @@ impl<A:Clone> Invokable<A> for Invoker<A> {
     }
 }
 
-fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>> {
+fn f<A:Clone + 'static>(a: A, b: u16) -> Box<Invokable<A>+'static> {
     box Invoker {
         a: a,
         b: b,
-    } as (Box<Invokable<A>>)
+    } as (Box<Invokable<A>+'static>)
 }
 
 pub fn main() {
diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs
index c05f2502a89..aa4d48e5ae0 100644
--- a/src/test/run-pass/closure-reform.rs
+++ b/src/test/run-pass/closure-reform.rs
@@ -26,7 +26,7 @@ fn call_this(f: |&str|:Send) {
     f("Hello!");
 }
 
-fn call_that(f: <'a>|&'a int, &'a int|: -> int) {
+fn call_that(f: <'a>|&'a int, &'a int| -> int) {
     let (ten, forty_two) = (10, 42);
     println!("Your lucky number is {}", f(&ten, &forty_two));
 }
diff --git a/src/test/run-pass/closure-syntax.rs b/src/test/run-pass/closure-syntax.rs
index 7b8d1dd7576..c2fbc2a4bf2 100644
--- a/src/test/run-pass/closure-syntax.rs
+++ b/src/test/run-pass/closure-syntax.rs
@@ -13,16 +13,16 @@
 fn foo<T>() {}
 
 trait Bar1 {}
-impl Bar1 for proc() {}
+impl Bar1 for proc():'static {}
 
 trait Bar2 {}
-impl Bar2 for proc(): Send {}
+impl Bar2 for proc():Send {}
 
 trait Bar3 {}
 impl<'b> Bar3 for <'a>|&'a int|: 'b + Send -> &'a int {}
 
 trait Bar4 {}
-impl Bar4 for proc<'a>(&'a int) -> &'a int {}
+impl Bar4 for proc<'a>(&'a int):'static -> &'a int {}
 
 struct Foo<'a> {
     a: ||: 'a,
@@ -30,9 +30,9 @@ struct Foo<'a> {
     c: <'b>||: 'a,
     d: ||: 'a + Sync,
     e: <'b>|int|: 'a + Sync -> &'b f32,
-    f: proc(),
-    g: proc(): 'static + Sync,
-    h: proc<'b>(int): Sync -> &'b f32,
+    f: proc():'static,
+    g: proc():'static+Sync,
+    h: proc<'b>(int):'static+Sync -> &'b f32,
 }
 
 fn f<'a>(a: &'a int, f: <'b>|&'b int| -> &'b int) -> &'a int {
diff --git a/src/test/run-pass/colorful-write-macros.rs b/src/test/run-pass/colorful-write-macros.rs
index 724e57bdef2..60b6d8f8be0 100644
--- a/src/test/run-pass/colorful-write-macros.rs
+++ b/src/test/run-pass/colorful-write-macros.rs
@@ -18,7 +18,7 @@ use std::fmt;
 use std::fmt::FormatWriter;
 
 struct Foo<'a> {
-    writer: &'a mut Writer,
+    writer: &'a mut Writer+'a,
     other: &'a str,
 }
 
diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs
index ac2922e92d4..e95b1ed2f0e 100644
--- a/src/test/run-pass/explicit-self-generic.rs
+++ b/src/test/run-pass/explicit-self-generic.rs
@@ -13,8 +13,8 @@
  *
  * The hash should concentrate entropy in the lower bits.
  */
-type HashFn<K> = proc(K) -> uint;
-type EqFn<K> = proc(K, K) -> bool;
+type HashFn<K> = proc(K):'static -> uint;
+type EqFn<K> = proc(K, K):'static -> bool;
 
 struct LM { resize_at: uint, size: uint }
 
diff --git a/src/test/run-pass/issue-10802.rs b/src/test/run-pass/issue-10802.rs
index 4fda506ae64..7487ea81fa8 100644
--- a/src/test/run-pass/issue-10802.rs
+++ b/src/test/run-pass/issue-10802.rs
@@ -30,9 +30,9 @@ trait MyTrait { }
 impl MyTrait for Box<DroppableStruct> {}
 impl MyTrait for Box<DroppableEnum> {}
 
-struct Whatever { w: Box<MyTrait> }
+struct Whatever { w: Box<MyTrait+'static> }
 impl  Whatever {
-    fn new(w: Box<MyTrait>) -> Whatever {
+    fn new(w: Box<MyTrait+'static>) -> Whatever {
         Whatever { w: w }
     }
 }
diff --git a/src/test/run-pass/issue-11205.rs b/src/test/run-pass/issue-11205.rs
index 5b52bc34d2b..c2c291c0bec 100644
--- a/src/test/run-pass/issue-11205.rs
+++ b/src/test/run-pass/issue-11205.rs
@@ -49,7 +49,7 @@ fn main() {
     foog(x, &[box 1i]);
 
     struct T<'a> {
-        t: [&'a Foo, ..2]
+        t: [&'a Foo+'a, ..2]
     }
     let _n = T {
         t: [&1i, &2i]
@@ -64,7 +64,7 @@ fn main() {
     };
 
     struct F<'b> {
-        t: &'b [&'b Foo]
+        t: &'b [&'b Foo+'b]
     }
     let _n = F {
         t: &[&1i, &2i]
@@ -80,7 +80,7 @@ fn main() {
     };
 
     struct M<'a> {
-        t: &'a [Box<Foo>]
+        t: &'a [Box<Foo+'static>]
     }
     let _n = M {
         t: &[box 1i, box 2i]
diff --git a/src/test/run-pass/issue-11612.rs b/src/test/run-pass/issue-11612.rs
index 5fb2274a446..fa25d25df05 100644
--- a/src/test/run-pass/issue-11612.rs
+++ b/src/test/run-pass/issue-11612.rs
@@ -14,7 +14,7 @@
 
 trait A {}
 
-struct B<'a, T> {
+struct B<'a, T:'a> {
     f: &'a T
 }
 
diff --git a/src/test/run-pass/issue-11677.rs b/src/test/run-pass/issue-11677.rs
index 5a244250852..14c1b1b06ea 100644
--- a/src/test/run-pass/issue-11677.rs
+++ b/src/test/run-pass/issue-11677.rs
@@ -14,7 +14,8 @@
 
 trait X<T> {}
 
-struct S<T> {f: Box<X<T>>, g: Box<X<T>>}
+struct S<T> {f: Box<X<T>+'static>,
+             g: Box<X<T>+'static>}
 
 struct F;
 impl X<int> for F {}
diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs
index b53c2258736..c2bd8c5b3e5 100644
--- a/src/test/run-pass/issue-14958.rs
+++ b/src/test/run-pass/issue-14958.rs
@@ -14,7 +14,7 @@ trait Foo {}
 
 struct Bar;
 
-impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar {
+impl<'a> std::ops::Fn<(&'a Foo+'a,), ()> for Bar {
     extern "rust-call" fn call(&self, _: (&'a Foo,)) {}
 }
 
diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs
index af0bc78094e..74b9df9b88d 100644
--- a/src/test/run-pass/issue-14959.rs
+++ b/src/test/run-pass/issue-14959.rs
@@ -33,8 +33,8 @@ impl Alloy {
     }
 }
 
-impl<'a, 'b> Fn<(&'b mut Response,),()> for SendFile<'a> {
-    extern "rust-call" fn call(&self, (_res,): (&'b mut Response,)) {}
+impl<'a, 'b> Fn<(&'b mut Response+'b,),()> for SendFile<'a> {
+    extern "rust-call" fn call(&self, (_res,): (&'b mut Response+'b,)) {}
 }
 
 impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for HelloWorld {
diff --git a/src/test/run-pass/issue-2734.rs b/src/test/run-pass/issue-2734.rs
index 11ebf014bc6..9eec2d048d4 100644
--- a/src/test/run-pass/issue-2734.rs
+++ b/src/test/run-pass/issue-2734.rs
@@ -12,8 +12,8 @@
 trait hax { }
 impl<A> hax for A { }
 
-fn perform_hax<T: 'static>(x: Box<T>) -> Box<hax> {
-    box x as Box<hax>
+fn perform_hax<T: 'static>(x: Box<T>) -> Box<hax+'static> {
+    box x as Box<hax+'static>
 }
 
 fn deadcode() {
diff --git a/src/test/run-pass/issue-2735.rs b/src/test/run-pass/issue-2735.rs
index 1a5b175cffc..74b64bb87cf 100644
--- a/src/test/run-pass/issue-2735.rs
+++ b/src/test/run-pass/issue-2735.rs
@@ -12,8 +12,8 @@
 trait hax { }
 impl<A> hax for A { }
 
-fn perform_hax<T: 'static>(x: Box<T>) -> Box<hax> {
-    box x as Box<hax>
+fn perform_hax<T: 'static>(x: Box<T>) -> Box<hax+'static> {
+    box x as Box<hax+'static>
 }
 
 fn deadcode() {
diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs
index b7818ea732a..2dac64b2ec8 100644
--- a/src/test/run-pass/issue-3424.rs
+++ b/src/test/run-pass/issue-3424.rs
@@ -15,7 +15,7 @@ use std::path::{Path};
 use std::path;
 use std::result;
 
-type rsrc_loader = proc(path: &Path) -> result::Result<String, String>;
+type rsrc_loader = proc(path: &Path):'static -> result::Result<String, String>;
 
 fn tester()
 {
diff --git a/src/test/run-pass/issue-5192.rs b/src/test/run-pass/issue-5192.rs
index 0dd6623a349..3b1a8c4a190 100644
--- a/src/test/run-pass/issue-5192.rs
+++ b/src/test/run-pass/issue-5192.rs
@@ -28,12 +28,12 @@ impl EventLoop for UvEventLoop {
 }
 
 pub struct Scheduler {
-    event_loop: Box<EventLoop>,
+    event_loop: Box<EventLoop+'static>,
 }
 
 impl Scheduler {
 
-    pub fn new(event_loop: Box<EventLoop>) -> Scheduler {
+    pub fn new(event_loop: Box<EventLoop+'static>) -> Scheduler {
         Scheduler {
             event_loop: event_loop,
         }
diff --git a/src/test/run-pass/issue-5554.rs b/src/test/run-pass/issue-5554.rs
index 9151fb2b764..24dcc3838c5 100644
--- a/src/test/run-pass/issue-5554.rs
+++ b/src/test/run-pass/issue-5554.rs
@@ -17,7 +17,10 @@ pub struct X<T> {
 }
 
 // reordering these bounds stops the ICE
-impl<T: Default + PartialEq + Default> Default for X<T> {
+//
+// nmatsakis: This test used to have the bounds Default + PartialEq +
+// Default, but having duplicate bounds became illegal.
+impl<T: Default + PartialEq> Default for X<T> {
     fn default() -> X<T> {
         X { a: Default::default() }
     }
diff --git a/src/test/run-pass/issue-5708.rs b/src/test/run-pass/issue-5708.rs
index 2bb320e5562..6168753b6d7 100644
--- a/src/test/run-pass/issue-5708.rs
+++ b/src/test/run-pass/issue-5708.rs
@@ -29,7 +29,7 @@ impl Inner for int {
 }
 
 struct Outer<'a> {
-    inner: &'a Inner
+    inner: &'a Inner+'a
 }
 
 impl<'a> Outer<'a> {
@@ -51,7 +51,7 @@ pub fn main() {
 trait MyTrait<T> { }
 
 pub struct MyContainer<'a, T> {
-    foos: Vec<&'a MyTrait<T>> ,
+    foos: Vec<&'a MyTrait<T>+'a> ,
 }
 
 impl<'a, T> MyContainer<'a, T> {
diff --git a/src/test/run-pass/issue-6318.rs b/src/test/run-pass/issue-6318.rs
index 6512db3b1c5..a4576bc7c8c 100644
--- a/src/test/run-pass/issue-6318.rs
+++ b/src/test/run-pass/issue-6318.rs
@@ -10,7 +10,7 @@
 
 
 pub enum Thing {
-    A(Box<Foo>)
+    A(Box<Foo+'static>)
 }
 
 pub trait Foo {}
@@ -20,7 +20,7 @@ pub struct Struct;
 impl Foo for Struct {}
 
 pub fn main() {
-    match A(box Struct as Box<Foo>) {
+    match A(box Struct as Box<Foo+'static>) {
         A(_a) => 0i,
     };
 }
diff --git a/src/test/run-pass/issue-8249.rs b/src/test/run-pass/issue-8249.rs
index 3ca6c806ef5..dae5db11b0a 100644
--- a/src/test/run-pass/issue-8249.rs
+++ b/src/test/run-pass/issue-8249.rs
@@ -13,7 +13,7 @@ struct B;
 impl A for B {}
 
 struct C<'a> {
-    foo: &'a mut A,
+    foo: &'a mut A+'a,
 }
 
 fn foo(a: &mut A) {
diff --git a/src/test/run-pass/issue-9719.rs b/src/test/run-pass/issue-9719.rs
index ac200e6c1ac..0f054a3083d 100644
--- a/src/test/run-pass/issue-9719.rs
+++ b/src/test/run-pass/issue-9719.rs
@@ -16,7 +16,7 @@ mod a {
     pub trait X {}
     impl X for int {}
 
-    pub struct Z<'a>(Enum<&'a X>);
+    pub struct Z<'a>(Enum<&'a X+'a>);
     fn foo() { let x = 42i; let z = Z(A(&x as &X)); let _ = z; }
 }
 
@@ -24,7 +24,7 @@ mod b {
     trait X {}
     impl X for int {}
     struct Y<'a>{
-        x:Option<&'a X>,
+        x:Option<&'a X+'a>,
     }
 
     fn bar() {
@@ -36,7 +36,7 @@ mod b {
 mod c {
     pub trait X { fn f(&self); }
     impl X for int { fn f(&self) {} }
-    pub struct Z<'a>(Option<&'a X>);
+    pub struct Z<'a>(Option<&'a X+'a>);
     fn main() { let x = 42i; let z = Z(Some(&x as &X)); let _ = z; }
 }
 
diff --git a/src/test/run-pass/kindck-owned-trait-contains-1.rs b/src/test/run-pass/kindck-owned-trait-contains-1.rs
index 511629a6d7a..fbd6c92a020 100644
--- a/src/test/run-pass/kindck-owned-trait-contains-1.rs
+++ b/src/test/run-pass/kindck-owned-trait-contains-1.rs
@@ -17,9 +17,8 @@ impl<A:Clone + 'static> repeat<A> for Box<A> {
     }
 }
 
-fn repeater<A:Clone + 'static>(v: Box<A>) -> Box<repeat<A>> {
-    // Note: owned kind is not necessary as A appears in the trait type
-    box v as Box<repeat<A>> // No
+fn repeater<A:Clone + 'static>(v: Box<A>) -> Box<repeat<A>+'static> {
+    box v as Box<repeat<A>+'static> // No
 }
 
 pub fn main() {
diff --git a/src/test/run-pass/newlambdas-ret-infer.rs b/src/test/run-pass/newlambdas-ret-infer.rs
index 84d49820239..f704545af33 100644
--- a/src/test/run-pass/newlambdas-ret-infer.rs
+++ b/src/test/run-pass/newlambdas-ret-infer.rs
@@ -11,7 +11,7 @@
 // Test that the lambda kind is inferred correctly as a return
 // expression
 
-fn unique() -> proc() { return proc() (); }
+fn unique() -> proc():'static { return proc() (); }
 
 pub fn main() {
 }
diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs
index 86ad53c0228..22e51ea9a75 100644
--- a/src/test/run-pass/newlambdas-ret-infer2.rs
+++ b/src/test/run-pass/newlambdas-ret-infer2.rs
@@ -11,7 +11,7 @@
 // Test that the lambda kind is inferred correctly as a return
 // expression
 
-fn unique() -> proc() { proc() () }
+fn unique() -> proc():'static { proc() () }
 
 pub fn main() {
 }
diff --git a/src/test/run-pass/overloaded-autoderef-indexing.rs b/src/test/run-pass/overloaded-autoderef-indexing.rs
index 37e7ee6c216..5c4befcd0c8 100644
--- a/src/test/run-pass/overloaded-autoderef-indexing.rs
+++ b/src/test/run-pass/overloaded-autoderef-indexing.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct DerefArray<'a, T> {
+struct DerefArray<'a, T:'a> {
     inner: &'a [T]
 }
 
diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs
index 6deae8618fa..27ef90d7376 100644
--- a/src/test/run-pass/regions-early-bound-trait-param.rs
+++ b/src/test/run-pass/regions-early-bound-trait-param.rs
@@ -30,7 +30,7 @@ fn object_invoke1<'d>(x: &'d Trait<'d>) -> (int, int) {
 }
 
 struct Struct1<'e> {
-    f: &'e Trait<'e>
+    f: &'e Trait<'e>+'e
 }
 
 fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (int,int) {
@@ -40,7 +40,7 @@ fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (int,int) {
 }
 
 struct Struct2<'h, 'i> {
-    f: &'h Trait<'i>
+    f: &'h Trait<'i>+'h
 }
 
 fn object_invoke2<'j, 'k>(x: &'k Trait<'j>) -> int {
@@ -78,8 +78,8 @@ impl<'s> Trait<'s> for (int,int) {
     }
 }
 
-impl<'t> MakerTrait<'t> for Box<Trait<'t>> {
-    fn mk() -> Box<Trait<'t>> { box() (4i,5i) as Box<Trait> }
+impl<'t> MakerTrait<'t> for Box<Trait<'t>+'static> {
+    fn mk() -> Box<Trait<'t>+'static> { box() (4i,5i) as Box<Trait> }
 }
 
 enum List<'l> {
diff --git a/src/test/run-pass/regions-early-bound-used-in-bound.rs b/src/test/run-pass/regions-early-bound-used-in-bound.rs
index c262370ac5d..58de2e0e20e 100644
--- a/src/test/run-pass/regions-early-bound-used-in-bound.rs
+++ b/src/test/run-pass/regions-early-bound-used-in-bound.rs
@@ -15,7 +15,7 @@ trait GetRef<'a, T> {
     fn get(&self) -> &'a T;
 }
 
-struct Box<'a, T> {
+struct Box<'a, T:'a> {
     t: &'a T
 }
 
diff --git a/src/test/run-pass/swap-overlapping.rs b/src/test/run-pass/swap-overlapping.rs
index 1a96af43d23..f33483d31bf 100644
--- a/src/test/run-pass/swap-overlapping.rs
+++ b/src/test/run-pass/swap-overlapping.rs
@@ -34,8 +34,8 @@ pub enum TestName {
 }
 
 pub enum TestFn {
-    DynTestFn(proc()),
-    DynBenchFn(proc(&mut int))
+    DynTestFn(proc():'static),
+    DynBenchFn(proc(&mut int):'static)
 }
 
 pub struct TestDesc {
diff --git a/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs b/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs
index 55ad22dd0bf..5b744a44132 100644
--- a/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs
+++ b/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs
@@ -17,7 +17,7 @@ trait A {
 }
 
 impl A for int {
-    fn foo<T: Ord + Ord>(&self) {}
+    fn foo<T: Ord>(&self) {} // Ord implies Eq, so this is ok.
 }
 
 fn main() {}
diff --git a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs
index ebcaf772db4..e3234f03754 100644
--- a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs
+++ b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs
@@ -12,11 +12,11 @@ trait U {}
 trait T<X: U> {}
 
 trait S2<Y: U> {
-    fn m(x: Box<T<Y>>) {}
+    fn m(x: Box<T<Y>+'static>) {}
 }
 
 struct St<X: U> {
-    f: Box<T<X>>,
+    f: Box<T<X>+'static>,
 }
 
 impl<X: U> St<X> {
diff --git a/src/test/run-pass/trait-object-generics.rs b/src/test/run-pass/trait-object-generics.rs
index 3c5ae6b57a3..b20915763f2 100644
--- a/src/test/run-pass/trait-object-generics.rs
+++ b/src/test/run-pass/trait-object-generics.rs
@@ -21,7 +21,7 @@ pub struct Impl<A1, A2, A3> {
      * task <unnamed> failed at 'index out of bounds: the len is 1 but the index is 1',
      * src/librustc/middle/subst.rs:58
      */
-    t: Box<Trait2<A2>>
+    t: Box<Trait2<A2>+'static>
 }
 
 impl<A1, A2, A3> Impl<A1, A2, A3> {
diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs
index c4b990abf7e..746af1b9cf5 100644
--- a/src/test/run-pass/unboxed-closures-boxed.rs
+++ b/src/test/run-pass/unboxed-closures-boxed.rs
@@ -12,8 +12,8 @@
 
 use std::ops::FnMut;
 
-fn make_adder(x: int) -> Box<FnMut<(int,),int>> {
-    (box |&mut: y: int| -> int { x + y }) as Box<FnMut<(int,),int>>
+ fn make_adder(x: int) -> Box<FnMut<(int,),int>+'static> {
+    (box |&mut: y: int| -> int { x + y }) as Box<FnMut<(int,),int>+'static>
 }
 
 pub fn main() {