about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-02-16 20:31:15 +0000
committerbors <bors@rust-lang.org>2015-02-16 20:31:15 +0000
commit81bce5290ff55b9a2eddd83d31b0778180904d7f (patch)
tree4084cf72cf82195b29cd94ab65f57769b694d29e
parente4e7aa28566d062514a7a1f5534d76b9d82f524a (diff)
parent503e15b7c9095e11838c1bbb3f084232950aff18 (diff)
downloadrust-81bce5290ff55b9a2eddd83d31b0778180904d7f.tar.gz
rust-81bce5290ff55b9a2eddd83d31b0778180904d7f.zip
Auto merge of #22230 - nikomatsakis:object-lifetime-defaults-2, r=pnkfelix
Implement rules described in rust-lang/rfcs#599.

Fixes https://github.com/rust-lang/rust/issues/22211.

~~Based atop PR https://github.com/rust-lang/rust/pull/22182, so the first few commits (up to and including "Pacify the mercilous nrc") have already been reviewed.~~
-rw-r--r--src/librustc/metadata/tydecode.rs20
-rw-r--r--src/librustc/metadata/tyencode.rs15
-rw-r--r--src/librustc/middle/infer/error_reporting.rs4
-rw-r--r--src/librustc/middle/ty.rs56
-rw-r--r--src/librustc/middle/ty_fold.rs13
-rw-r--r--src/librustc_typeck/astconv.rs344
-rw-r--r--src/librustc_typeck/check/mod.rs9
-rw-r--r--src/librustc_typeck/check/regionck.rs4
-rw-r--r--src/librustc_typeck/check/regionmanip.rs3
-rw-r--r--src/librustc_typeck/collect.rs129
-rw-r--r--src/librustc_typeck/rscope.rs88
-rw-r--r--src/libsyntax/ext/base.rs6
-rw-r--r--src/libsyntax/ext/deriving/mod.rs4
-rw-r--r--src/libsyntax/ext/expand.rs9
-rw-r--r--src/test/compile-fail/builtin-superkinds-simple.rs2
-rw-r--r--src/test/compile-fail/issue-11374.rs4
-rw-r--r--src/test/compile-fail/issue-5216.rs8
-rw-r--r--src/test/compile-fail/kindck-impl-type-params.rs2
-rw-r--r--src/test/compile-fail/kindck-send-object1.rs2
-rw-r--r--src/test/compile-fail/kindck-send-owned.rs2
-rw-r--r--src/test/compile-fail/kindck-send-region-pointers.rs6
-rw-r--r--src/test/compile-fail/object-lifetime-default-ambiguous.rs61
-rw-r--r--src/test/compile-fail/object-lifetime-default-elision.rs89
-rw-r--r--src/test/compile-fail/object-lifetime-default-from-box-error.rs45
-rw-r--r--src/test/compile-fail/object-lifetime-default-mybox.rs44
-rw-r--r--src/test/compile-fail/object-lifetime-default.rs32
-rw-r--r--src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs2
-rw-r--r--src/test/compile-fail/region-object-lifetime-1.rs29
-rw-r--r--src/test/compile-fail/region-object-lifetime-2.rs24
-rw-r--r--src/test/compile-fail/region-object-lifetime-3.rs28
-rw-r--r--src/test/compile-fail/region-object-lifetime-4.rs26
-rw-r--r--src/test/compile-fail/region-object-lifetime-5.rs25
-rw-r--r--src/test/compile-fail/region-object-lifetime-in-coercion.rs10
-rw-r--r--src/test/compile-fail/regions-bounded-by-send.rs10
-rw-r--r--src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs12
-rw-r--r--src/test/compile-fail/regions-bounded-method-type-parameters.rs2
-rw-r--r--src/test/compile-fail/regions-close-object-into-object-1.rs (renamed from src/test/compile-fail/regions-close-object-into-object.rs)15
-rw-r--r--src/test/compile-fail/regions-close-object-into-object-2.rs23
-rw-r--r--src/test/compile-fail/regions-close-object-into-object-3.rs25
-rw-r--r--src/test/compile-fail/regions-close-object-into-object-4.rs24
-rw-r--r--src/test/compile-fail/seq-args.rs2
-rw-r--r--src/test/compile-fail/structure-constructor-type-mismatch.rs1
-rw-r--r--src/test/compile-fail/trait-bounds-cant-coerce.rs2
-rw-r--r--src/test/compile-fail/trait-bounds-sugar.rs3
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs4
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs4
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs1
-rw-r--r--src/test/run-pass/object-lifetime-default-default-to-static.rs42
-rw-r--r--src/test/run-pass/object-lifetime-default-from-ref-struct.rs47
-rw-r--r--src/test/run-pass/object-lifetime-default-from-rptr-box.rs42
-rw-r--r--src/test/run-pass/object-lifetime-default-from-rptr-mut.rs43
-rw-r--r--src/test/run-pass/object-lifetime-default-from-rptr-struct.rs46
-rw-r--r--src/test/run-pass/object-lifetime-default-from-rptr.rs43
53 files changed, 1264 insertions, 272 deletions
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 9962f49dfcf..94654b84922 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -824,6 +824,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
     assert_eq!(next(st), '|');
     let bounds = parse_bounds_(st, conv);
     let default = parse_opt(st, |st| parse_ty_(st, conv));
+    let object_lifetime_default = parse_object_lifetime_default(st, conv);
 
     ty::TypeParameterDef {
         name: name,
@@ -831,7 +832,24 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
         space: space,
         index: index,
         bounds: bounds,
-        default: default
+        default: default,
+        object_lifetime_default: object_lifetime_default,
+    }
+}
+
+fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
+                                             conv: &mut F)
+                                             -> Option<ty::ObjectLifetimeDefault>
+    where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
+{
+    match next(st) {
+        'n' => None,
+        'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
+        's' => {
+            let region = parse_region_(st, conv);
+            Some(ty::ObjectLifetimeDefault::Specific(region))
+        }
+        _ => panic!("parse_object_lifetime_default: bad input")
     }
 }
 
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 640b9649286..e1e9d49dd05 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -414,6 +414,21 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
              v.space.to_uint(), v.index);
     enc_bounds(w, cx, &v.bounds);
     enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
+    enc_object_lifetime_default(w, cx, v.object_lifetime_default);
+}
+
+fn enc_object_lifetime_default<'a, 'tcx>(w: &mut SeekableMemWriter,
+                                         cx: &ctxt<'a, 'tcx>,
+                                         default: Option<ty::ObjectLifetimeDefault>)
+{
+    match default {
+        None => mywrite!(w, "n"),
+        Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
+        Some(ty::ObjectLifetimeDefault::Specific(r)) => {
+            mywrite!(w, "s");
+            enc_region(w, cx, r);
+        }
+    }
 }
 
 pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 72454046eb9..72b33613c66 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -619,7 +619,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
             infer::RelateRegionParamBound(span) => {
                 self.tcx.sess.span_err(
                     span,
-                    "declared lifetime bound not satisfied");
+                    "lifetime bound not satisfied");
                 note_and_explain_region(
                     self.tcx,
                     "lifetime parameter instantiated with ",
@@ -1628,7 +1628,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
                 self.tcx.sess.span_note(
                     span,
                     &format!("...so that the type `{}` \
-                             will meet the declared lifetime bounds",
+                             will meet its required lifetime bounds",
                             self.ty_to_string(t))[]);
             }
             infer::RelateDefaultParamBound(span, t) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index fe5c81bf2c0..107715a8261 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1762,6 +1762,21 @@ impl fmt::Debug for IntVarValue {
     }
 }
 
+/// Default region to use for the bound of objects that are
+/// supplied as the value for this type parameter. This is derived
+/// from `T:'a` annotations appearing in the type definition.  If
+/// this is `None`, then the default is inherited from the
+/// surrounding context. See RFC #599 for details.
+#[derive(Copy, Clone, Debug)]
+pub enum ObjectLifetimeDefault {
+    /// Require an explicit annotation. Occurs when multiple
+    /// `T:'a` constraints are found.
+    Ambiguous,
+
+    /// Use the given region as the default.
+    Specific(Region),
+}
+
 #[derive(Clone, Debug)]
 pub struct TypeParameterDef<'tcx> {
     pub name: ast::Name,
@@ -1770,6 +1785,7 @@ pub struct TypeParameterDef<'tcx> {
     pub index: u32,
     pub bounds: ParamBounds<'tcx>,
     pub default: Option<Ty<'tcx>>,
+    pub object_lifetime_default: Option<ObjectLifetimeDefault>,
 }
 
 #[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
@@ -5884,42 +5900,13 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
     return true;
 }
 
