about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-20 06:28:16 +0000
committerbors <bors@rust-lang.org>2017-04-20 06:28:16 +0000
commitfa6b50fc6282a2c64814b35b16464a22f4ae9265 (patch)
tree3c2914f8b96d35eed2b3cbe0a27bc7b89be4272e
parent1bb1530239c801bb46b705eb2874ac4e5b213e54 (diff)
parent204243fcac7dfb646c37cab0138fc037dcb0bd53 (diff)
downloadrust-fa6b50fc6282a2c64814b35b16464a22f4ae9265.tar.gz
rust-fa6b50fc6282a2c64814b35b16464a22f4ae9265.zip
Auto merge of #41413 - frewsxcv:rollup, r=frewsxcv
Rollup of 5 pull requests

- Successful merges: #41214, #41369, #41377, #41378, #41390
- Failed merges:
-rw-r--r--src/librustc/infer/mod.rs10
-rw-r--r--src/librustc/traits/coherence.rs8
-rw-r--r--src/librustc/traits/error_reporting.rs28
-rw-r--r--src/librustc/traits/fulfill.rs10
-rw-r--r--src/librustc/traits/specialize/mod.rs7
-rw-r--r--src/librustc_driver/test.rs6
-rw-r--r--src/librustc_trans/cabi_x86_64.rs6
-rw-r--r--src/librustc_typeck/check/compare_method.rs7
-rw-r--r--src/librustc_typeck/check/dropck.rs5
-rw-r--r--src/librustc_typeck/lib.rs17
-rw-r--r--src/libstd/ffi/os_str.rs18
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/path.rs12
-rw-r--r--src/libsyntax/codemap.rs19
-rw-r--r--src/stage0.txt2
-rw-r--r--src/test/run-make/extern-fn-struct-passing-abi/test.c15
-rw-r--r--src/test/run-make/extern-fn-struct-passing-abi/test.rs8
-rw-r--r--src/test/run-pass/issue-41298.rs16
-rw-r--r--src/test/ui/resolve/issue-3907-2.stderr2
-rw-r--r--src/test/ui/span/E0072.rs (renamed from src/test/compile-fail/E0072.rs)3
-rw-r--r--src/test/ui/span/E0072.stderr10
-rw-r--r--src/test/ui/span/multiline-span-E0072.rs20
-rw-r--r--src/test/ui/span/multiline-span-E0072.stderr16
23 files changed, 197 insertions, 49 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index a1bafe113e4..4d8b31a33cd 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1597,9 +1597,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             // generic so we don't have to do anything quite this
             // terrible.
             let trace = TypeTrace::dummy(self.tcx);
-            self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| {
-                // FIXME(#32730) propagate obligations
-                assert!(obligations.is_empty());
+            self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| {
+                // We can intentionally ignore obligations here, since
+                // this is part of a simple test for general
+                // "equatability". However, it's not entirely clear
+                // that we *ought* to be, perhaps a better thing would
+                // be to use a mini-fulfillment context or something
+                // like that.
             })
         })
     }
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 383fab3fcd7..a943ef30e53 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -55,16 +55,15 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     debug!("overlap: b_impl_header={:?}", b_impl_header);
 
     // Do `a` and `b` unify? If not, no overlap.
-    match selcx.infcx().eq_impl_headers(true,
+    let obligations = match selcx.infcx().eq_impl_headers(true,
                                         &ObligationCause::dummy(),
                                         &a_impl_header,
                                         &b_impl_header) {
         Ok(InferOk { obligations, .. }) => {
-            // FIXME(#32730) propagate obligations
-            assert!(obligations.is_empty());
+            obligations
         }
         Err(_) => return None
-    }
+    };
 
     debug!("overlap: unification check succeeded");
 
@@ -78,6 +77,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
                      .map(|p| Obligation { cause: ObligationCause::dummy(),
                                            recursion_depth: 0,
                                            predicate: p })
+                     .chain(obligations)
                      .find(|o| !selcx.evaluate_obligation(o));
 
     if let Some(failing_obligation) = opt_failing_obligation {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 71dff3b2bb9..ba340a40692 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -329,22 +329,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 Some(val) => Some(val),
                                 None => {
                                     span_err!(self.tcx.sess, err_sp, E0272,
-                                                    "the #[rustc_on_unimplemented] \
-                                                            attribute on \
-                                                            trait definition for {} refers to \
-                                                            non-existent type parameter {}",
-                                                            trait_str, s);
+                                              "the #[rustc_on_unimplemented] attribute on trait \
+                                               definition for {} refers to non-existent type \
+                                               parameter {}",
+                                              trait_str, s);
                                     errored = true;
                                     None
                                 }
                             },
                             _ => {
                                 span_err!(self.tcx.sess, err_sp, E0273,
-                                            "the #[rustc_on_unimplemented] attribute \
-                                            on trait definition for {} must have \
-                                            named format arguments, eg \
-                                            `#[rustc_on_unimplemented = \
-                                            \"foo {{T}}\"]`", trait_str);
+                                          "the #[rustc_on_unimplemented] attribute on trait \
+                                           definition for {} must have named format arguments, eg \
+                                           `#[rustc_on_unimplemented = \"foo {{T}}\"]`",
+                                          trait_str);
                                 errored = true;
                                 None
                             }
