about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-24 03:01:11 +0000
committerbors <bors@rust-lang.org>2018-07-24 03:01:11 +0000
commitbaba5007bf857b4577a8d26de454a03d7afef3ac (patch)
tree0e552f1865570b25ddabb354b6c6119f8979b866
parente842dea7a3d9babc7a19bd201711f4243840fab0 (diff)
parent3efc612a930822ea1b9c6749a3d146235c324a83 (diff)
downloadrust-baba5007bf857b4577a8d26de454a03d7afef3ac.tar.gz
rust-baba5007bf857b4577a8d26de454a03d7afef3ac.zip
Auto merge of #52655 - kennytm:rollup, r=kennytm
Rollup of 10 pull requests

Successful merges:

 - #52538 (Remove obsolete flags in the i586_musl Dockerfile)
 - #52548 (Cursor: update docs to clarify Cursor only works with in-memory buffers)
 - #52605 (Do not suggest using `to_owned()` on `&str += &str`)
 - #52621 (Fix color detection for Windows msys terminals.)
 - #52622 (Use MultiSpan in E0707 and E709)
 - #52627 (Compile rustc before building tests for rustdoc)
 - #52637 (Don't use NonNull::dangling as sentinel value in Rc, Arc)
 - #52640 (Forget Waker when cloning LocalWaker)
 - #52641 (Simplify 2 functions in rustc_mir/dataflow)
 - #52642 (Replace a few expect+format combos with unwrap_or_else+panic)

Failed merges:

r? @ghost
-rw-r--r--src/Cargo.lock14
-rw-r--r--src/bootstrap/bin/rustc.rs4
-rw-r--r--src/bootstrap/install.rs2
-rw-r--r--src/bootstrap/test.rs1
-rw-r--r--src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile4
-rw-r--r--src/liballoc/rc.rs13
-rw-r--r--src/liballoc/sync.rs13
-rw-r--r--src/libcore/task/wake.rs9
-rw-r--r--src/librustc/hir/lowering.rs6
-rw-r--r--src/librustc_codegen_llvm/back/rpath.rs4
-rw-r--r--src/librustc_codegen_llvm/base.rs2
-rw-r--r--src/librustc_mir/dataflow/graphviz.rs4
-rw-r--r--src/librustc_mir/dataflow/mod.rs11
-rw-r--r--src/librustc_typeck/check/op.rs67
-rw-r--r--src/libstd/io/cursor.rs17
-rw-r--r--src/libsyntax_ext/format_foreign.rs4
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.stderr6
-rw-r--r--src/test/ui/issue-10401.stderr5
-rw-r--r--src/test/ui/span/issue-39018.stderr8
19 files changed, 95 insertions, 99 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 09baaeadaee..8594e4ff130 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -87,7 +87,7 @@ dependencies = [
 
 [[package]]
 name = "atty"
-version = "0.2.10"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -187,7 +187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "cargo"
 version = "0.30.0"
 dependencies = [
- "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -303,7 +303,7 @@ version = "2.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -622,7 +622,7 @@ name = "env_logger"
 version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1844,7 +1844,7 @@ name = "rustc-ap-rustc_errors"
 version = "182.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-ap-rustc_data_structures 182.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-ap-serialize 182.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-ap-syntax_pos 182.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2097,7 +2097,7 @@ dependencies = [
 name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
- "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_data_structures 0.0.0",
  "serialize 0.0.0",
  "syntax_pos 0.0.0",
@@ -3056,7 +3056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
 "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
 "checksum assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98589b0e465a6c510d95fceebd365bb79bedece7f6e18a480897f2015f85ec51"
-"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
+"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
 "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
 "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e"
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index e81595a8c62..f2b2f6f1eeb 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -326,7 +326,7 @@ fn main() {
             let start = Instant::now();
             let status = cmd
                 .status()
-                .expect(&format!("\n\n failed to run {:?}", cmd));
+                .unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd));
             let dur = start.elapsed();
 
             let is_test = args.iter().any(|a| a == "--test");
@@ -346,7 +346,7 @@ fn main() {
         }
     }
 