-pub fn object_region_bounds<'tcx>(
-    tcx: &ctxt<'tcx>,
-    opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures
-    others: BuiltinBounds)
-    -> Vec<ty::Region>
-{
-    // Since we don't actually *know* the self type for an object,
-    // this "open(err)" serves as a kind of dummy standin -- basically
-    // a skolemized type.
-    let open_ty = ty::mk_infer(tcx, FreshTy(0));
-
-    let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
-        // Note that we preserve the overall binding levels here.
-        assert!(!open_ty.has_escaping_regions());
-        let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
-        vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))))
-    });
-
-    let param_bounds = ty::ParamBounds {
-        region_bounds: Vec::new(),
-        builtin_bounds: others,
-        trait_bounds: opt_trait_ref,
-        projection_bounds: Vec::new(), // not relevant to computing region bounds
-    };
-
-    let predicates = ty::predicates(tcx, open_ty, &param_bounds);
-    ty::required_region_bounds(tcx, open_ty, predicates)
-}
-
 /// Given a set of predicates that apply to an object type, returns
 /// the region bounds that the (erased) `Self` type must
 /// outlive. Precisely *because* the `Self` type is erased, the
 /// parameter `erased_self_ty` must be supplied to indicate what type
 /// has been used to represent `Self` in the predicates
 /// themselves. This should really be a unique type; `FreshTy(0)` is a
-/// popular choice (see `object_region_bounds` above).
+/// popular choice.
 ///
 /// Requires that trait definitions have been processed so that we can
 /// elaborate predicates and walk supertraits.
@@ -7390,3 +7377,12 @@ impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
             self.caller_bounds.repr(tcx))
     }
 }
+
+impl<'tcx> Repr<'tcx> for ObjectLifetimeDefault {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        match *self {
+            ObjectLifetimeDefault::Ambiguous => format!("Ambiguous"),
+            ObjectLifetimeDefault::Specific(ref r) => r.repr(tcx),
+        }
+    }
+}
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 645a7ab9440..5e46ce08e4f 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -379,6 +379,19 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
             index: self.index,
             bounds: self.bounds.fold_with(folder),
             default: self.default.fold_with(folder),
+            object_lifetime_default: self.object_lifetime_default.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
+        match *self {
+            ty::ObjectLifetimeDefault::Ambiguous =>
+                ty::ObjectLifetimeDefault::Ambiguous,
+
+            ty::ObjectLifetimeDefault::Specific(r) =>
+                ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
         }
     }
 }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 68054c79f27..0183b3474a5 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -55,8 +55,8 @@ use middle::resolve_lifetime as rl;
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
 use middle::traits;
 use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
-use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
-             ShiftedRscope, BindingRscope};
+use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
+             ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
 use TypeAndSubsts;
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::DefIdMap;
@@ -264,19 +264,18 @@ pub fn ast_path_substs_for_ty<'tcx>(
 
     let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
         ast::AngleBracketedParameters(ref data) => {
-            convert_angle_bracketed_parameters(this, rscope, data)
+            convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
         }
         ast::ParenthesizedParameters(ref data) => {
             span_err!(tcx.sess, path.span, E0214,
                 "parenthesized parameters may only be used with a trait");
-            convert_parenthesized_parameters(this, data)
+            convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
         }
     };
 
     prohibit_projections(this.tcx(), &assoc_bindings);
 
     create_substs_for_ast_path(this,
-                               rscope,
                                path.span,
                                decl_generics,
                                None,
@@ -284,14 +283,12 @@ pub fn ast_path_substs_for_ty<'tcx>(
                                regions)
 }
 
-fn create_substs_for_ast_path<'tcx>(
+fn create_region_substs<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
     span: Span,
     decl_generics: &ty::Generics<'tcx>,
-    self_ty: Option<Ty<'tcx>>,
-    types: Vec<Ty<'tcx>>,
-    regions: Vec<ty::Region>)
+    regions_provided: Vec<ty::Region>)
     -> Substs<'tcx>
 {
     let tcx = this.tcx();
@@ -300,9 +297,9 @@ fn create_substs_for_ast_path<'tcx>(
     // region with the current anon region binding (in other words,
     // whatever & would get replaced with).
     let expected_num_region_params = decl_generics.regions.len(TypeSpace);
-    let supplied_num_region_params = regions.len();
+    let supplied_num_region_params = regions_provided.len();
     let regions = if expected_num_region_params == supplied_num_region_params {
-        regions
+        regions_provided
     } else {
         let anon_regions =
             rscope.anon_regions(span, expected_num_region_params);
@@ -314,51 +311,82 @@ fn create_substs_for_ast_path<'tcx>(
         }
 
         match anon_regions {
-            Ok(v) => v.into_iter().collect(),
-            Err(_) => (0..expected_num_region_params)
-                          .map(|_| ty::ReStatic).collect() // hokey
+            Ok(anon_regions) => anon_regions,
+            Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
         }
     };