@@ -485,8 +483,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                              "impl has stricter requirements than trait");
 
         if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) {
-            err.span_label(trait_item_span,
-                           &format!("definition of `{}` from trait", item_name));
+            let span = self.tcx.sess.codemap().def_span(trait_item_span);
+            err.span_label(span, &format!("definition of `{}` from trait", item_name));
         }
 
         err.span_label(
@@ -692,6 +690,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         assert!(type_def_id.is_local());
         let span = self.hir.span_if_local(type_def_id).unwrap();
+        let span = self.sess.codemap().def_span(span);
         let mut err = struct_span_err!(self.sess, span, E0072,
                                        "recursive type `{}` has infinite size",
                                        self.item_path_str(type_def_id));
@@ -709,13 +708,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                       -> DiagnosticBuilder<'tcx>
     {
         let trait_str = self.item_path_str(trait_def_id);
+        let span = self.sess.codemap().def_span(span);
         let mut err = struct_span_err!(
             self.sess, span, E0038,
             "the trait `{}` cannot be made into an object",
             trait_str);
-        err.span_label(span, &format!(
-            "the trait `{}` cannot be made into an object", trait_str
-        ));
+        err.span_label(span, &format!("the trait `{}` cannot be made into an object", trait_str));
 
         let mut reported_violations = FxHashSet();
         for violation in violations {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index d771be077ae..d49affa3e87 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -184,6 +184,16 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
         });
     }
 