-    let code = exec_cmd(&mut cmd).expect(&format!("\n\n failed to run {:?}", cmd));
+    let code = exec_cmd(&mut cmd).unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd));
     std::process::exit(code);
 }
 
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 97fd6f77646..cb28698aa3d 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -75,7 +75,7 @@ fn install_sh(
     let libdir_default = PathBuf::from("lib");
     let mandir_default = datadir_default.join("man");
     let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
-        fs::canonicalize(p).expect(&format!("could not canonicalize {}", p.display()))
+        fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
     });
     let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
     let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 38bba40aa65..639c96bc208 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1732,6 +1732,7 @@ impl Step for CrateRustdoc {
 
         let compiler = builder.compiler(builder.top_stage, self.host);
         let target = compiler.host;
+        builder.ensure(compile::Rustc { compiler, target });
 
         let mut cargo = tool::prepare_tool_cargo(builder,
                                                  compiler,
diff --git a/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile
index e12bed3abc5..ba2d32a9296 100644
--- a/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile
+++ b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile
@@ -42,9 +42,7 @@ ENV RUST_CONFIGURE_ARGS \
 # See: https://github.com/rust-lang/rust/issues/34978
 ENV CFLAGS_i686_unknown_linux_musl=-Wa,-mrelax-relocations=no
 ENV CFLAGS_i586_unknown_linux_gnu=-Wa,-mrelax-relocations=no
-# FIXME remove -Wl,-melf_i386 after cc is updated to include
-#       https://github.com/alexcrichton/cc-rs/pull/281
-ENV CFLAGS_i586_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wl,-melf_i386"
+ENV CFLAGS_i586_unknown_linux_musl=-Wa,-mrelax-relocations=no
 
 ENV TARGETS=i586-unknown-linux-gnu,i686-unknown-linux-musl
 
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index d76acb28df9..be049eb6e5e 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -258,6 +258,7 @@ use core::ops::Deref;
 use core::ops::CoerceUnsized;
 use core::ptr::{self, NonNull};
 use core::convert::From;
+use core::usize;
 
 use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error};
 use string::String;
@@ -449,6 +450,8 @@ impl<T: ?Sized> Rc<T> {
     #[stable(feature = "rc_weak", since = "1.4.0")]
     pub fn downgrade(this: &Self) -> Weak<T> {
         this.inc_weak();
+        // Make sure we do not create a dangling Weak
+        debug_assert!(!is_dangling(this.ptr));
         Weak { ptr: this.ptr }
     }
 
@@ -1154,8 +1157,9 @@ impl<T> From<Vec<T>> for Rc<[T]> {
 pub struct Weak<T: ?Sized> {
     // This is a `NonNull` to allow optimizing the size of this type in enums,
     // but it is not necessarily a valid pointer.
-    // `Weak::new` sets this to a dangling pointer so that it doesn’t need
-    // to allocate space on the heap.
+    // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
+    // to allocate space on the heap.  That's not a value a real pointer
+    // will ever have because RcBox has alignment at least 2.
     ptr: NonNull<RcBox<T>>,
 }
 
@@ -1185,15 +1189,14 @@ impl<T> Weak<T> {
     #[stable(feature = "downgraded_weak", since = "1.10.0")]
     pub fn new() -> Weak<T> {
         Weak {
-            ptr: NonNull::dangling(),
+            ptr: NonNull::new(usize::MAX as *mut RcBox<T>).expect("MAX is not 0"),
         }
     }
 }
 
 pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
     let address = ptr.as_ptr() as *mut () as usize;
-    let align = align_of_val(unsafe { ptr.as_ref() });
-    address == align
+    address == usize::MAX
 }
 
 impl<T: ?Sized> Weak<T> {
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 5def0237e7e..a00b6b4e435 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -238,8 +238,9 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
 pub struct Weak<T: ?Sized> {
     // This is a `NonNull` to allow optimizing the size of this type in enums,
     // but it is not necessarily a valid pointer.
-    // `Weak::new` sets this to a dangling pointer so that it doesn’t need
-    // to allocate space on the heap.
+    // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
+    // to allocate space on the heap.  That's not a value a real pointer
+    // will ever have because RcBox has alignment at least 2.
     ptr: NonNull<ArcInner<T>>,
 }
 
@@ -442,7 +443,11 @@ impl<T: ?Sized> Arc<T> {
             // synchronize with the write coming from `is_unique`, so that the
             // events prior to that write happen before this read.
             match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
-                Ok(_) => return Weak { ptr: this.ptr },
+                Ok(_) => {
+                    // Make sure we do not create a dangling Weak
+                    debug_assert!(!is_dangling(this.ptr));
+                    return Weak { ptr: this.ptr };
+                }
                 Err(old) => cur = old,
             }
         }
@@ -1033,7 +1038,7 @@ impl<T> Weak<T> {
     #[stable(feature = "downgraded_weak", since = "1.10.0")]
     pub fn new() -> Weak<T> {
         Weak {
-            ptr: NonNull::dangling(),
+            ptr: NonNull::new(usize::MAX as *mut ArcInner<T>).expect("MAX is not 0"),
         }
     }
 }
diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs
index d3df8b50ee2..3b901c9aef0 100644
--- a/src/libcore/task/wake.rs
+++ b/src/libcore/task/wake.rs
@@ -12,7 +12,7 @@
             reason = "futures in libcore are unstable",
             issue = "50547")]
 