+    Substs::new_type(vec![], regions)
+}
+
+/// Given the type/region arguments provided to some path (along with
+/// an implicit Self, if this is a trait reference) returns the complete
+/// set of substitutions. This may involve applying defaulted type parameters.
+///
+/// Note that the type listing given here is *exactly* what the user provided.
+///
+/// The `region_substs` should be the result of `create_region_substs`
+/// -- that is, a substitution with no types but the correct number of
+/// regions.
+fn create_substs_for_ast_path<'tcx>(
+    this: &AstConv<'tcx>,
+    span: Span,
+    decl_generics: &ty::Generics<'tcx>,
+    self_ty: Option<Ty<'tcx>>,
+    types_provided: Vec<Ty<'tcx>>,
+    region_substs: Substs<'tcx>)
+    -> Substs<'tcx>
+{
+    let tcx = this.tcx();
+
+    debug!("create_substs_for_ast_path(decl_generics={}, self_ty={}, \
+           types_provided={}, region_substs={}",
+           decl_generics.repr(tcx), self_ty.repr(tcx), types_provided.repr(tcx),
+           region_substs.repr(tcx));
+
+    assert_eq!(region_substs.regions().len(TypeSpace), decl_generics.regions.len(TypeSpace));
+    assert!(region_substs.types.is_empty());
 
     // Convert the type parameters supplied by the user.
     let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
-    let supplied_ty_param_count = types.len();
-    let formal_ty_param_count =
-        ty_param_defs.iter()
-        .take_while(|x| !ty::is_associated_type(tcx, x.def_id))
-        .count();
-    let required_ty_param_count =
-        ty_param_defs.iter()
-        .take_while(|x| {
-            x.default.is_none() &&
-                !ty::is_associated_type(tcx, x.def_id)
-        })
-        .count();
+    let supplied_ty_param_count = types_provided.len();
+    let formal_ty_param_count = ty_param_defs.len();
+    let required_ty_param_count = ty_param_defs.iter()
+                                               .take_while(|x| x.default.is_none())
+                                               .count();
+
+    let mut type_substs = types_provided;
     if supplied_ty_param_count < required_ty_param_count {
         let expected = if required_ty_param_count < formal_ty_param_count {
             "expected at least"
         } else {
             "expected"
         };
-        span_fatal!(this.tcx().sess, span, E0243,
-                                   "wrong number of type arguments: {} {}, found {}",
-                                           expected,
-                                           required_ty_param_count,
-                                           supplied_ty_param_count);
+        span_err!(this.tcx().sess, span, E0243,
+                  "wrong number of type arguments: {} {}, found {}",
+                  expected,
+                  required_ty_param_count,
+                  supplied_ty_param_count);
+        while type_substs.len() < required_ty_param_count {
+            type_substs.push(tcx.types.err);
+        }
     } else if supplied_ty_param_count > formal_ty_param_count {
         let expected = if required_ty_param_count < formal_ty_param_count {
             "expected at most"
         } else {
             "expected"
         };
-        span_fatal!(this.tcx().sess, span, E0244,
-                                   "wrong number of type arguments: {} {}, found {}",
-                                           expected,
-                                           formal_ty_param_count,
-                                           supplied_ty_param_count);
+        span_err!(this.tcx().sess, span, E0244,
+                  "wrong number of type arguments: {} {}, found {}",
+                  expected,
+                  formal_ty_param_count,
+                  supplied_ty_param_count);
+        type_substs.truncate(formal_ty_param_count);
     }
+    assert!(type_substs.len() >= required_ty_param_count &&
+            type_substs.len() <= formal_ty_param_count);
 
-    let mut substs = Substs::new_type(types, regions);
+    let mut substs = region_substs;
+    substs.types.extend(TypeSpace, type_substs.into_iter());
 
     match self_ty {
         None => {
@@ -374,7 +402,8 @@ fn create_substs_for_ast_path<'tcx>(
         }
     }
 
-    for param in &ty_param_defs[supplied_ty_param_count..] {
+    let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
+    for param in &ty_param_defs[actual_supplied_ty_param_count..] {
         match param.default {
             Some(default) => {
                 // This is a default type parameter.
@@ -400,29 +429,36 @@ struct ConvertedBinding<'tcx> {
 
 fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
                                             rscope: &RegionScope,
+                                            span: Span,
+                                            decl_generics: &ty::Generics<'tcx>,
                                             data: &ast::AngleBracketedParameterData)
-                                            -> (Vec<ty::Region>,
+                                            -> (Substs<'tcx>,
                                                 Vec<Ty<'tcx>>,
                                                 Vec<ConvertedBinding<'tcx>>)
 {
     let regions: Vec<_> =
         data.lifetimes.iter()
-        .map(|l| ast_region_to_region(this.tcx(), l))
-        .collect();
+                      .map(|l| ast_region_to_region(this.tcx(), l))
+                      .collect();
+
+    let region_substs =
+        create_region_substs(this, rscope, span, decl_generics, regions);
 
     let types: Vec<_> =
         data.types.iter()
-        .map(|t| ast_ty_to_ty(this, rscope, &**t))
-        .collect();
+                  .enumerate()
+                  .map(|(i,t)| ast_ty_arg_to_ty(this, rscope, decl_generics,
+                                                i, &region_substs, t))
+                  .collect();
 
     let assoc_bindings: Vec<_> =
         data.bindings.iter()
-        .map(|b| ConvertedBinding { item_name: b.ident.name,
-                                    ty: ast_ty_to_ty(this, rscope, &*b.ty),
-                                    span: b.span })
-        .collect();
+                     .map(|b| ConvertedBinding { item_name: b.ident.name,
+                                                 ty: ast_ty_to_ty(this, rscope, &*b.ty),
+                                                 span: b.span })
+                     .collect();
 
-    (regions, types, assoc_bindings)
+    (region_substs, types, assoc_bindings)
 }
 
 /// Returns the appropriate lifetime to use for any output lifetimes
@@ -465,7 +501,7 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
 {
     match implied_output_region {
         Some(implied_output_region) => {
-            let rb = SpecificRscope::new(implied_output_region);
+            let rb = ElidableRscope::new(implied_output_region);
             ast_ty_to_ty(this, &rb, ty)
         }
         None => {
@@ -479,15 +515,23 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
 }
 
 fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
+                                          rscope: &RegionScope,
+                                          span: Span,
+                                          decl_generics: &ty::Generics<'tcx>,
                                           data: &ast::ParenthesizedParameterData)
-                                          -> (Vec<ty::Region>,
+                                          -> (Substs<'tcx>,
                                               Vec<Ty<'tcx>>,
                                               Vec<ConvertedBinding<'tcx>>)
 {
+    let region_substs =
+        create_region_substs(this, rscope, span, decl_generics, Vec::new());
+
     let binding_rscope = BindingRscope::new();
-    let inputs = data.inputs.iter()
-                            .map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
-                            .collect::<Vec<Ty<'tcx>>>();
+    let inputs =
+        data.inputs.iter()
+                   .map(|a_t| ast_ty_arg_to_ty(this, &binding_rscope, decl_generics,
+                                               0, &region_substs, a_t))
+                   .collect::<Vec<Ty<'tcx>>>();
 
     let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect();
     let (implied_output_region,
@@ -514,7 +558,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
         span: output_span
     };
 
-    (vec![], vec![input_ty], vec![output_binding])
+    (region_substs, vec![input_ty], vec![output_binding])
 }
 
 pub fn instantiate_poly_trait_ref<'tcx>(
@@ -615,7 +659,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
 
     let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
         ast::AngleBracketedParameters(ref data) => {
-            // For now, require that parenthetical5D notation be used
+            // For now, require that parenthetical notation be used
             // only with `Fn()` etc.
             if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
                 span_err!(this.tcx().sess, path.span, E0215,
@@ -626,7 +670,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
                             the crate attributes to enable");
             }
 
-            convert_angle_bracketed_parameters(this, rscope, data)
+            convert_angle_bracketed_parameters(this, rscope, path.span, &trait_def.generics, data)
         }
         ast::ParenthesizedParameters(ref data) => {
             // For now, require that parenthetical notation be used
@@ -640,12 +684,11 @@ fn ast_path_to_trait_ref<'a,'tcx>(
                             the crate attributes to enable");
             }
 
-            convert_parenthesized_parameters(this, data)
+            convert_parenthesized_parameters(this, rscope, path.span, &trait_def.generics, data)
         }
     };
 
     let substs = create_substs_for_ast_path(this,
-                                            rscope,
                                             path.span,
                                             &trait_def.generics,
                                             self_ty,
@@ -932,7 +975,7 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
     let existential_bounds = conv_existential_bounds(this,
                                                      rscope,
                                                      span,
-                                                     Some(trait_ref.clone()),
+                                                     trait_ref.clone(),
                                                      projection_bounds,
                                                      bounds);
 
@@ -1031,10 +1074,45 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
                              qpath.item_path.identifier.name);
 }
 
-// Parses the programmer's textual representation of a type into our
-// internal notion of a type.
-pub fn ast_ty_to_ty<'tcx>(
-        this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx>
+/// Convert a type supplied as value for a type argument from AST into our
+/// our internal representation. This is the same as `ast_ty_to_ty` but that
+/// it applies the object lifetime default.
+///
+/// # Parameters
+///
+/// * `this`, `rscope`: the surrounding context
+/// * `decl_generics`: the generics of the struct/enum/trait declaration being
+///   referenced
+/// * `index`: the index of the type parameter being instantiated from the list
+///   (we assume it is in the `TypeSpace`)
+/// * `region_substs`: a partial substitution consisting of
+///   only the region type parameters being supplied to this type.
+/// * `ast_ty`: the ast representation of the type being supplied
+pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>,
+                              rscope: &RegionScope,
+                              decl_generics: &ty::Generics<'tcx>,
+                              index: usize,
+                              region_substs: &Substs<'tcx>,
+                              ast_ty: &ast::Ty)
+                              -> Ty<'tcx>
+{
+    let tcx = this.tcx();
+
+    if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
+        let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
+        let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
+        ast_ty_to_ty(this, rscope1, ast_ty)
+    } else {
+        ast_ty_to_ty(this, rscope, ast_ty)
+    }
+}
+
+/// Parses the programmer's textual representation of a type into our
+/// internal notion of a type.
+pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
+                          rscope: &RegionScope,
+                          ast_ty: &ast::Ty)
+                          -> Ty<'tcx>
 {
     debug!("ast_ty_to_ty(ast_ty={})",
            ast_ty.repr(this.tcx()));
@@ -1084,7 +1162,11 @@ pub fn ast_ty_to_ty<'tcx>(
             ast::TyRptr(ref region, ref mt) => {
                 let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
                 debug!("ty_rptr r={}", r.repr(this.tcx()));
-                let t = ast_ty_to_ty(this, rscope, &*mt.ty);
+                let rscope1 =
+                    &ObjectLifetimeDefaultRscope::new(
+                        rscope,
+                        Some(ty::ObjectLifetimeDefault::Specific(r)));
+                let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
                 ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
             }
             ast::TyTup(ref fields) => {
@@ -1518,11 +1600,11 @@ pub fn ty_of_closure<'tcx>(
 /// `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.
-pub fn conv_existential_bounds<'tcx>(
+fn conv_existential_bounds<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
     span: Span,
-    principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
+    principal_trait_ref: ty::PolyTraitRef<'tcx>,
     projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
     ast_bounds: &[ast::TyParamBound])
     -> ty::ExistentialBounds<'tcx>
@@ -1546,15 +1628,15 @@ fn conv_ty_poly_trait_ref<'tcx>(
     let mut projection_bounds = Vec::new();
     let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
         let trait_bound = partitioned_bounds.trait_bounds.remove(0);
-        Some(instantiate_poly_trait_ref(this,
-                                        rscope,
-                                        trait_bound,
-                                        None,
-                                        &mut projection_bounds))
+        instantiate_poly_trait_ref(this,
+                                   rscope,
+                                   trait_bound,
+                                   None,
+                                   &mut projection_bounds)
     } else {
         span_err!(this.tcx().sess, span, E0224,
-            "at least one non-builtin trait is required for an object type");
-        None
+                  "at least one non-builtin trait is required for an object type");
+        return this.tcx().types.err;
     };
 
     let bounds =
@@ -1565,17 +1647,14 @@ fn conv_ty_poly_trait_ref<'tcx>(
                                                         projection_bounds,
                                                         partitioned_bounds);
 
-    match main_trait_bound {
-        None => this.tcx().types.err,
-        Some(principal) => ty::mk_trait(this.tcx(), principal, bounds)
-    }
+    ty::mk_trait(this.tcx(), main_trait_bound, bounds)
 }
 
 pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
     span: Span,
-    principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
+    principal_trait_ref: ty::PolyTraitRef<'tcx>,
     mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
     partitioned_bounds: PartitionedBounds)
     -> ty::ExistentialBounds<'tcx>
@@ -1588,16 +1667,15 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
     if !trait_bounds.is_empty() {
         let b = &trait_bounds[0];
         span_err!(this.tcx().sess, b.trait_ref.path.span, E0225,
-            "only the builtin traits can be used \
-                     as closure or object bounds");
+                  "only the builtin traits can be used as closure or object bounds");
     }
 
-    let region_bound = compute_region_bound(this,
-                                            rscope,
-                                            span,
-                                            &region_bounds,
-                                            principal_trait_ref,
-                                            builtin_bounds);
+    let region_bound = compute_object_lifetime_bound(this,
+                                                     rscope,
+                                                     span,
+                                                     &region_bounds,
+                                                     principal_trait_ref,
+                                                     builtin_bounds);
 
     ty::sort_bounds_list(&mut projection_bounds);
 