+    pub fn register_predicate_obligations(&mut self,
+                                          infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                          obligations: Vec<PredicateObligation<'tcx>>)
+    {
+        for obligation in obligations {
+            self.register_predicate_obligation(infcx, obligation);
+        }
+    }
+
+
     pub fn region_obligations(&self,
                               body_id: ast::NodeId)
                               -> &[RegionObligation<'tcx>]
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 92b7c736d42..5f02688be34 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -218,7 +218,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                        -> Result<&'tcx Substs<'tcx>, ()> {
     let selcx = &mut SelectionContext::new(&infcx);
     let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
-    let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx,
+    let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx,
                                                                    target_impl,
                                                                    target_substs);
 
@@ -227,9 +227,8 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                               &ObligationCause::dummy(),
                               source_trait_ref,
                               target_trait_ref) {
-        Ok(InferOk { obligations, .. }) => {
-            // FIXME(#32730) propagate obligations
-            assert!(obligations.is_empty())
+        Ok(InferOk { obligations: o, .. }) => {
+            obligations.extend(o);
         }
         Err(_) => {
             debug!("fulfill_implication: {:?} does not unify with {:?}",
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 44e291a44c7..7447fba3038 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -376,7 +376,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
         match self.sub(t1, t2) {
             Ok(InferOk { obligations, .. }) => {
-                // FIXME(#32730) once obligations are being propagated, assert the right thing.
+                // None of these tests should require nested obligations:
                 assert!(obligations.is_empty());
             }
             Err(ref e) => {
@@ -400,7 +400,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
         match self.lub(t1, t2) {
             Ok(InferOk { obligations, value: t }) => {
-                // FIXME(#32730) once obligations are being propagated, assert the right thing.
+                // None of these tests should require nested obligations:
                 assert!(obligations.is_empty());
 
                 self.assert_eq(t, t_lub);
@@ -415,7 +415,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         match self.glb(t1, t2) {
             Err(e) => panic!("unexpected error computing LUB: {:?}", e),
             Ok(InferOk { obligations, value: t }) => {
-                // FIXME(#32730) once obligations are being propagated, assert the right thing.
+                // None of these tests should require nested obligations:
                 assert!(obligations.is_empty());
 
                 self.assert_eq(t, t_glb);
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 2daebf5cf3d..2cfab7df8b3 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -229,12 +229,12 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType
         };
 
         if in_mem {
-            // `sret` / `byval` parameter thus one less integer register available
-            int_regs -= 1;
-
             arg.make_indirect(ccx);
             if is_arg {
                 arg.attrs.set(ArgAttribute::ByVal);
+            } else {
+                // `sret` parameter thus one less integer register available
+                int_regs -= 1;
             }
         } else {
             // split into sized chunks passed individually
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 8a6853461a5..ae70049cc5b 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -294,10 +294,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
 
         let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty)
-            .map(|InferOk { obligations, .. }| {
-                // FIXME(#32730) propagate obligations
-                assert!(obligations.is_empty());
-            });
+                              .map(|InferOk { obligations, .. }| {
+                                  inh.register_predicates(obligations);
+                              });
 
         if let Err(terr) = sub_result {
             debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 9f41373dab1..b71ff58ccec 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -82,7 +82,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
     // check that the impl type can be made to match the trait type.
 
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
-    tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| {
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
@@ -97,8 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
         let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
         match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) {
             Ok(InferOk { obligations, .. }) => {
-                // FIXME(#32730) propagate obligations
-                assert!(obligations.is_empty());
+                fulfillment_cx.register_predicate_obligations(infcx, obligations);
             }
             Err(_) => {
                 let item_span = tcx.hir.span(self_type_node_id);
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index e9a606dc0ab..0754b52cf28 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -109,7 +109,7 @@ use rustc::infer::InferOk;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
-use rustc::traits::{ObligationCause, ObligationCauseCode, Reveal};
+use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
 use session::config;
 use util::common::time;
 
@@ -153,15 +153,22 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
-    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|ref infcx| {
+        let mut fulfill_cx = FulfillmentContext::new();
         match infcx.eq_types(false, &cause, expected, actual) {
             Ok(InferOk { obligations, .. }) => {
-                // FIXME(#32730) propagate obligations
-                assert!(obligations.is_empty());
-                true
+                fulfill_cx.register_predicate_obligations(infcx, obligations);
             }
             Err(err) => {
                 infcx.report_mismatched_types(cause, expected, actual, err).emit();
+                return false;
+            }
+        }
+
+        match fulfill_cx.select_all_or_error(infcx) {
+            Ok(()) => true,
+            Err(errors) => {
+                infcx.report_fulfillment_errors(&errors);
                 false
             }
         }
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index bf3f41b13c1..b90192dd8af 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -677,7 +677,13 @@ impl Borrow<OsStr> for OsString {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToOwned for OsStr {
     type Owned = OsString;
-    fn to_owned(&self) -> OsString { self.to_os_string() }
+    fn to_owned(&self) -> OsString {
+        self.to_os_string()
+    }
+    fn clone_into(&self, target: &mut OsString) {
+        target.clear();
+        target.push(self);
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -863,4 +869,14 @@ mod tests {
         let boxed = <Box<OsStr>>::default();
         assert!(boxed.is_empty());
     }
+
+    #[test]
+    fn test_os_str_clone_into() {
+        let mut os_string = OsString::with_capacity(123);
+        os_string.push("hello");
+        let os_str = OsStr::new("bonjour");
+        os_str.clone_into(&mut os_string);
+        assert_eq!(os_str, os_string);
+        assert!(os_string.capacity() >= 123);
+    }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 8de6e1a24f1..367779bb701 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -311,6 +311,7 @@
 #![feature(str_utf16)]
 #![feature(test, rustc_private)]
 #![feature(thread_local)]
+#![feature(toowned_clone_into)]
 #![feature(try_from)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 22889b5de4c..812b65b61e7 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1414,6 +1414,9 @@ impl ToOwned for Path {
     fn to_owned(&self) -> PathBuf {
         self.to_path_buf()
     }
+    fn clone_into(&self, target: &mut PathBuf) {
+        self.inner.clone_into(&mut target.inner);
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -3859,4 +3862,13 @@ mod tests {
         assert_eq!(&*boxed, &*path_buf);
         assert_eq!(&*path_buf, path);
     }
+
+    #[test]
+    fn test_clone_into() {
+        let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
+        let path = Path::new("short");
+        path.clone_into(&mut path_buf);
+        assert_eq!(path, path_buf);
+        assert!(path_buf.into_os_string().capacity() >= 15);
+    }
 }
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 4d67390d442..da2d0a33d1a 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -441,6 +441,25 @@ impl CodeMap {
         }
     }
 
+    /// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char`
+    pub fn span_until_char(&self, sp: Span, c: char) -> Span {
+        match self.span_to_snippet(sp) {
+            Ok(snippet) => {
+                let snippet = snippet.split(c).nth(0).unwrap_or("").trim_right();
+                if snippet.len() > 0 && !snippet.contains('\n') {
+                    Span { hi: BytePos(sp.lo.0 + snippet.len() as u32), ..sp }
+                } else {
+                    sp
+                }
+            }
+            _ => sp,
+        }
+    }
+
+    pub fn def_span(&self, sp: Span) -> Span {
+        self.span_until_char(sp, '{')
+    }
+
     pub fn get_filemap(&self, filename: &str) -> Option<Rc<FileMap>> {
         for fm in self.files.borrow().iter() {
             if filename == fm.name {
diff --git a/src/stage0.txt b/src/stage0.txt
index 60fbcadf491..dc6931c1d0b 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,4 +12,4 @@
 # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
 # released on `$date`
 
-rustc: beta-2017-03-21
+rustc: beta-2017-04-05
diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c
index 4e09928edc6..44a940a17a9 100644
--- a/src/test/run-make/extern-fn-struct-passing-abi/test.c
+++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c
@@ -137,6 +137,21 @@ void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d,
     assert(s.d == 556);
 }
 
+// System V x86_64 ABI:
+// a, b, d, e, f should be byval pointer (on the stack)
+// g passed via register (fixes #41375)
+//
+// Win64 ABI:
+// a, b, d, e, f, g should be byval pointer
+void byval_rect_with_many_huge(struct Huge a, struct Huge b, struct Huge c,
+                               struct Huge d, struct Huge e, struct Huge f,
+                               struct Rect g) {
+    assert(g.a == 123);
+    assert(g.b == 456);
+    assert(g.c == 789);
+    assert(g.d == 420);
+}
+
 // System V x86_64 & Win64 ABI:
 // a, b should be in registers
 // s should be split across 2 integer registers
diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs
index ff845a644b1..aaae7ae4fb4 100644
--- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs
+++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs
@@ -64,6 +64,8 @@ extern {
 
     fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);
 
+    fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);
+
     fn split_rect(a: i32, b: i32, s: Rect);
 
     fn split_rect_floats(a: f32, b: f32, s: FloatRect);
@@ -95,6 +97,12 @@ fn main() {
         byval_many_rect(1, 2, 3, 4, 5, 6, s);
         byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
         byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
+        byval_rect_with_many_huge(v, v, v, v, v, v, Rect {
+            a: 123,
+            b: 456,
+            c: 789,
+            d: 420
+        });
         split_rect(1, 2, s);
         split_rect_floats(1., 2., u);
         split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
diff --git a/src/test/run-pass/issue-41298.rs b/src/test/run-pass/issue-41298.rs
new file mode 100644
index 00000000000..2b9baa74674
--- /dev/null
+++ b/src/test/run-pass/issue-41298.rs
@@ -0,0 +1,16 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Function<T, F> { t: T, f: F }
+
+impl<T, R> Function<T, fn() -> R> { fn foo() { } }
+impl<T, R> Function<T, fn() -> R> { fn bar() { } }
+
+fn main() { }
diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr
index ef02250e21c..2ef8c830eb2 100644
--- a/src/test/ui/resolve/issue-3907-2.stderr
+++ b/src/test/ui/resolve/issue-3907-2.stderr
@@ -2,7 +2,7 @@ error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
   --> $DIR/issue-3907-2.rs:20:1
    |
 20 | fn bar(_x: Foo) {}
-   | ^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
+   | ^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
    |
    = note: method `bar` has no receiver
 
diff --git a/src/test/compile-fail/E0072.rs b/src/test/ui/span/E0072.rs
index e6de7921b30..18ade4f1ab6 100644
--- a/src/test/compile-fail/E0072.rs
+++ b/src/test/ui/span/E0072.rs
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct ListNode { //~ ERROR E0072
-                  //~| NOTE recursive type has infinite size
+struct ListNode {
     head: u8,
     tail: Option<ListNode>,
 }
diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr
new file mode 100644
index 00000000000..5204390ef9d
--- /dev/null
+++ b/src/test/ui/span/E0072.stderr
@@ -0,0 +1,10 @@
+error[E0072]: recursive type `ListNode` has infinite size
+  --> $DIR/E0072.rs:11:1
+   |
+11 | struct ListNode {
+   | ^^^^^^^^^^^^^^^ recursive type has infinite size
+   |
+   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/multiline-span-E0072.rs b/src/test/ui/span/multiline-span-E0072.rs
new file mode 100644
index 00000000000..323e7fb5a42
--- /dev/null
+++ b/src/test/ui/span/multiline-span-E0072.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// It should just use the entire body instead of pointing at the next two lines
+struct
+ListNode
+{
+    head: u8,
+    tail: Option<ListNode>,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr
new file mode 100644
index 00000000000..58cdc502300
--- /dev/null
+++ b/src/test/ui/span/multiline-span-E0072.stderr
@@ -0,0 +1,16 @@
+error[E0072]: recursive type `ListNode` has infinite size
+  --> $DIR/multiline-span-E0072.rs:12:1
+   |
+12 |   struct
+   |  _^ starting here...
+13 | | ListNode
+14 | | {
+15 | |     head: u8,
+16 | |     tail: Option<ListNode>,
+17 | | }
+   | |_^ ...ending here: recursive type has infinite size
+   |
+   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
+
+error: aborting due to previous error
+