-use fmt;
+use {fmt, mem};
 use marker::Unpin;
 use ptr::NonNull;
 
@@ -166,9 +166,10 @@ impl From<LocalWaker> for Waker {
 impl Clone for LocalWaker {
     #[inline]
     fn clone(&self) -> Self {
-        unsafe {
-            LocalWaker { inner: self.inner.as_ref().clone_raw().inner }
-        }
+        let waker = unsafe { self.inner.as_ref().clone_raw() };
+        let inner = waker.inner;
+        mem::forget(waker);
+        LocalWaker { inner }
     }
 }
 
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 31350a78ac1..3b030fc098f 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -73,7 +73,7 @@ use syntax::tokenstream::{Delimited, TokenStream, TokenTree};
 use syntax::parse::token::Token;
 use syntax::util::small_vector::SmallVector;
 use syntax::visit::{self, Visitor};
-use syntax_pos::Span;
+use syntax_pos::{Span, MultiSpan};
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -2071,7 +2071,7 @@ impl<'a> LoweringContext<'a> {
                         if current_lt_name != name {
                             struct_span_err!(
                                 self.context.sess,
-                                current_lt_span.between(lifetime.span),
+                                MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
                                 E0709,
                                 "multiple different lifetimes used in arguments of `async fn`",
                             )
@@ -2083,7 +2083,7 @@ impl<'a> LoweringContext<'a> {
                         } else if current_lt_name.is_elided() && name.is_elided() {
                             struct_span_err!(
                                 self.context.sess,
-                                current_lt_span.between(lifetime.span),
+                                MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
                                 E0707,
                                 "multiple elided lifetimes used in arguments of `async fn`",
                             )
diff --git a/src/librustc_codegen_llvm/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs
index f46205cb590..e73073cfad0 100644
--- a/src/librustc_codegen_llvm/back/rpath.rs
+++ b/src/librustc_codegen_llvm/back/rpath.rs
@@ -114,8 +114,8 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String
     let mut output = cwd.join(&config.out_filename);
     output.pop();
     let output = fs::canonicalize(&output).unwrap_or(output);
-    let relative = path_relative_from(&lib, &output)
-        .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib));
+    let relative = path_relative_from(&lib, &output).unwrap_or_else(||
+        panic!("couldn't create relative path from {:?} to {:?}", output, lib));
     // FIXME (#9639): This needs to handle non-utf8 paths
     format!("{}/{}", prefix,
             relative.to_str().expect("non-utf8 component in path"))
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 6d37f1ca3ca..223c04f420f 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -1277,7 +1277,7 @@ pub fn provide(providers: &mut Providers) {
         all.iter()
             .find(|cgu| *cgu.name() == name)
             .cloned()
-            .expect(&format!("failed to find cgu with name {:?}", name))
+            .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name))
     };
     providers.compile_codegen_unit = compile_codegen_unit;
 
diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs
index f8dc7d2a2a8..7475b4d82f4 100644
--- a/src/librustc_mir/dataflow/graphviz.rs
+++ b/src/librustc_mir/dataflow/graphviz.rs
@@ -73,8 +73,8 @@ pub type Node = BasicBlock;
 pub struct Edge { source: BasicBlock, index: usize }
 
 fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