@@ -1608,17 +1686,21 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
     }
 }
 
-/// Given the bounds on a type parameter / existential type, determines what single region bound
+/// Given the bounds on an object, 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`.
-fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                  span: Span,
-                                  explicit_region_bounds: &[&ast::Lifetime],
-                                  principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
-                                  builtin_bounds: ty::BuiltinBounds)
-                                  -> Option<ty::Region>
+fn compute_object_lifetime_bound<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
+    span: Span,
+    explicit_region_bounds: &[&ast::Lifetime],
+    principal_trait_ref: ty::PolyTraitRef<'tcx>,
+    builtin_bounds: ty::BuiltinBounds)
+    -> ty::Region
 {
+    let tcx = this.tcx();
+
     debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
            principal_trait_ref={}, builtin_bounds={})",
            explicit_region_bounds,
@@ -1633,24 +1715,32 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
     if explicit_region_bounds.len() != 0 {
         // Explicitly specified region bound. Use that.
         let r = explicit_region_bounds[0];
-        return Some(ast_region_to_region(tcx, r));
+        return 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::object_region_bounds(tcx, principal_trait_ref.as_ref(), builtin_bounds);
+        object_region_bounds(tcx, &principal_trait_ref, builtin_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;
+        match rscope.object_lifetime_default(span) {
+            Some(r) => { return r; }
+            None => {
+                span_err!(this.tcx().sess, span, E0228,
+                          "the lifetime bound for this object type cannot be deduced \
+                           from context; please supply an explicit bound");
+                return ty::ReStatic;
+            }
+        }
     }
 
     // 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);
+        return ty::ReStatic;
     }
 
     // Determine whether there is exactly one unique region in the set
@@ -1659,38 +1749,42 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
     let r = derived_region_bounds[0];
     if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
         span_err!(tcx.sess, span, E0227,
-            "ambiguous lifetime bound, \
-                     explicit lifetime bound required");
+                  "ambiguous lifetime bound, explicit lifetime bound required");
     }
-    return Some(r);
+    return r;
 }
 
-/// 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.
-fn compute_region_bound<'tcx>(
-    this: &AstConv<'tcx>,
-    rscope: &RegionScope,
-    span: Span,
-    region_bounds: &[&ast::Lifetime],
-    principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
-    builtin_bounds: ty::BuiltinBounds)
-    -> ty::Region
+/// Given an object type like `SomeTrait+Send`, computes the lifetime
+/// bounds that must hold on the elided self type. These are derived
+/// from the declarations of `SomeTrait`, `Send`, and friends -- if
+/// they declare `trait SomeTrait : 'static`, for example, then
+/// `'static` would appear in the list. The hard work is done by
+/// `ty::required_region_bounds`, see that for more information.
+pub fn object_region_bounds<'tcx>(
+    tcx: &ty::ctxt<'tcx>,
+    principal: &ty::PolyTraitRef<'tcx>,
+    others: ty::BuiltinBounds)
+    -> Vec<ty::Region>
 {
-    match compute_opt_region_bound(this.tcx(), span, region_bounds,
-                                   principal_trait_ref, builtin_bounds) {
-        Some(r) => r,
-        None => {
-            match rscope.default_region_bound(span) {
-                Some(r) => { r }
-                None => {
-                    span_err!(this.tcx().sess, span, E0228,
-                        "explicit lifetime bound required");
-                    ty::ReStatic
-                }
-            }
-        }
-    }
+    // Since we don't actually *know* the self type for an object,
+    // this "open(err)" serves as a kind of dummy standin -- basically
+    // a skolemized type.
+    let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+
+    // Note that we preserve the overall binding levels here.
+    assert!(!open_ty.has_escaping_regions());
+    let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
+    let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
+
+    let param_bounds = ty::ParamBounds {
+        region_bounds: Vec::new(),
+        builtin_bounds: others,
+        trait_bounds: trait_refs,
+        projection_bounds: Vec::new(), // not relevant to computing region bounds
+    };
+
+    let predicates = ty::predicates(tcx, open_ty, &param_bounds);
+    ty::required_region_bounds(tcx, open_ty, predicates)
 }
 
 pub struct PartitionedBounds<'a> {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1c15e295ad9..30896c1607a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1890,7 +1890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
-    fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
+    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+        // RFC #599 specifies that object lifetime defaults take
+        // precedence over other defaults. But within a fn body we
+        // don't have a *default* region, rather we use inference to
+        // find the *correct* region, which is strictly more general
+        // (and anyway, within a fn body the right region may not even
+        // be something the user can write explicitly, since it might
+        // be some expression).
         Some(self.infcx().next_region_var(infer::MiscVariable(span)))
     }
 
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index bcb2ba6231d..17c259e674e 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -154,7 +154,7 @@ pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         // 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),
+        type_must_outlive(&mut rcx, infer::RelateParamBound(span, component_ty),
                           component_ty, ty::ReEmpty);
     }
 }
@@ -305,7 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
             debug!("visit_region_obligations: r_o={}",
                    r_o.repr(self.tcx()));
             let sup_type = self.resolve_type(r_o.sup_type);
-            let origin = infer::RelateRegionParamBound(r_o.cause.span);
+            let origin = infer::RelateParamBound(r_o.cause.span, sup_type);
             type_must_outlive(self, origin, sup_type, r_o.sub_region);
         }
 
diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs
index 4a0e2acc854..209570585d2 100644
--- a/src/librustc_typeck/check/regionmanip.rs
+++ b/src/librustc_typeck/check/regionmanip.rs
@@ -12,6 +12,7 @@
 
 pub use self::WfConstraint::*;
 
+use astconv::object_region_bounds;
 use middle::infer::GenericKind;
 use middle::subst::{ParamSpace, Subst, Substs};
 use middle::ty::{self, Ty};
@@ -95,7 +96,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
 
             ty::ty_trait(ref t) => {
                 let required_region_bounds =
-                    ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds);
+                    object_region_bounds(self.tcx, &t.principal, t.bounds.builtin_bounds);
                 self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
             }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 8a1945c16a6..f26041dbbe1 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -86,6 +86,7 @@ There are some shortcomings in this design:
 */
 
 use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
+use middle::def;
 use middle::lang_items::SizedTraitLangItem;
 use middle::region;
 use middle::resolve_lifetime;
@@ -1199,8 +1200,23 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                                              predicates.clone());
     assert!(prev_predicates.is_none());
 
-    return (scheme, predicates);
+    // Debugging aid.
+    if ty::has_attr(tcx, local_def(it.id), "rustc_object_lifetime_default") {
+        let object_lifetime_default_reprs: String =
+            scheme.generics.types.iter()
+                                 .map(|t| match t.object_lifetime_default {
+                                     Some(ty::ObjectLifetimeDefault::Specific(r)) =>
+                                         r.user_string(tcx),
+                                     d =>
+                                         d.repr(ccx.tcx()),
+                                 })
+                                 .collect::<Vec<String>>()
+                                 .connect(",");
+
+        tcx.sess.span_err(it.span, &object_lifetime_default_reprs);
+    }
 
+    return (scheme, predicates);
 }
 
 fn type_scheme_of_foreign_item<'a, 'tcx>(
@@ -1269,6 +1285,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                 subst::TypeSpace,
                 &generics.lifetimes[],
                 &generics.ty_params[],
+                &generics.where_clause,
                 ty::Generics::empty())
 }
 
@@ -1298,6 +1315,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                     subst::TypeSpace,
                     &ast_generics.lifetimes[],
                     &ast_generics.ty_params[],
+                    &ast_generics.where_clause,
                     ty::Generics::empty());
 
     // Add in the self type parameter.
@@ -1321,7 +1339,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
             trait_bounds: vec!(ty::Binder(self_trait_ref.clone())),
             projection_bounds: vec!(),
         },
-        default: None
+        default: None,
+        object_lifetime_default: None,
     };
 
     ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
@@ -1341,6 +1360,7 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                 subst::FnSpace,
                 &early_lifetimes[],
                 &generics.ty_params[],
+                &generics.where_clause,
                 base_generics)
 }
 
@@ -1487,6 +1507,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                         space: subst::ParamSpace,
                         lifetime_defs: &[ast::LifetimeDef],
                         types: &[ast::TyParam],
+                        where_clause: &ast::WhereClause,
                         base_generics: ty::Generics<'tcx>)
                         -> ty::Generics<'tcx>
 {
@@ -1511,7 +1532,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
 
     // Now create the real type parameters.
     for (i, param) in types.iter().enumerate() {
-        let def = get_or_create_type_parameter_def(ccx, space, param, i as u32);
+        let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause);
         debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
         result.types.push(space, def);
     }
@@ -1522,7 +1543,8 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
 fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                                              space: subst::ParamSpace,
                                              param: &ast::TyParam,
-                                             index: u32)
+                                             index: u32,
+                                             where_clause: &ast::WhereClause)
                                              -> ty::TypeParameterDef<'tcx>
 {
     let tcx = ccx.tcx;
@@ -1558,13 +1580,17 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
         }
     };
 
+    let object_lifetime_default =
+        compute_object_lifetime_default(ccx, space, index, &param.bounds, where_clause);
+
     let def = ty::TypeParameterDef {
         space: space,
         index: index,
         name: param.ident.name,
         def_id: local_def(param.id),
         bounds: bounds,
-        default: default
+        default: default,
+        object_lifetime_default: object_lifetime_default,
     };
 
     tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
@@ -1572,6 +1598,99 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
     def
 }
 
+/// Scan the bounds and where-clauses on a parameter to extract bounds
+/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`.
+/// This runs as part of computing the minimal type scheme, so we
+/// intentionally avoid just asking astconv to convert all the where
+/// clauses into a `ty::Predicate`. This is because that could induce
+/// artificial cycles.
+fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                            space: subst::ParamSpace,
+                                            index: u32,
+                                            param_bounds: &[ast::TyParamBound],
+                                            where_clause: &ast::WhereClause)
+                                            -> Option<ty::ObjectLifetimeDefault>
+{
+    let inline_bounds = from_bounds(ccx, param_bounds);
+    let where_bounds = from_predicates(ccx, space, index, &where_clause.predicates);
+    let all_bounds: HashSet<_> = inline_bounds.into_iter()
+                                              .chain(where_bounds.into_iter())
+                                              .collect();
+    return if all_bounds.len() > 1 {
+        Some(ty::ObjectLifetimeDefault::Ambiguous)
+    } else {
+        all_bounds.into_iter()
+                  .next()
+                  .map(ty::ObjectLifetimeDefault::Specific)
+    };
+
+    fn from_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                            bounds: &[ast::TyParamBound])
+                            -> Vec<ty::Region>
+    {
+        bounds.iter()
+              .filter_map(|bound| {
+                  match *bound {
+                      ast::TraitTyParamBound(..) =>
+                          None,
+                      ast::RegionTyParamBound(ref lifetime) =>
+                          Some(astconv::ast_region_to_region(ccx.tcx(), lifetime)),
+                  }
+              })
+              .collect()
+    }
+
+    fn from_predicates<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                space: subst::ParamSpace,
+                                index: u32,
+                                predicates: &[ast::WherePredicate])
+                                -> Vec<ty::Region>
+    {
+        predicates.iter()
+                  .flat_map(|predicate| {
+                      match *predicate {
+                          ast::WherePredicate::BoundPredicate(ref data) => {
+                              if data.bound_lifetimes.len() == 0 &&
+                                  is_param(ccx, &data.bounded_ty, space, index)
+                              {
+                                  from_bounds(ccx, &data.bounds).into_iter()
+                              } else {
+                                  Vec::new().into_iter()
+                              }
+                          }
+                          ast::WherePredicate::RegionPredicate(..) |
+                          ast::WherePredicate::EqPredicate(..) => {
+                              Vec::new().into_iter()
+                          }
+                      }
+                  })
+                  .collect()
+    }
+
+    fn is_param(ccx: &CollectCtxt,
+                ast_ty: &ast::Ty,
+                space: subst::ParamSpace,
+                index: u32)
+                -> bool
+    {
+        match ast_ty.node {
+            ast::TyPath(_, id) => {
+                match ccx.tcx.def_map.borrow()[id] {
+                    def::DefTyParam(s, i, _, _) => {
+                        space == s && index == i
+                    }
+                    _ => {
+                        false
+                    }
+                }
+            }
+            _ => {
+                false
+            }
+        }
+    }
+}
+
 enum SizedByDefault { Yes, No }
 
 /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs
index 60e969c4f99..b591209a638 100644
--- a/src/librustc_typeck/rscope.rs
+++ b/src/librustc_typeck/rscope.rs
@@ -32,7 +32,10 @@ pub trait RegionScope {
                     count: uint)
                     -> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>;
 
-    fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
+    /// If an object omits any explicit lifetime bound, and none can
+    /// be derived from the object traits, what should we use? If
+    /// `None` is returned, an explicit annotation is required.
+    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
 }
 
 // A scope in which all regions must be explicitly named. This is used
@@ -41,8 +44,8 @@ pub trait RegionScope {
 pub struct ExplicitRscope;
 
 impl RegionScope for ExplicitRscope {
-    fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
-        None
+    fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
+        Some(ty::ReStatic)
     }
 
     fn anon_regions(&self,
@@ -63,8 +66,8 @@ impl UnelidableRscope {
 }
 
 impl RegionScope for UnelidableRscope {
-    fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
-        None
+    fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
+        Some(ty::ReStatic)
     }
 
     fn anon_regions(&self,
@@ -76,22 +79,26 @@ impl RegionScope for UnelidableRscope {
     }
 }
 
-// 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
+// A scope in which omitted anonymous region defaults to
+// `default`. This is used after the `->` in function signatures. The
+// latter use may go away. Note that object-lifetime defaults work a
+// bit differently, as specified in RFC #599.
+pub struct ElidableRscope {
+    default: ty::Region,
 }
 
-impl SpecificRscope {
-    pub fn new(r: ty::Region) -> SpecificRscope {
-        SpecificRscope { default: r }
+impl ElidableRscope {
+    pub fn new(r: ty::Region) -> ElidableRscope {
+        ElidableRscope { default: r }
     }
 }
 
-impl RegionScope for SpecificRscope {
-    fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
-        Some(self.default)
+impl RegionScope for ElidableRscope {
+    fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
+        // Per RFC #599, object-lifetimes default to 'static unless
+        // overridden by context, and this takes precedence over
+        // lifetime elision.
+        Some(ty::ReStatic)
     }
 
     fn anon_regions(&self,
@@ -124,9 +131,11 @@ impl BindingRscope {
 }
 
 impl RegionScope for BindingRscope {
-    fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
-    {
-        Some(self.next_region())
+    fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
+        // Per RFC #599, object-lifetimes default to 'static unless
+        // overridden by context, and this takes precedence over the
+        // binding defaults.
+        Some(ty::ReStatic)
     }
 
     fn anon_regions(&self,
@@ -138,6 +147,42 @@ impl RegionScope for BindingRscope {
     }
 }
 
+/// A scope which overrides the default object lifetime but has no other effect.
+pub struct ObjectLifetimeDefaultRscope<'r> {
+    base_scope: &'r (RegionScope+'r),
+    default: Option<ty::ObjectLifetimeDefault>,
+}
+
+impl<'r> ObjectLifetimeDefaultRscope<'r> {
+    pub fn new(base_scope: &'r (RegionScope+'r),
+               default: Option<ty::ObjectLifetimeDefault>)
+               -> ObjectLifetimeDefaultRscope<'r>
+    {
+        ObjectLifetimeDefaultRscope {
+            base_scope: base_scope,
+            default: default,
+        }
+    }
+}
+
+impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
+    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+        match self.default {
+            None => self.base_scope.object_lifetime_default(span),
+            Some(ty::ObjectLifetimeDefault::Ambiguous) => None,
+            Some(ty::ObjectLifetimeDefault::Specific(r)) => Some(r),
+        }
+    }
+
+    fn anon_regions(&self,
+                    span: Span,
+                    count: uint)
+                    -> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>
+    {
+        self.base_scope.anon_regions(span, count)
+    }
+}
+
 /// A scope which simply shifts the Debruijn index of other scopes
 /// to account for binding levels.
 pub struct ShiftedRscope<'r> {
@@ -151,9 +196,8 @@ impl<'r> ShiftedRscope<'r> {
 }
 
 impl<'r> RegionScope for ShiftedRscope<'r> {
-    fn default_region_bound(&self, span: Span) -> Option<ty::Region>
-    {
-        self.base_scope.default_region_bound(span)
+    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+        self.base_scope.object_lifetime_default(span)
             .map(|r| ty_fold::shift_region(r, 1))
     }
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 64ae6162ef4..083039995ee 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -35,18 +35,18 @@ pub trait ItemDecorator {
               sp: Span,
               meta_item: &ast::MetaItem,
               item: &ast::Item,
-              push: Box<FnMut(P<ast::Item>)>);
+              push: &mut FnMut(P<ast::Item>));
 }
 
 impl<F> ItemDecorator for F
-    where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, Box<FnMut(P<ast::Item>)>)
+    where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P<ast::Item>))
 {
     fn expand(&self,
               ecx: &mut ExtCtxt,
               sp: Span,
               meta_item: &ast::MetaItem,
               item: &ast::Item,
-              push: Box<FnMut(P<ast::Item>)>) {
+              push: &mut FnMut(P<ast::Item>)) {
         (*self)(ecx, sp, meta_item, item, push)
     }
 }
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index 9c3fa58ad09..0ed9e85e576 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -72,7 +72,7 @@ pub fn expand_deprecated_deriving(cx: &mut ExtCtxt,
                                   span: Span,
                                   _: &MetaItem,
                                   _: &Item,
-                                  _: Box<FnMut(P<Item>)>) {
+                                  _: &mut FnMut(P<Item>)) {
     cx.span_err(span, "`deriving` has been renamed to `derive`");
 }
 
@@ -80,7 +80,7 @@ pub fn expand_meta_derive(cx: &mut ExtCtxt,
                           _span: Span,
                           mitem: &MetaItem,
                           item: &Item,
-                          mut push: Box<FnMut(P<Item>)>) {
+                          push: &mut FnMut(P<Item>)) {
     match mitem.node {
         MetaNameValue(_, ref l) => {
             cx.span_err(l.span, "unexpected value in `derive`");
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 131bbc41005..fd98f42c2ab 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -363,7 +363,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac, span: codemap::Span,
                              mark_thunk: G,
                              fld: &mut MacroExpander)
                              -> Option<T> where
-    F: FnOnce(Box<MacResult>) -> Option<T>,
+    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
     G: FnOnce(T, Mrk) -> T,
 {
     match mac.node {
@@ -1102,9 +1102,10 @@ fn expand_annotatable(a: Annotatable,
                     // but that double-mut-borrows fld
                     let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
                     dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
-                               box |item| items.push(item));
-                    decorator_items.extend(items.into_iter()
-                        .flat_map(|item| expand_item(item, fld).into_iter()));
+                               &mut |item| items.push(item));
+                    decorator_items.extend(
+                        items.into_iter()
+                             .flat_map(|item| expand_item(item, fld).into_iter()));
 
                     fld.cx.bt_pop();
                 }
diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs
index 2c689f6909b..c7b75ade555 100644
--- a/src/test/compile-fail/builtin-superkinds-simple.rs
+++ b/src/test/compile-fail/builtin-superkinds-simple.rs
@@ -14,6 +14,6 @@
 trait Foo : Send { }
 
 impl <'a> Foo for &'a mut () { }
-//~^ ERROR declared lifetime bound not satisfied
+//~^ ERROR the type `&'a mut ()` does not fulfill the required lifetime
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-11374.rs b/src/test/compile-fail/issue-11374.rs
index 6dbea33d7d5..09d7293a3d0 100644
--- a/src/test/compile-fail/issue-11374.rs
+++ b/src/test/compile-fail/issue-11374.rs
@@ -12,7 +12,7 @@ use std::old_io;
 use std::vec;
 
 pub struct Container<'a> {
-    reader: &'a mut Reader //~ ERROR explicit lifetime bound required
+    reader: &'a mut Reader
 }
 
 impl<'a> Container<'a> {
@@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
 fn main() {
     let mut c = for_stdin();
     let mut v = Vec::new();
-    c.read_to(v);
+    c.read_to(v); //~ ERROR mismatched types
 }
diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs
index fef414ce978..81424577d49 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(Box<FnMut()>); //~ ERROR explicit lifetime bound required
-pub static C: S = S(f);
+struct S(Box<FnMut()>);
+pub static C: S = S(f); //~ ERROR mismatched types
 
 
 fn g() { }
-type T = Box<FnMut()>;  //~ ERROR explicit lifetime bound required
-pub static D: T = g;
+type T = Box<FnMut()>;
+pub static D: T = g; //~ ERROR mismatched types
 
 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 5d090689415..de7639c6213 100644
--- a/src/test/compile-fail/kindck-impl-type-params.rs
+++ b/src/test/compile-fail/kindck-impl-type-params.rs
@@ -36,7 +36,7 @@ fn g<T>(val: T) {
 fn foo<'a>() {
     let t: S<&'a isize> = S;
     let a = &t as &Gettable<&'a isize>;
-    //~^ ERROR declared lifetime bound not satisfied
+    //~^ ERROR the type `&'a isize` does not fulfill the required lifetime
 }
 
 fn foo2<'a>() {
diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs
index c781fffff2d..3d47d33d7c3 100644
--- a/src/test/compile-fail/kindck-send-object1.rs
+++ b/src/test/compile-fail/kindck-send-object1.rs
@@ -22,7 +22,7 @@ fn test51<'a>() {
 }
 fn test52<'a>() {
     assert_send::<&'a (Dummy+Send)>();
-    //~^ ERROR declared lifetime bound not satisfied
+    //~^ ERROR does not fulfill the required lifetime
 }
 
 // ...unless they are properly bounded
diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs
index 7025249fafb..266b6156656 100644
--- a/src/test/compile-fail/kindck-send-owned.rs
+++ b/src/test/compile-fail/kindck-send-owned.rs
@@ -19,7 +19,7 @@ fn test32() { assert_send::<Vec<isize> >(); }
 
 // but not if they own a bad thing
 fn test40<'a>(_: &'a isize) {
-    assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/kindck-send-region-pointers.rs b/src/test/compile-fail/kindck-send-region-pointers.rs
index c6987e89e3a..e2a5b0678a6 100644
--- a/src/test/compile-fail/kindck-send-region-pointers.rs
+++ b/src/test/compile-fail/kindck-send-region-pointers.rs
@@ -22,13 +22,13 @@ fn test10() { assert_send::<&'static mut isize>(); }
 
 // otherwise lifetime pointers are not ok
 fn test20<'a>(_: &'a isize) {
-    assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
 }
 fn test21<'a>(_: &'a isize) {
-    assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
 }
 fn test22<'a>(_: &'a isize) {
-    assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/object-lifetime-default-ambiguous.rs b/src/test/compile-fail/object-lifetime-default-ambiguous.rs
new file mode 100644
index 00000000000..322283a4ca9
--- /dev/null
+++ b/src/test/compile-fail/object-lifetime-default-ambiguous.rs
@@ -0,0 +1,61 @@
+// Copyright 2015 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 if a struct declares multiple region bounds for a given
+// type parameter, an explicit lifetime bound is required on object
+// lifetimes within.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct Ref0<T:?Sized> {
+    r: *mut T
+}
+
+struct Ref1<'a,T:'a+?Sized> {
+    r: &'a T
+}
+
+struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
+    r: &'a &'b T
+}
+
+fn a<'a,'b>(t: Ref2<'a,'b,Test>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+}
+
+fn b(t: Ref2<Test>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+}
+
+fn c(t: Ref2<&Test>) {
+    // In this case, the &'a overrides.
+}
+
+fn d(t: Ref2<Ref1<Test>>) {
+    // In this case, the lifetime parameter from the Ref1 overrides.
+}
+
+fn e(t: Ref2<Ref0<Test>>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+    //
+    // In this case, Ref2 is ambiguous, and Ref0 inherits the
+    // ambiguity.
+}
+
+fn f(t: &Ref2<Test>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs
new file mode 100644
index 00000000000..0077d10e6ca
--- /dev/null
+++ b/src/test/compile-fail/object-lifetime-default-elision.rs
@@ -0,0 +1,89 @@
+// Copyright 2015 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 various cases where the old rules under lifetime elision
+// yield slightly different results than the new rules.
+
+#![allow(dead_code)]
+
+trait SomeTrait {
+    fn dummy(&self) { }
+}
+
+struct SomeStruct<'a> {
+    r: Box<SomeTrait+'a>
+}
+
+fn deref<T>(ss: &T) -> T {
+    // produces the type of a deref without worrying about whether a
+    // move out would actually be legal
+    loop { }
+}
+
+fn load0<'a>(ss: &'a Box<SomeTrait>) -> Box<SomeTrait> {
+    // Under old rules, the fully elaborated types of input/output were:
+    //
+    // for<'a,'b> fn(&'a Box<SomeTrait+'b>) -> Box<SomeTrait+'a>
+    //
+    // Under new rules the result is:
+    //
+    // for<'a> fn(&'a Box<SomeTrait+'a>) -> Box<SomeTrait+'static>
+    //
+    // Therefore, we get a type error attempting to return `deref(ss)`
+    // since `SomeTrait+'a <: SomeTrait+'static` does not hold.
+
+    deref(ss)
+        //~^ ERROR cannot infer
+}
+
+fn load1(ss: &SomeTrait) -> &SomeTrait {
+    // Under old rules, the fully elaborated types of input/output were:
+    //
+    // for<'a,'b> fn(&'a (SomeTrait+'b)) -> &'a (SomeTrait+'a)
+    //
+    // Under new rules the result is:
+    //
+    // for<'a> fn(&'a (SomeTrait+'a)) -> &'a (SomeTrait+'a)
+    //
+    // In both cases, returning `ss` is legal.
+
+    ss
+}
+
+fn load2<'a>(ss: &'a SomeTrait) -> &SomeTrait {
+    // Same as `load1` but with an explicit name thrown in for fun.
+
+    ss
+}
+
+fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
+    // Under old rules, the fully elaborated types of input/output were:
+    //
+    // for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a)
+    //
+    // Based on the input/output types, the compiler could infer that
+    //     'c : 'a
+    //     'b : 'a
+    // must hold, and therefore it permitted `&'a (Sometrait+'c)` to be
+    // coerced to `&'b (SomeTrait+'a)`.
+    //
+    // Under the newer defaults, though, we get:
+    //
+    // for<'a,'b> fn(&'a (SomeTrait+'a)) -> &'b (SomeTrait+'b)
+    //
+    // which fails to type check.
+
+    ss
+        //~^ ERROR cannot infer
+        //~| ERROR mismatched types
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs
new file mode 100644
index 00000000000..70752cbfda1
--- /dev/null
+++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs
@@ -0,0 +1,45 @@
+// Copyright 2015 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 various cases where the defaults should lead to errors being
+// reported.
+
+#![allow(dead_code)]
+
+trait SomeTrait {
+    fn dummy(&self) { }
+}
+
+struct SomeStruct<'a> {
+    r: Box<SomeTrait+'a>
+}
+
+fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
+    // `Box<SomeTrait>` defaults to a `'static` bound, so this return
+    // is illegal.
+
+    ss.r //~ ERROR mismatched types
+}
+
+fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
+    // No error: b is bounded by 'static which outlives the
+    // (anonymous) lifetime on the struct.
+
+    ss.r = b;
+}
+
+fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
+    // Here we override the lifetimes explicitly, and so naturally we get an error.
+
+    ss.r = b; //~ ERROR mismatched types
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/object-lifetime-default-mybox.rs b/src/test/compile-fail/object-lifetime-default-mybox.rs
new file mode 100644
index 00000000000..c107c8d131d
--- /dev/null
+++ b/src/test/compile-fail/object-lifetime-default-mybox.rs
@@ -0,0 +1,44 @@
+// Copyright 2015 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 a "pass-through" object-lifetime-default that produces errors.
+
+#![allow(dead_code)]
+
+trait SomeTrait {
+    fn dummy(&self) { }
+}
+
+struct MyBox<T:?Sized> {
+    r: Box<T>
+}
+
+fn deref<T>(ss: &T) -> T {
+    // produces the type of a deref without worrying about whether a
+    // move out would actually be legal
+    loop { }
+}
+
+fn load0(ss: &MyBox<SomeTrait>) -> MyBox<SomeTrait> {
+    deref(ss) //~ ERROR cannot infer
+}
+
+fn load1<'a,'b>(a: &'a MyBox<SomeTrait>,
+                b: &'b MyBox<SomeTrait>)
+                -> &'b MyBox<SomeTrait>
+{
+    a
+      //~^ ERROR cannot infer
+      //~| ERROR mismatched types
+      //~| ERROR mismatched types
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/object-lifetime-default.rs b/src/test/compile-fail/object-lifetime-default.rs
new file mode 100644
index 00000000000..73f71751ee8
--- /dev/null
+++ b/src/test/compile-fail/object-lifetime-default.rs
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+#[rustc_object_lifetime_default]
+struct A<T>(T); //~ ERROR None
+
+#[rustc_object_lifetime_default]
+struct B<'a,T>(&'a (), T); //~ ERROR None
+
+#[rustc_object_lifetime_default]
+struct C<'a,T:'a>(&'a T); //~ ERROR 'a
+
+#[rustc_object_lifetime_default]
+struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous
+
+#[rustc_object_lifetime_default]
+struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b
+
+#[rustc_object_lifetime_default]
+struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b
+
+#[rustc_object_lifetime_default]
+struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous
+
+fn main() { }
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
index 6b3c92e0028..b8cbbdbe9ec 100644
--- 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
@@ -25,7 +25,7 @@ struct Foo<'a,'b,'c> {
     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
+    f: Box<SomeTrait>,   // OK, defaults to 'static due to RFC 599.
     g: Box<SomeTrait+'a>,
 
     z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted
diff --git a/src/test/compile-fail/region-object-lifetime-1.rs b/src/test/compile-fail/region-object-lifetime-1.rs
index 4758ce71fff..bb37d55fb08 100644
--- a/src/test/compile-fail/region-object-lifetime-1.rs
+++ b/src/test/compile-fail/region-object-lifetime-1.rs
@@ -11,6 +11,8 @@
 // Various tests related to testing how region inference works
 // with respect to the object receivers.
 
+#![allow(warnings)]
+
 trait Foo {
     fn borrowed<'a>(&'a self) -> &'a ();
 }
@@ -21,29 +23,6 @@ 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() {}
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
 
diff --git a/src/test/compile-fail/region-object-lifetime-2.rs b/src/test/compile-fail/region-object-lifetime-2.rs
new file mode 100644
index 00000000000..f9bf4e257b3
--- /dev/null
+++ b/src/test/compile-fail/region-object-lifetime-2.rs
@@ -0,0 +1,24 @@
+// 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 ();
+}
+
+// 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
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/region-object-lifetime-3.rs b/src/test/compile-fail/region-object-lifetime-3.rs
new file mode 100644
index 00000000000..7f00334f67e
--- /dev/null
+++ b/src/test/compile-fail/region-object-lifetime-3.rs
@@ -0,0 +1,28 @@
+// 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.
+
+#![allow(warnings)]
+
+trait Foo {
+    fn borrowed<'a>(&'a self) -> &'a ();
+}
+
+// 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()
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
+
diff --git a/src/test/compile-fail/region-object-lifetime-4.rs b/src/test/compile-fail/region-object-lifetime-4.rs
new file mode 100644
index 00000000000..fe0ff8dc3fe
--- /dev/null
+++ b/src/test/compile-fail/region-object-lifetime-4.rs
@@ -0,0 +1,26 @@
+// 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 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
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/region-object-lifetime-5.rs b/src/test/compile-fail/region-object-lifetime-5.rs
new file mode 100644
index 00000000000..f07f753d825
--- /dev/null
+++ b/src/test/compile-fail/region-object-lifetime-5.rs
@@ -0,0 +1,25 @@
+// 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 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 `*x` does not live long enough
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs
index e4521873a61..20cc624ab19 100644
--- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs
+++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs
@@ -17,20 +17,22 @@ trait Foo {}
 impl<'a> Foo for &'a [u8] {}
 
 fn a(v: &[u8]) -> Box<Foo + 'static> {
-    let x: Box<Foo + 'static> = box v; //~ ERROR declared lifetime bound not satisfied
+    let x: Box<Foo + 'static> = box v; //~ ERROR does not fulfill the required lifetime
     x
 }
 
 fn b(v: &[u8]) -> Box<Foo + 'static> {
-    box v //~ ERROR declared lifetime bound not satisfied
+    box v //~ ERROR does not fulfill the required lifetime
 }
 
 fn c(v: &[u8]) -> Box<Foo> {
-    box v // OK thanks to lifetime elision
+    // same as previous case due to RFC 599
+
+    box v //~ ERROR does not fulfill the required lifetime
 }
 
 fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
-    box v //~ ERROR declared lifetime bound not satisfied
+    box v //~ ERROR does not fulfill the required lifetime
 }
 
 fn e<'a:'b,'b>(v: &'a [u8]) -> Box<Foo+'b> {
diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs
index e3f0d3bcdb6..71254e15d32 100644
--- a/src/test/compile-fail/regions-bounded-by-send.rs
+++ b/src/test/compile-fail/regions-bounded-by-send.rs
@@ -32,15 +32,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
 // otherwise lifetime pointers are not ok
 
 fn param_not_ok<'a>(x: &'a isize) {
-    assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn param_not_ok1<'a>(_: &'a isize) {
-    assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn param_not_ok2<'a>(_: &'a isize) {
-    assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
 }
 
 // boxes are ok
@@ -54,7 +54,7 @@ fn box_ok() {
 // but not if they own a bad thing
 
 fn box_with_region_not_ok<'a>() {
-    assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
 }
 
 // objects with insufficient bounds no ok
@@ -66,7 +66,7 @@ fn object_with_random_bound_not_ok<'a>() {
 
 fn object_with_send_bound_not_ok<'a>() {
     assert_send::<&'a (Dummy+Send)>();
-    //~^ ERROR declared lifetime bound not satisfied
+    //~^ ERROR does not fulfill the required lifetime
 }
 
 // unsafe pointers are ok unless they point at unsendable things
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
index 8194af25d73..9e4c4e677cc 100644
--- a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs
+++ b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs
@@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
 // otherwise lifetime pointers are not ok
 
 fn param_not_ok<'a>(x: &'a isize) {
-    assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn param_not_ok1<'a>(_: &'a isize) {
-    assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn param_not_ok2<'a>(_: &'a isize) {
-    assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
 }
 
 // boxes are ok
@@ -51,7 +51,7 @@ fn box_ok() {
 // but not if they own a bad thing
 
 fn box_with_region_not_ok<'a>() {
-    assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
 }
 
 // unsafe pointers are ok unless they point at unsendable things
@@ -62,11 +62,11 @@ fn unsafe_ok1<'a>(_: &'a isize) {
 }
 
 fn unsafe_ok2<'a>(_: &'a isize) {
-    assert_send::<*const &'a isize>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn unsafe_ok3<'a>(_: &'a isize) {
-    assert_send::<*mut &'a isize>(); //~ ERROR declared lifetime bound not satisfied
+    assert_send::<*mut &'a isize>(); //~ ERROR does not fulfill the required lifetime
 }
 
 fn main() {
diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs
index 9afacacd662..da4e8231a23 100644
--- a/src/test/compile-fail/regions-bounded-method-type-parameters.rs
+++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs
@@ -20,7 +20,7 @@ impl Foo {
 
 fn caller<'a>(x: &isize) {
     Foo.some_method::<&'a isize>();
-    //~^ ERROR declared lifetime bound not satisfied
+    //~^ ERROR does not fulfill the required lifetime
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/regions-close-object-into-object.rs b/src/test/compile-fail/regions-close-object-into-object-1.rs
index 675f86b58f4..7a0e3cf4611 100644
--- a/src/test/compile-fail/regions-close-object-into-object.rs
+++ b/src/test/compile-fail/regions-close-object-into-object-1.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(box_syntax)]
+#![allow(warnings)]
 
 trait A<T> {}
 struct B<'a, T>(&'a (A<T>+'a));
@@ -17,19 +18,7 @@ trait X {}
 impl<'a, T> X for B<'a, T> {}
 
 fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
-    box B(&*v) as Box<X>
-}
-
-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, 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
+    box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-close-object-into-object-2.rs b/src/test/compile-fail/regions-close-object-into-object-2.rs
new file mode 100644
index 00000000000..7861fb95fef
--- /dev/null
+++ b/src/test/compile-fail/regions-close-object-into-object-2.rs
@@ -0,0 +1,23 @@
+// 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.
+
+#![feature(box_syntax)]
+
+trait A<T> {}
+struct B<'a, T>(&'a (A<T>+'a));
+
+trait X {}
+impl<'a, T> X for B<'a, T> {}
+
+fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
+    box B(&*v) as Box<X> //~ ERROR cannot infer
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/regions-close-object-into-object-3.rs b/src/test/compile-fail/regions-close-object-into-object-3.rs
new file mode 100644
index 00000000000..31354de2a27
--- /dev/null
+++ b/src/test/compile-fail/regions-close-object-into-object-3.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(box_syntax)]
+#![allow(warnings)]
+
+trait A<T> {}
+struct B<'a, T>(&'a (A<T>+'a));
+
+trait X {}
+impl<'a, T> X for B<'a, T> {}
+
+fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
+    box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/regions-close-object-into-object-4.rs b/src/test/compile-fail/regions-close-object-into-object-4.rs
new file mode 100644
index 00000000000..c60975f97e1
--- /dev/null
+++ b/src/test/compile-fail/regions-close-object-into-object-4.rs
@@ -0,0 +1,24 @@
+// 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.
+
+#![feature(box_syntax)]
+
+trait A<T> {}
+struct B<'a, T>(&'a (A<T>+'a));
+
+trait X {}
+impl<'a, T> X for B<'a, T> {}
+
+fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
+    box B(&*v) as Box<X> //~ ERROR cannot infer
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/seq-args.rs b/src/test/compile-fail/seq-args.rs
index b4929eacf3d..44b049d6561 100644
--- a/src/test/compile-fail/seq-args.rs
+++ b/src/test/compile-fail/seq-args.rs
@@ -14,7 +14,7 @@ trait seq { }
 impl<T> seq<T> for Vec<T> { //~ ERROR wrong number of type arguments
     /* ... */
 }
-impl seq<bool> for u32 {
+impl seq<bool> for u32 { //~ ERROR wrong number of type arguments
    /* Treat the integer as a sequence of bits */
 }
 
diff --git a/src/test/compile-fail/structure-constructor-type-mismatch.rs b/src/test/compile-fail/structure-constructor-type-mismatch.rs
index a82c05c72c3..c276228b18e 100644
--- a/src/test/compile-fail/structure-constructor-type-mismatch.rs
+++ b/src/test/compile-fail/structure-constructor-type-mismatch.rs
@@ -57,6 +57,7 @@ fn main() {
 
     let pt3 = PointF::<i32> {
         //~^ ERROR wrong number of type arguments
+        //~| ERROR structure constructor specifies a structure of type
         x: 9i32,
         y: 10i32,
     };
diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs
index 79174552ae0..89e89cf8246 100644
--- a/src/test/compile-fail/trait-bounds-cant-coerce.rs
+++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs
@@ -22,7 +22,7 @@ fn c(x: Box<Foo+Sync+Send>) {
 fn d(x: Box<Foo>) {
     a(x); //~  ERROR mismatched types
           //~| expected `Box<Foo + Send>`
-          //~| found `Box<Foo>`
+          //~| found `Box<Foo + 'static>`
           //~| expected bounds `Send`
           //~| found no bounds
 }
diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs
index 4da496621d1..3d264e681a3 100644
--- a/src/test/compile-fail/trait-bounds-sugar.rs
+++ b/src/test/compile-fail/trait-bounds-sugar.rs
@@ -24,8 +24,7 @@ fn c(x: Box<Foo+Sync>) {
 }
 
 fn d(x: &'static (Foo+Sync)) {
-    b(x); //~ ERROR cannot infer
-    //~^ ERROR mismatched types
+    b(x);
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
index dcfcb7d4772..9f0682df3fe 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
@@ -12,7 +12,9 @@
 
 trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
 
-fn foo(_: &Three()) //~ ERROR wrong number of type arguments
+fn foo(_: &Three())
+//~^ ERROR wrong number of type arguments
+//~| ERROR no associated type `Output`
 {}
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
index a8ac62444aa..40635cf3ddd 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
@@ -12,7 +12,9 @@
 
 trait Zero { fn dummy(&self); }
 
-fn foo(_: Zero()) //~ ERROR wrong number of type arguments
+fn foo(_: Zero())
+    //~^ ERROR wrong number of type arguments
+    //~| ERROR no associated type `Output` defined in `Zero`
 {}
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
index e63f510b890..5810ffcf21a 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
@@ -14,6 +14,7 @@ trait Trait {}
 
 fn f<F:Trait(isize) -> isize>(x: F) {}
 //~^ ERROR wrong number of type arguments: expected 0, found 1
+//~| ERROR no associated type `Output`
 
 fn main() {}
 
diff --git a/src/test/run-pass/object-lifetime-default-default-to-static.rs b/src/test/run-pass/object-lifetime-default-default-to-static.rs
new file mode 100644
index 00000000000..c385a0195b6
--- /dev/null
+++ b/src/test/run-pass/object-lifetime-default-default-to-static.rs
@@ -0,0 +1,42 @@
+// Copyright 2015 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 `Box<Test>` is equivalent to `Box<Test+'static>`, both in
+// fields and fn arguments.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct {
+    t: Box<Test>,
+    u: Box<Test+'static>,
+}
+
+fn a(t: Box<Test>, mut ss: SomeStruct) {
+    ss.t = t;
+}
+
+fn b(t: Box<Test+'static>, mut ss: SomeStruct) {
+    ss.t = t;
+}
+
+fn c(t: Box<Test>, mut ss: SomeStruct) {
+    ss.u = t;
+}
+
+fn d(t: Box<Test+'static>, mut ss: SomeStruct) {
+    ss.u = t;
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs
new file mode 100644
index 00000000000..24da9603679
--- /dev/null
+++ b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs
@@ -0,0 +1,47 @@
+// Copyright 2015 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 the lifetime of the enclosing `&` is used for the object
+// lifetime bound.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct Ref<'a,T:'a+?Sized> {
+    r: &'a T
+}
+
+struct SomeStruct<'a> {
+    t: Ref<'a,Test>,
+    u: Ref<'a,Test+'a>,
+}
+
+fn a<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+
+fn main() {
+}
diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-box.rs b/src/test/run-pass/object-lifetime-default-from-rptr-box.rs
new file mode 100644
index 00000000000..825800e1d44
--- /dev/null
+++ b/src/test/run-pass/object-lifetime-default-from-rptr-box.rs
@@ -0,0 +1,42 @@
+// Copyright 2015 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 the lifetime from the enclosing `&` is "inherited"
+// through the `Box` struct.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a Box<Test>,
+    u: &'a Box<Test+'a>,
+}
+
+fn a<'a>(t: &'a Box<Test>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a Box<Test>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs b/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs
new file mode 100644
index 00000000000..0f34d945c8f
--- /dev/null
+++ b/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs
@@ -0,0 +1,43 @@
+// Copyright 2015 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 the lifetime of the enclosing `&` is used for the object
+// lifetime bound.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a mut Test,
+    u: &'a mut (Test+'a),
+}
+
+fn a<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+
+fn main() {
+}
diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-struct.rs b/src/test/run-pass/object-lifetime-default-from-rptr-struct.rs
new file mode 100644
index 00000000000..9d5dac536f1
--- /dev/null
+++ b/src/test/run-pass/object-lifetime-default-from-rptr-struct.rs
@@ -0,0 +1,46 @@
+// Copyright 2015 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 the lifetime from the enclosing `&` is "inherited"
+// through the `MyBox` struct.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a MyBox<Test>,
+    u: &'a MyBox<Test+'a>,
+}
+
+struct MyBox<T:?Sized> {
+    b: Box<T>
+}
+
+fn a<'a>(t: &'a MyBox<Test>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a MyBox<Test>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs
new file mode 100644
index 00000000000..b7a28a5c524
--- /dev/null
+++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs
@@ -0,0 +1,43 @@
+// Copyright 2015 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 the lifetime of the enclosing `&` is used for the object
+// lifetime bound.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a Test,
+    u: &'a (Test+'a),
+}
+
+fn a<'a>(t: &'a Test, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a Test, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+
+fn main() {
+}