-    mir[bb].terminator().successors().enumerate()
-        .map(|(index, _)| Edge { source: bb, index: index}).collect()
+    (0..mir[bb].terminator().successors().count())
+        .map(|index| Edge { source: bb, index: index}).collect()
 }
 
 impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index f58609aa9a5..4227f0bcd36 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -441,11 +441,6 @@ pub struct DataflowState<O: BitDenotation>
 }
 
 impl<O: BitDenotation> DataflowState<O> {
-    pub fn each_bit<F>(&self, words: &IdxSet<O::Idx>, f: F) where F: FnMut(O::Idx)
-    {
-        words.iter().for_each(f)
-    }
-
     pub(crate) fn interpret_set<'c, P>(&self,
                                        o: &'c O,
                                        words: &IdxSet<O::Idx>,
@@ -453,11 +448,7 @@ impl<O: BitDenotation> DataflowState<O> {
                                        -> Vec<DebugFormatted>
         where P: Fn(&O, O::Idx) -> DebugFormatted
     {
-        let mut v = Vec::new();
-        self.each_bit(words, |i| {
-            v.push(render_idx(o, i));
-        });
-        v
+        words.iter().map(|i| render_idx(o, i)).collect()
     }
 }
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index fb153464dff..259311408de 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -307,9 +307,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             if let Some(missing_trait) = missing_trait {
                                 if op.node == hir::BinOpKind::Add &&
                                     self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                            rhs_ty, &mut err) {
+                                                            rhs_ty, &mut err, true) {
                                     // This has nothing here because it means we did string
-                                    // concatenation (e.g. "Hello " + "World!"). This means
+                                    // concatenation (e.g. "Hello " += "World!"). This means
                                     // we don't want the note in the else clause to be emitted
                                 } else if let ty::TyParam(_) = lhs_ty.sty {
                                     // FIXME: point to span of param
@@ -381,7 +381,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             if let Some(missing_trait) = missing_trait {
                                 if op.node == hir::BinOpKind::Add &&
                                     self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                            rhs_ty, &mut err) {
+                                                            rhs_ty, &mut err, false) {
                                     // This has nothing here because it means we did string
                                     // concatenation (e.g. "Hello " + "World!"). This means
                                     // we don't want the note in the else clause to be emitted
@@ -410,13 +410,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         (lhs_ty, rhs_ty, return_ty)
     }
 
-    fn check_str_addition(&self,
-                          expr: &'gcx hir::Expr,
-                          lhs_expr: &'gcx hir::Expr,
-                          rhs_expr: &'gcx hir::Expr,
-                          lhs_ty: Ty<'tcx>,
-                          rhs_ty: Ty<'tcx>,
-                          err: &mut errors::DiagnosticBuilder) -> bool {
+    fn check_str_addition(
+        &self,
+        expr: &'gcx hir::Expr,
+        lhs_expr: &'gcx hir::Expr,
+        rhs_expr: &'gcx hir::Expr,
+        lhs_ty: Ty<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        err: &mut errors::DiagnosticBuilder,
+        is_assign: bool,
+    ) -> bool {
         let codemap = self.tcx.sess.codemap();
         let msg = "`to_owned()` can be used to create an owned `String` \
                    from a string reference. String concatenation \
@@ -428,34 +431,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match (&lhs_ty.sty, &rhs_ty.sty) {
             (&TyRef(_, l_ty, _), &TyRef(_, r_ty, _))
             if l_ty.sty == TyStr && r_ty.sty == TyStr => {
-                err.span_label(expr.span,
-                    "`+` can't be used to concatenate two `&str` strings");
-                match codemap.span_to_snippet(lhs_expr.span) {
-                    Ok(lstring) => err.span_suggestion(lhs_expr.span,
-                                                       msg,
-                                                       format!("{}.to_owned()", lstring)),
-                    _ => err.help(msg),
-                };
+                if !is_assign {
+                    err.span_label(expr.span,
+                                   "`+` can't be used to concatenate two `&str` strings");
+                    match codemap.span_to_snippet(lhs_expr.span) {
+                        Ok(lstring) => err.span_suggestion(lhs_expr.span,
+                                                           msg,
+                                                           format!("{}.to_owned()", lstring)),
+                        _ => err.help(msg),
+                    };
+                }
                 true
             }
             (&TyRef(_, l_ty, _), &TyAdt(..))
             if l_ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => {
                 err.span_label(expr.span,
                     "`+` can't be used to concatenate a `&str` with a `String`");
-                match codemap.span_to_snippet(lhs_expr.span) {
-                    Ok(lstring) => err.span_suggestion(lhs_expr.span,
-                                                       msg,
-                                                       format!("{}.to_owned()", lstring)),
-                    _ => err.help(msg),
-                };
-                match codemap.span_to_snippet(rhs_expr.span) {
-                    Ok(rstring) => {
-                        err.span_suggestion(rhs_expr.span,
-                                            "you also need to borrow the `String` on the right to \
-                                             get a `&str`",
-                                            format!("&{}", rstring));
+                match (
+                    codemap.span_to_snippet(lhs_expr.span),
+                    codemap.span_to_snippet(rhs_expr.span),
+                    is_assign,
+                ) {
+                    (Ok(l), Ok(r), false) => {
+                        err.multipart_suggestion(msg, vec![
+                            (lhs_expr.span, format!("{}.to_owned()", l)),
+                            (rhs_expr.span, format!("&{}", r)),
+                        ]);
+                    }
+                    _ => {
+                        err.help(msg);
                     }
-                    _ => {}
                 };
                 true
             }
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
index aadd33b3954..3622df16b9d 100644
--- a/src/libstd/io/cursor.rs
+++ b/src/libstd/io/cursor.rs
@@ -14,12 +14,13 @@ use core::convert::TryInto;
 use cmp;
 use io::{self, Initializer, SeekFrom, Error, ErrorKind};
 
-/// A `Cursor` wraps another type and provides it with a
+/// A `Cursor` wraps an in-memory buffer and provides it with a
 /// [`Seek`] implementation.
 ///
-/// `Cursor`s are typically used with in-memory buffers to allow them to
-/// implement [`Read`] and/or [`Write`], allowing these buffers to be used
-/// anywhere you might use a reader or writer that does actual I/O.
+/// `Cursor`s are used with in-memory buffers, anything implementing
+/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
+/// allowing these buffers to be used anywhere you might use a reader or writer
+/// that does actual I/O.
 ///
 /// The standard library implements some I/O traits on various types which
 /// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
@@ -87,11 +88,11 @@ pub struct Cursor<T> {
 }
 
 impl<T> Cursor<T> {
-    /// Creates a new cursor wrapping the provided underlying I/O object.
+    /// Creates a new cursor wrapping the provided underlying in-memory buffer.
     ///
-    /// Cursor initial position is `0` even if underlying object (e.
-    /// g. `Vec`) is not empty. So writing to cursor starts with
-    /// overwriting `Vec` content, not with appending to it.
+    /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`)
+    /// is not empty. So writing to cursor starts with overwriting `Vec`
+    /// content, not with appending to it.
     ///
     /// # Examples
     ///
diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs
index ff9663cdd3c..8ccb3be1ad9 100644
--- a/src/libsyntax_ext/format_foreign.rs
+++ b/src/libsyntax_ext/format_foreign.rs
@@ -232,11 +232,11 @@ pub mod printf {
     impl Num {
         fn from_str(s: &str, arg: Option<&str>) -> Self {
             if let Some(arg) = arg {
-                Num::Arg(arg.parse().expect(&format!("invalid format arg `{:?}`", arg)))
+                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{:?}`", arg)))
             } else if s == "*" {
                 Num::Next
             } else {
-                Num::Num(s.parse().expect(&format!("invalid format num `{:?}`", s)))
+                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{:?}`", s)))
             }
         }
 
diff --git a/src/test/ui/async-fn-multiple-lifetimes.stderr b/src/test/ui/async-fn-multiple-lifetimes.stderr
index f203d9acf87..1d34673a005 100644
--- a/src/test/ui/async-fn-multiple-lifetimes.stderr
+++ b/src/test/ui/async-fn-multiple-lifetimes.stderr
@@ -1,8 +1,8 @@
 error[E0709]: multiple different lifetimes used in arguments of `async fn`
-  --> $DIR/async-fn-multiple-lifetimes.rs:17:49
+  --> $DIR/async-fn-multiple-lifetimes.rs:17:47
    |
 LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
-   |                                               --^^^^^^^^^-- different lifetime here
+   |                                               ^^         ^^ different lifetime here
    |                                               |
    |                                               first lifetime here
    |
@@ -12,7 +12,7 @@ error[E0707]: multiple elided lifetimes used in arguments of `async fn`
   --> $DIR/async-fn-multiple-lifetimes.rs:26:39
    |
 LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-   |                                       -^^^^^^^- different lifetime here
+   |                                       ^       ^ different lifetime here
    |                                       |
    |                                       first lifetime here
    |
diff --git a/src/test/ui/issue-10401.stderr b/src/test/ui/issue-10401.stderr
index 8c91c11a67c..94d13d5f268 100644
--- a/src/test/ui/issue-10401.stderr
+++ b/src/test/ui/issue-10401.stderr
@@ -5,11 +5,6 @@ LL |     a += { "b" };
    |     -^^^^^^^^^^^
    |     |
    |     cannot use `+=` on type `&str`
-   |     `+` can't be used to concatenate two `&str` strings
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
-   |
-LL |     a.to_owned() += { "b" };
-   |     ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index ee6334e8164..bd4e7cf574f 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -23,12 +23,8 @@ LL |     let x = "Hello " + "World!".to_owned();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String`
 help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
    |
-LL |     let x = "Hello ".to_owned() + "World!".to_owned();
-   |             ^^^^^^^^^^^^^^^^^^^
-help: you also need to borrow the `String` on the right to get a `&str`
-   |
-LL |     let x = "Hello " + &"World!".to_owned();
-   |                        ^^^^^^^^^^^^^^^^^^^^
+LL |     let x = "Hello ".to_owned() + &"World!".to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors