about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-09-22 14:26:15 +0000
committerbors <bors@rust-lang.org>2018-09-22 14:26:15 +0000
commitaf50e3822c4ceda60445c4a2adbb3bfa480ebd39 (patch)
tree34fd72c893b38708f648f92b4222ebc7ea625b9a /src
parente7b5ba8661aa844a06c37f22d7af0afb1807d347 (diff)
parent48ec53ccaebe555832114612b6c3f8df183c0a91 (diff)
downloadrust-af50e3822c4ceda60445c4a2adbb3bfa480ebd39.tar.gz
rust-af50e3822c4ceda60445c4a2adbb3bfa480ebd39.zip
Auto merge of #54457 - pietroalbini:rollup, r=pietroalbini
Rollup of 16 pull requests

Successful merges:

 - #53652 (define copy_within on slices)
 - #54261 (Make `dyn` a keyword in the 2018 edition)
 - #54280 (remove (more) CAS API from Atomic* types where not natively supported)
 - #54323 (rustbuild: drop color handling)
 - #54350 (Support specifying edition in doc test)
 - #54370 (Improve handling of type bounds in `bit_set.rs`.)
 - #54371 (add -Zui-testing to rustdoc)
 - #54374 (Make 'proc_macro::MultiSpan' public.)
 - #54402 (Use no_default_libraries for all NetBSD flavors)
 - #54409 (Detect `for _ in in bar {}` typo)
 - #54412 (add applicability to span_suggestion call)
 - #54413 (Add UI test for deref recursion limit printing twice)
 - #54415 (parser: Tweak function parameter parsing to avoid rollback on succesfull path)
 - #54420 (Compress `Liveness` data some more.)
 - #54422 (Simplify slice's first(_mut) and last(_mut) with get)
 - #54446 (Unify christianpoveda's emails)

Failed merges:

 - #54058 (Introduce the partition_dedup/by/by_key methods for slices)

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bin/rustc.rs9
-rw-r--r--src/bootstrap/compile.rs34
-rw-r--r--src/doc/rustdoc/src/documentation-tests.md16
-rw-r--r--src/doc/unstable-book/src/language-features/try-blocks.md4
-rw-r--r--src/libcore/slice/mod.rs69
-rw-r--r--src/libcore/sync/atomic.rs23
-rw-r--r--src/libcore/tests/lib.rs1
-rw-r--r--src/libcore/tests/slice.rs46
-rw-r--r--src/libproc_macro/lib.rs2
-rw-r--r--src/librustc/middle/liveness.rs207
-rw-r--r--src/librustc/traits/select.rs4
-rw-r--r--src/librustc_data_structures/bit_set.rs386
-rw-r--r--src/librustc_lint/builtin.rs3
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs4
-rw-r--r--src/librustc_mir/dataflow/graphviz.rs3
-rw-r--r--src/librustc_mir/dataflow/impls/mod.rs3
-rw-r--r--src/librustc_mir/monomorphize/collector.rs2
-rw-r--r--src/librustc_target/spec/netbsd_base.rs1
-rw-r--r--src/librustc_target/spec/x86_64_rumprun_netbsd.rs1
-rw-r--r--src/librustdoc/core.rs11
-rw-r--r--src/librustdoc/html/markdown.rs107
-rw-r--r--src/librustdoc/lib.rs12
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libserialize/serialize.rs14
-rw-r--r--src/libsyntax/parse/parser.rs101
-rw-r--r--src/libsyntax/parse/token.rs1
-rw-r--r--src/libsyntax_pos/edition.rs2
-rw-r--r--src/libsyntax_pos/symbol.rs19
-rw-r--r--src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr4
-rw-r--r--src/test/rustdoc-ui/deprecated-attrs.stderr10
-rw-r--r--src/test/rustdoc-ui/intra-doc-alias-ice.stderr4
-rw-r--r--src/test/rustdoc-ui/intra-links-warning.stderr44
-rw-r--r--src/test/rustdoc/edition-doctest.rs54
-rw-r--r--src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr12
-rw-r--r--src/test/ui/issues/issue-38940.rs46
-rw-r--r--src/test/ui/issues/issue-38940.stderr21
-rw-r--r--src/test/ui/parser/if-in-in.rs5
-rw-r--r--src/test/ui/parser/if-in-in.stderr13
-rw-r--r--src/test/ui/rust-2018/dyn-keyword.fixed10
-rw-r--r--src/test/ui/rust-2018/dyn-keyword.rs10
-rw-r--r--src/test/ui/rust-2018/dyn-keyword.stderr16
-rw-r--r--src/test/ui/rust-2018/dyn-trait-compatibility.rs8
-rw-r--r--src/test/ui/rust-2018/dyn-trait-compatibility.stderr14
43 files changed, 911 insertions, 447 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index f30f34acf5c..b89976eca26 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -291,15 +291,6 @@ fn main() {
         cmd.arg("-Z").arg("verify-llvm-ir");
     }
 
-    let color = match env::var("RUSTC_COLOR") {
-        Ok(s) => usize::from_str(&s).expect("RUSTC_COLOR should be an integer"),
-        Err(_) => 0,
-    };
-
-    if color != 0 {
-        cmd.arg("--color=always");
-    }
-
     if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none()
     {
         cmd.arg("-Dwarnings");
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 4205d5aebff..608f2c982c2 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -29,7 +29,7 @@ use build_helper::{output, mtime, up_to_date};
 use filetime::FileTime;
 use serde_json;
 
-use util::{exe, libdir, is_dylib, CiEnv};
+use util::{exe, libdir, is_dylib};
 use {Compiler, Mode, GitRepo};
 use native;
 
@@ -1034,29 +1034,6 @@ pub fn add_to_sysroot(builder: &Builder, sysroot_dst: &Path, stamp: &Path) {
     }
 }
 
-// Avoiding a dependency on winapi to keep compile times down
-#[cfg(unix)]
-fn stderr_isatty() -> bool {
-    use libc;
-    unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
-}
-#[cfg(windows)]
-fn stderr_isatty() -> bool {
-    type DWORD = u32;
-    type BOOL = i32;
-    type HANDLE = *mut u8;
-    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
-    extern "system" {
-        fn GetStdHandle(which: DWORD) -> HANDLE;
-        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: *mut DWORD) -> BOOL;
-    }
-    unsafe {
-        let handle = GetStdHandle(STD_ERROR_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
-    }
-}
-
 pub fn run_cargo(builder: &Builder,
                  cargo: &mut Command,
                  tail_args: Vec<String>,
@@ -1218,15 +1195,6 @@ pub fn stream_cargo(
     cargo.arg("--message-format").arg("json")
          .stdout(Stdio::piped());
 
-    if stderr_isatty() && builder.ci_env == CiEnv::None &&
-        // if the terminal is reported as dumb, then we don't want to enable color for rustc
-        env::var_os("TERM").map(|t| t != *"dumb").unwrap_or(true) {
-        // since we pass message-format=json to cargo, we need to tell the rustc
-        // wrapper to give us colored output if necessary. This is because we
-        // only want Cargo's JSON output, not rustcs.
-        cargo.env("RUSTC_COLOR", "1");
-    }
-
     for arg in tail_args {
         cargo.arg(arg);
     }
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index e4af122d0cb..dd8dcb7ff9b 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/documentation-tests.md
@@ -323,6 +323,22 @@ compiles, then the test will fail. However please note that code failing
 with the current Rust release may work in a future release, as new features
 are added.
 
+```text
+/// Only runs on the 2018 edition.
+///
+/// ```edition2018
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// ```
+```
+
+`edition2018` tells `rustdoc` that the code sample should be compiled the 2018
+edition of Rust. Similarly, you can specify `edition2015` to compile the code
+with the 2015 edition.
+
 ## Syntax reference
 
 The *exact* syntax for code blocks, including the edge cases, can be found
diff --git a/src/doc/unstable-book/src/language-features/try-blocks.md b/src/doc/unstable-book/src/language-features/try-blocks.md
index 866b37a39a7..e342c260a73 100644
--- a/src/doc/unstable-book/src/language-features/try-blocks.md
+++ b/src/doc/unstable-book/src/language-features/try-blocks.md
@@ -9,9 +9,7 @@ The tracking issue for this feature is: [#31436]
 The `try_blocks` feature adds support for `try` blocks. A `try`
 block creates a new scope one can use the `?` operator in.
 
-```rust,ignore
-// This code needs the 2018 edition
-
+```rust,edition2018
 #![feature(try_blocks)]
 
 use std::num::ParseIntError;
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index da4a56cfecd..aed9020d9d1 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -119,7 +119,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn first(&self) -> Option<&T> {
-        if self.is_empty() { None } else { Some(&self[0]) }
+        self.get(0)
     }
 
     /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
@@ -137,7 +137,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn first_mut(&mut self) -> Option<&mut T> {
-        if self.is_empty() { None } else { Some(&mut self[0]) }
+        self.get_mut(0)
     }
 
     /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
@@ -239,7 +239,8 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn last(&self) -> Option<&T> {
-        if self.is_empty() { None } else { Some(&self[self.len() - 1]) }
+        let last_idx = self.len().checked_sub(1)?;
+        self.get(last_idx)
     }
 
     /// Returns a mutable pointer to the last item in the slice.
@@ -257,9 +258,8 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn last_mut(&mut self) -> Option<&mut T> {
-        let len = self.len();
-        if len == 0 { return None; }
-        Some(&mut self[len - 1])
+        let last_idx = self.len().checked_sub(1)?;
+        self.get_mut(last_idx)
     }
 
     /// Returns a reference to an element or subslice depending on the type of
@@ -1618,6 +1618,63 @@ impl<T> [T] {
         }
     }
 
+    /// Copies elements from one part of the slice to another part of itself,
+    /// using a memmove.
+    ///
+    /// `src` is the range within `self` to copy from. `dest` is the starting
+    /// index of the range within `self` to copy to, which will have the same
+    /// length as `src`. The two ranges may overlap. The ends of the two ranges
+    /// must be less than or equal to `self.len()`.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if either range exceeds the end of the slice,
+    /// or if the end of `src` is before the start.
+    ///
+    /// # Examples
+    ///
+    /// Copying four bytes within a slice:
+    ///
+    /// ```
+    /// # #![feature(copy_within)]
+    /// let mut bytes = *b"Hello, World!";
+    ///
+    /// bytes.copy_within(1..5, 8);
+    ///
+    /// assert_eq!(&bytes, b"Hello, Wello!");
+    /// ```
+    #[unstable(feature = "copy_within", issue = "54236")]
+    pub fn copy_within<R: ops::RangeBounds<usize>>(&mut self, src: R, dest: usize)
+    where
+        T: Copy,
+    {
+        let src_start = match src.start_bound() {
+            ops::Bound::Included(&n) => n,
+            ops::Bound::Excluded(&n) => n
+                .checked_add(1)
+                .unwrap_or_else(|| slice_index_overflow_fail()),
+            ops::Bound::Unbounded => 0,
+        };
+        let src_end = match src.end_bound() {
+            ops::Bound::Included(&n) => n
+                .checked_add(1)
+                .unwrap_or_else(|| slice_index_overflow_fail()),
+            ops::Bound::Excluded(&n) => n,
+            ops::Bound::Unbounded => self.len(),
+        };
+        assert!(src_start <= src_end, "src end is before src start");
+        assert!(src_end <= self.len(), "src is out of bounds");
+        let count = src_end - src_start;
+        assert!(dest <= self.len() - count, "dest is out of bounds");
+        unsafe {
+            ptr::copy(
+                self.get_unchecked(src_start),
+                self.get_unchecked_mut(dest),
+                count,
+            );
+        }
+    }
+
     /// Swaps all elements in `self` with those in `other`.
     ///
     /// The length of `other` must be the same as `self`.
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 602f8d4ee71..69c524925fc 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -558,6 +558,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[cfg(target_has_atomic = "cas")]
     pub fn compare_exchange_weak(&self,
                                  current: bool,
                                  new: bool,
@@ -1041,6 +1042,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[cfg(target_has_atomic = "cas")]
     pub fn compare_exchange_weak(&self,
                                  current: *mut T,
                                  new: *mut T,
@@ -1434,6 +1436,7 @@ loop {
 ```"),
                 #[inline]
                 #[$stable_cxchg]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn compare_exchange_weak(&self,
                                              current: $int_type,
                                              new: $int_type,
@@ -1471,6 +1474,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 10);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_add(self.v.get(), val, order) }
                 }
@@ -1502,6 +1506,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 10);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_sub(self.v.get(), val, order) }
                 }
@@ -1536,6 +1541,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_and(self.v.get(), val, order) }
                 }
@@ -1571,6 +1577,7 @@ assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
 ```"),
                 #[inline]
                 #[$stable_nand]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_nand(self.v.get(), val, order) }
                 }
@@ -1605,6 +1612,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_or(self.v.get(), val, order) }
                 }
@@ -1639,6 +1647,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_xor(self.v.get(), val, order) }
                 }
@@ -1688,6 +1697,7 @@ assert_eq!(x.load(Ordering::SeqCst), 9);
                 #[unstable(feature = "no_more_cas",
                        reason = "no more CAS loops in user code",
                        issue = "48655")]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_update<F>(&self,
                                        mut f: F,
                                        fetch_order: Ordering,
@@ -1748,6 +1758,7 @@ assert!(max_foo == 42);
                 #[unstable(feature = "atomic_min_max",
                        reason = "easier and faster min/max than writing manual CAS loop",
                        issue = "48655")]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { $max_fn(self.v.get(), val, order) }
                 }
@@ -1799,6 +1810,7 @@ assert_eq!(min_foo, 12);
                 #[unstable(feature = "atomic_min_max",
                        reason = "easier and faster min/max than writing manual CAS loop",
                        issue = "48655")]
+                #[cfg(target_has_atomic = "cas")]
                 pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { $min_fn(self.v.get(), val, order) }
                 }
@@ -1987,6 +1999,7 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_xadd_acq(dst, val),
@@ -1999,6 +2012,7 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_xsub_acq(dst, val),
@@ -2035,6 +2049,7 @@ unsafe fn atomic_compare_exchange<T>(dst: *mut T,
 }
 
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
                                           old: T,
                                           new: T,
@@ -2059,6 +2074,7 @@ unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
 }
 
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_and_acq(dst, val),
@@ -2070,6 +2086,7 @@ unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_nand_acq(dst, val),
@@ -2081,6 +2098,7 @@ unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_or_acq(dst, val),
@@ -2092,6 +2110,7 @@ unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_xor_acq(dst, val),
@@ -2104,6 +2123,7 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (signed comparison)
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_max<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_max_acq(dst, val),
@@ -2116,6 +2136,7 @@ unsafe fn atomic_max<T>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (signed comparison)
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_min<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_min_acq(dst, val),
@@ -2128,6 +2149,7 @@ unsafe fn atomic_min<T>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (signed comparison)
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_umax<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_umax_acq(dst, val),
@@ -2140,6 +2162,7 @@ unsafe fn atomic_umax<T>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (signed comparison)
 #[inline]
+#[cfg(target_has_atomic = "cas")]
 unsafe fn atomic_umin<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_umin_acq(dst, val),
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 4f3086575c0..8fc32f40b99 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -39,6 +39,7 @@
 #![feature(inner_deref)]
 #![feature(slice_internals)]
 #![feature(option_replace)]
+#![feature(copy_within)]
 
 extern crate core;
 extern crate test;
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 012dc9bf5e0..d46a35ab82c 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -1000,3 +1000,49 @@ fn test_align_to_empty_mid() {
         assert_eq!(mid.as_ptr() as usize % mem::align_of::<Chunk>(), 0);
     }
 }
+
+#[test]
+fn test_copy_within() {
+    // Start to end, with a RangeTo.
+    let mut bytes = *b"Hello, World!";
+    bytes.copy_within(..3, 10);
+    assert_eq!(&bytes, b"Hello, WorHel");
+
+    // End to start, with a RangeFrom.
+    let mut bytes = *b"Hello, World!";
+    bytes.copy_within(10.., 0);
+    assert_eq!(&bytes, b"ld!lo, World!");
+
+    // Overlapping, with a RangeInclusive.
+    let mut bytes = *b"Hello, World!";
+    bytes.copy_within(0..=11, 1);
+    assert_eq!(&bytes, b"HHello, World");
+
+    // Whole slice, with a RangeFull.
+    let mut bytes = *b"Hello, World!";
+    bytes.copy_within(.., 0);
+    assert_eq!(&bytes, b"Hello, World!");
+}
+
+#[test]
+#[should_panic(expected = "src is out of bounds")]
+fn test_copy_within_panics_src_too_long() {
+    let mut bytes = *b"Hello, World!";
+    // The length is only 13, so 14 is out of bounds.
+    bytes.copy_within(10..14, 0);
+}
+
+#[test]
+#[should_panic(expected = "dest is out of bounds")]
+fn test_copy_within_panics_dest_too_long() {
+    let mut bytes = *b"Hello, World!";
+    // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds.
+    bytes.copy_within(0..4, 10);
+}
+#[test]
+#[should_panic(expected = "src end is before src start")]
+fn test_copy_within_panics_src_inverted() {
+    let mut bytes = *b"Hello, World!";
+    // 2 is greater than 1, so this range is invalid.
+    bytes.copy_within(2..1, 0);
+}
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 1a0dde3ccd7..d885f9b406f 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -48,7 +48,7 @@ pub mod rustc;
 mod diagnostic;
 
 #[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
-pub use diagnostic::{Diagnostic, Level};
+pub use diagnostic::{Diagnostic, Level, MultiSpan};
 
 use std::{ascii, fmt, iter};
 use std::path::PathBuf;
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 13847fb48ce..0d70a64123b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -64,10 +64,10 @@
 //! methods.  It effectively does a reverse walk of the AST; whenever we
 //! reach a loop node, we iterate until a fixed point is reached.
 //!
-//! ## The `users_*` fields
+//! ## The `RWU` struct
 //!
 //! At each live node `N`, we track three pieces of information for each
-//! variable `V` (these are in the `users_*` fields):
+//! variable `V` (these are encapsulated in the `RWU` struct):
 //!
 //! - `reader`: the `LiveNode` ID of some node which will read the value
 //!    that `V` holds on entry to `N`.  Formally: a node `M` such
@@ -536,6 +536,112 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
 // Actually we compute just a bit more than just liveness, but we use
 // the same basic propagation framework in all cases.
 
+#[derive(Clone, Copy)]
+struct RWU {
+    reader: LiveNode,
+    writer: LiveNode,
+    used: bool
+}
+
+/// Conceptually, this is like a `Vec<RWU>`. But the number of `RWU`s can get
+/// very large, so it uses a more compact representation that takes advantage
+/// of the fact that when the number of `RWU`s is large, most of them have an
+/// invalid reader and an invalid writer.
+struct RWUTable {
+    /// Each entry in `packed_rwus` is either INV_INV_FALSE, INV_INV_TRUE, or
+    /// an index into `unpacked_rwus`. In the common cases, this compacts the
+    /// 65 bits of data into 32; in the uncommon cases, it expands the 65 bits
+    /// in 96.
+    ///
+    /// More compact representations are possible -- e.g. use only 2 bits per
+    /// packed `RWU` and make the secondary table a HashMap that maps from
+    /// indices to `RWU`s -- but this one strikes a good balance between size
+    /// and speed.
+    packed_rwus: Vec<u32>,
+    unpacked_rwus: Vec<RWU>,
+}
+
+// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: false }`.
+const INV_INV_FALSE: u32 = u32::MAX;
+
+// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: true }`.
+const INV_INV_TRUE: u32 = u32::MAX - 1;
+
+impl RWUTable {
+    fn new(num_rwus: usize) -> RWUTable {
+        Self {
+            packed_rwus: vec![INV_INV_FALSE; num_rwus],
+            unpacked_rwus: vec![],
+        }
+    }
+
+    fn get(&self, idx: usize) -> RWU {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE => RWU { reader: invalid_node(), writer: invalid_node(), used: false },
+            INV_INV_TRUE => RWU { reader: invalid_node(), writer: invalid_node(), used: true },
+            _ => self.unpacked_rwus[packed_rwu as usize],
+        }
+    }
+
+    fn get_reader(&self, idx: usize) -> LiveNode {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE | INV_INV_TRUE => invalid_node(),
+            _ => self.unpacked_rwus[packed_rwu as usize].reader,
+        }
+    }
+
+    fn get_writer(&self, idx: usize) -> LiveNode {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE | INV_INV_TRUE => invalid_node(),
+            _ => self.unpacked_rwus[packed_rwu as usize].writer,
+        }
+    }
+
+    fn get_used(&self, idx: usize) -> bool {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE => false,
+            INV_INV_TRUE => true,
+            _ => self.unpacked_rwus[packed_rwu as usize].used,
+        }
+    }
+
+    #[inline]
+    fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) {
+        self.packed_rwus[dst_idx] = self.packed_rwus[src_idx];
+    }
+
+    fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
+        if rwu.reader == invalid_node() && rwu.writer == invalid_node() {
+            // When we overwrite an indexing entry in `self.packed_rwus` with
+            // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
+            // from `self.unpacked_rwus`; it's not worth the effort, and we
+            // can't have entries shifting around anyway.
+            self.packed_rwus[idx] = if rwu.used {
+                INV_INV_TRUE
+            } else {
+                INV_INV_FALSE
+            }
+        } else {
+            // Add a new RWU to `unpacked_rwus` and make `packed_rwus[idx]`
+            // point to it.
+            self.packed_rwus[idx] = self.unpacked_rwus.len() as u32;
+            self.unpacked_rwus.push(rwu);
+        }
+    }
+
+    fn assign_inv_inv(&mut self, idx: usize) {
+        self.packed_rwus[idx] = if self.get_used(idx) {
+            INV_INV_TRUE
+        } else {
+            INV_INV_FALSE
+        };
+    }
+}
+
 #[derive(Copy, Clone)]
 struct Specials {
     exit_ln: LiveNode,
@@ -552,14 +658,7 @@ struct Liveness<'a, 'tcx: 'a> {
     tables: &'a ty::TypeckTables<'tcx>,
     s: Specials,
     successors: Vec<LiveNode>,
-
-    // We used to have a single `users: Vec<Users>` field here, where `Users`
-    // had `reader`, `writer` and `used` fields. But the number of users can
-    // get very large, and it's more compact to store the data in three
-    // separate `Vec`s so that no space is wasted for padding.
-    users_reader: Vec<LiveNode>,
-    users_writer: Vec<LiveNode>,
-    users_used: Vec<bool>,
+    rwu_table: RWUTable,
 
     // mappings from loop node ID to LiveNode
     // ("break" label should map to loop node ID,
@@ -584,16 +683,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
         let num_live_nodes = ir.num_live_nodes;
         let num_vars = ir.num_vars;
-        let num_users = num_live_nodes * num_vars;
 
         Liveness {
             ir,
             tables,
             s: specials,
             successors: vec![invalid_node(); num_live_nodes],
-            users_reader: vec![invalid_node(); num_users],
-            users_writer: vec![invalid_node(); num_users],
-            users_used: vec![false; num_users],
+            rwu_table: RWUTable::new(num_live_nodes * num_vars),
             break_ln: NodeMap(),
             cont_ln: NodeMap(),
         }
@@ -657,16 +753,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         ln.get() * self.ir.num_vars + var.get()
     }
 
-    fn live_on_entry(&self, ln: LiveNode, var: Variable)
-                      -> Option<LiveNodeKind> {
+    fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
         assert!(ln.is_valid());
-        let reader = self.users_reader[self.idx(ln, var)];
-        if reader.is_valid() {Some(self.ir.lnk(reader))} else {None}
+        let reader = self.rwu_table.get_reader(self.idx(ln, var));
+        if reader.is_valid() { Some(self.ir.lnk(reader)) } else { None }
     }
 
-    /*
-    Is this variable live on entry to any of its successor nodes?
-    */
+    // Is this variable live on entry to any of its successor nodes?
     fn live_on_exit(&self, ln: LiveNode, var: Variable)
                     -> Option<LiveNodeKind> {
         let successor = self.successors[ln.get()];
@@ -675,14 +768,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
         assert!(ln.is_valid());
-        self.users_used[self.idx(ln, var)]
+        self.rwu_table.get_used(self.idx(ln, var))
     }
 
     fn assigned_on_entry(&self, ln: LiveNode, var: Variable)
                          -> Option<LiveNodeKind> {
         assert!(ln.is_valid());
-        let writer = self.users_writer[self.idx(ln, var)];
-        if writer.is_valid() {Some(self.ir.lnk(writer))} else {None}
+        let writer = self.rwu_table.get_writer(self.idx(ln, var));
+        if writer.is_valid() { Some(self.ir.lnk(writer)) } else { None }
     }
 
     fn assigned_on_exit(&self, ln: LiveNode, var: Variable)
@@ -725,9 +818,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         {
             let wr = &mut wr as &mut dyn Write;
             write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln));
-            self.write_vars(wr, ln, |idx| self.users_reader[idx]);
+            self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx));
             write!(wr, "  writes");
-            self.write_vars(wr, ln, |idx| self.users_writer[idx]);
+            self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx));
             write!(wr, "  precedes {:?}]", self.successors[ln.get()]);
         }
         String::from_utf8(wr).unwrap()
@@ -736,16 +829,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
         self.successors[ln.get()] = succ_ln;
 
-        // It is not necessary to initialize the
-        // values to empty because this is the value
-        // they have when they are created, and the sets
-        // only grow during iterations.
-        //
-        // self.indices(ln) { |idx|
-        //     self.users_reader[idx] = invalid_node();
-        //     self.users_writer[idx] = invalid_node();
-        //     self.users_used[idx] = false;
-        // }
+        // It is not necessary to initialize the RWUs here because they are all
+        // set to INV_INV_FALSE when they are created, and the sets only grow
+        // during iterations.
     }
 
     fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
@@ -753,9 +839,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         self.successors[ln.get()] = succ_ln;
 
         self.indices2(ln, succ_ln, |this, idx, succ_idx| {
-            this.users_reader[idx] = this.users_reader[succ_idx];
-            this.users_writer[idx] = this.users_writer[succ_idx];
-            this.users_used[idx] = this.users_used[succ_idx];
+            this.rwu_table.copy_packed(idx, succ_idx);
         });
         debug!("init_from_succ(ln={}, succ={})",
                self.ln_str(ln), self.ln_str(succ_ln));
@@ -770,26 +854,31 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
         let mut changed = false;
         self.indices2(ln, succ_ln, |this, idx, succ_idx| {
-            changed |= copy_if_invalid(this.users_reader[succ_idx], &mut this.users_reader[idx]);
-            changed |= copy_if_invalid(this.users_writer[succ_idx], &mut this.users_writer[idx]);
-            if this.users_used[succ_idx] && !this.users_used[idx] {
-                this.users_used[idx] = true;
+            let mut rwu = this.rwu_table.get(idx);
+            let succ_rwu = this.rwu_table.get(succ_idx);
+            if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() {
+                rwu.reader = succ_rwu.reader;
+                changed = true
+            }
+
+            if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() {
+                rwu.writer = succ_rwu.writer;
+                changed = true
+            }
+
+            if succ_rwu.used && !rwu.used {
+                rwu.used = true;
                 changed = true;
             }
+
+            if changed {
+                this.rwu_table.assign_unpacked(idx, rwu);
+            }
         });
 
         debug!("merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})",
                ln, self.ln_str(succ_ln), first_merge, changed);
         return changed;
-
-        fn copy_if_invalid(src: LiveNode, dst: &mut LiveNode) -> bool {
-            if src.is_valid() && !dst.is_valid() {
-                *dst = src;
-                true
-            } else {
-                false
-            }
-        }
     }
 
     // Indicates that a local variable was *defined*; we know that no
@@ -797,8 +886,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     // this) so we just clear out all the data.
     fn define(&mut self, writer: LiveNode, var: Variable) {
         let idx = self.idx(writer, var);
-        self.users_reader[idx] = invalid_node();
-        self.users_writer[idx] = invalid_node();
+        self.rwu_table.assign_inv_inv(idx);
 
         debug!("{:?} defines {:?} (idx={}): {}", writer, var,
                idx, self.ln_str(writer));
@@ -810,21 +898,24 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                ln, acc, var, self.ln_str(ln));
 
         let idx = self.idx(ln, var);
+        let mut rwu = self.rwu_table.get(idx);
 
         if (acc & ACC_WRITE) != 0 {
-            self.users_reader[idx] = invalid_node();
-            self.users_writer[idx] = ln;
+            rwu.reader = invalid_node();
+            rwu.writer = ln;
         }
 
         // Important: if we both read/write, must do read second
         // or else the write will override.
         if (acc & ACC_READ) != 0 {
-            self.users_reader[idx] = ln;
+            rwu.reader = ln;
         }
 
         if (acc & ACC_USE) != 0 {
-            self.users_used[idx] = true;
+            rwu.used = true;
         }
+
+        self.rwu_table.assign_unpacked(idx, rwu);
     }
 
     // _______________________________________________________________________
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index c6099e15f8b..9ffddf353ac 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -44,7 +44,7 @@ use ty::relate::TypeRelation;
 use middle::lang_items;
 use mir::interpret::{GlobalId};
 
-use rustc_data_structures::bit_set::BitSet;
+use rustc_data_structures::bit_set::GrowableBitSet;
 use rustc_data_structures::sync::Lock;
 use std::iter;
 use std::cmp;
@@ -3054,7 +3054,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 } else {
                     return Err(Unimplemented);
                 };
-                let mut ty_params = BitSet::new_empty(substs_a.types().count());
+                let mut ty_params = GrowableBitSet::new_empty();
                 let mut found = false;
                 for ty in field.walk() {
                     if let ty::Param(p) = ty.sty {
diff --git a/src/librustc_data_structures/bit_set.rs b/src/librustc_data_structures/bit_set.rs
index 9eb8d0afd46..1fba57fa541 100644
--- a/src/librustc_data_structures/bit_set.rs
+++ b/src/librustc_data_structures/bit_set.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use indexed_vec::{Idx, IndexVec};
-use rustc_serialize;
 use smallvec::SmallVec;
 use std::fmt;
 use std::iter;
@@ -26,33 +25,48 @@ pub const WORD_BITS: usize = WORD_BYTES * 8;
 ///
 /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
 /// just be `usize`.
-#[derive(Clone, Eq, PartialEq)]
+///
+/// All operations that involve an element will panic if the element is equal
+/// to or greater than the domain size. All operations that involve two bitsets
+/// will panic if the bitsets have differing domain sizes.
+#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
 pub struct BitSet<T: Idx> {
+    domain_size: usize,
     words: Vec<Word>,
     marker: PhantomData<T>,
 }
 
 impl<T: Idx> BitSet<T> {
+    /// Create a new, empty bitset with a given `domain_size`.
     #[inline]
     pub fn new_empty(domain_size: usize) -> BitSet<T> {
         let num_words = num_words(domain_size);
         BitSet {
+            domain_size,
             words: vec![0; num_words],
             marker: PhantomData,
         }
     }
 
+    /// Create a new, filled bitset with a given `domain_size`.
     #[inline]
     pub fn new_filled(domain_size: usize) -> BitSet<T> {
         let num_words = num_words(domain_size);
         let mut result = BitSet {
+            domain_size,
             words: vec![!0; num_words],
             marker: PhantomData,
         };
-        result.clear_above(domain_size);
+        result.clear_excess_bits();
         result
     }
 
+    /// Get the domain size.
+    pub fn domain_size(&self) -> usize {
+        self.domain_size
+    }
+
+    /// Clear all elements.
     #[inline]
     pub fn clear(&mut self) {
         for word in &mut self.words {
@@ -60,34 +74,19 @@ impl<T: Idx> BitSet<T> {
         }
     }
 
-    /// Sets all elements up to and including `size`.
-    pub fn set_up_to(&mut self, elem: usize) {
-        for word in &mut self.words {
-            *word = !0;
+    /// Clear excess bits in the final word.
+    fn clear_excess_bits(&mut self) {
+        let num_bits_in_final_word = self.domain_size % WORD_BITS;
+        if num_bits_in_final_word > 0 {
+            let mask = (1 << num_bits_in_final_word) - 1;
+            let final_word_idx = self.words.len() - 1;
+            self.words[final_word_idx] &= mask;
         }
-        self.clear_above(elem);
     }
 
-    /// Clear all elements above `elem`.
-    fn clear_above(&mut self, elem: usize) {
-        let first_clear_block = elem / WORD_BITS;
-
-        if first_clear_block < self.words.len() {
-            // Within `first_clear_block`, the `elem % WORD_BITS` LSBs should
-            // remain.
-            let mask = (1 << (elem % WORD_BITS)) - 1;
-            self.words[first_clear_block] &= mask;
-
-            // All the blocks above `first_clear_block` are fully cleared.
-            for word in &mut self.words[first_clear_block + 1..] {
-                *word = 0;
-            }
-        }
-    }
-
-    /// Efficiently overwrite `self` with `other`. Panics if `self` and `other`
-    /// don't have the same length.
+    /// Efficiently overwrite `self` with `other`.
     pub fn overwrite(&mut self, other: &BitSet<T>) {
+        assert!(self.domain_size == other.domain_size);
         self.words.clone_from_slice(&other.words);
     }
 
@@ -99,16 +98,15 @@ impl<T: Idx> BitSet<T> {
     /// True if `self` contains `elem`.
     #[inline]
     pub fn contains(&self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
         let (word_index, mask) = word_index_and_mask(elem);
         (self.words[word_index] & mask) != 0
     }
 
-    /// True if `self` is a (non-strict) superset of `other`.
-    ///
-    /// The two sets must have the same domain_size.
+    /// Is `self` is a (non-strict) superset of `other`?
     #[inline]
     pub fn superset(&self, other: &BitSet<T>) -> bool {
-        assert_eq!(self.words.len(), other.words.len());
+        assert_eq!(self.domain_size, other.domain_size);
         self.words.iter().zip(&other.words).all(|(a, b)| (a & b) == *b)
     }
 
@@ -121,6 +119,7 @@ impl<T: Idx> BitSet<T> {
     /// Insert `elem`. Returns true if the set has changed.
     #[inline]
     pub fn insert(&mut self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
         let (word_index, mask) = word_index_and_mask(elem);
         let word_ref = &mut self.words[word_index];
         let word = *word_ref;
@@ -134,11 +133,13 @@ impl<T: Idx> BitSet<T> {
         for word in &mut self.words {
             *word = !0;
         }
+        self.clear_excess_bits();
     }
 
     /// Returns true if the set has changed.
     #[inline]
     pub fn remove(&mut self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
         let (word_index, mask) = word_index_and_mask(elem);
         let word_ref = &mut self.words[word_index];
         let word = *word_ref;
@@ -162,6 +163,7 @@ impl<T: Idx> BitSet<T> {
     /// Set `self = self & other` and return true if `self` changed.
     /// (i.e., if any bits were removed).
     pub fn intersect(&mut self, other: &BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
         bitwise(&mut self.words, &other.words, |a, b| { a & b })
     }
 
@@ -182,43 +184,8 @@ impl<T: Idx> BitSet<T> {
 
     /// Duplicates the set as a hybrid set.
     pub fn to_hybrid(&self) -> HybridBitSet<T> {
-        // This domain_size may be slightly larger than the one specified
-        // upon creation, due to rounding up to a whole word. That's ok.
-        let domain_size = self.words.len() * WORD_BITS;
-
         // Note: we currently don't bother trying to make a Sparse set.
-        HybridBitSet::Dense(self.to_owned(), domain_size)
-    }
-
-    pub fn to_string(&self, bits: usize) -> String {
-        let mut result = String::new();
-        let mut sep = '[';
-
-        // Note: this is a little endian printout of bytes.
-
-        // i tracks how many bits we have printed so far.
-        let mut i = 0;
-        for word in &self.words {
-            let mut word = *word;
-            for _ in 0..WORD_BYTES { // for each byte in `word`:
-                let remain = bits - i;
-                // If less than a byte remains, then mask just that many bits.
-                let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
-                assert!(mask <= 0xFF);
-                let byte = word & mask;
-
-                result.push_str(&format!("{}{:02x}", sep, byte));
-
-                if remain <= 8 { break; }
-                word >>= 8;
-                i += 8;
-                sep = '-';
-            }
-            sep = '|';
-        }
-        result.push(']');
-
-        result
+        HybridBitSet::Dense(self.to_owned())
     }
 }
 
@@ -238,12 +205,14 @@ pub trait SubtractFromBitSet<T: Idx> {
 
 impl<T: Idx> UnionIntoBitSet<T> for BitSet<T> {
     fn union_into(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
         bitwise(&mut other.words, &self.words, |a, b| { a | b })
     }
 }
 
 impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> {
     fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
         bitwise(&mut other.words, &self.words, |a, b| { a & !b })
     }
 }
@@ -256,19 +225,36 @@ impl<T: Idx> fmt::Debug for BitSet<T> {
     }
 }
 
-impl<T: Idx> rustc_serialize::Encodable for BitSet<T> {
-    fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
-        self.words.encode(encoder)
-    }
-}
+impl<T: Idx> ToString for BitSet<T> {
+    fn to_string(&self) -> String {
+        let mut result = String::new();
+        let mut sep = '[';
 
-impl<T: Idx> rustc_serialize::Decodable for BitSet<T> {
-    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<BitSet<T>, D::Error> {
-        let words: Vec<Word> = rustc_serialize::Decodable::decode(d)?;
-        Ok(BitSet {
-            words,
-            marker: PhantomData,
-        })
+        // Note: this is a little endian printout of bytes.
+
+        // i tracks how many bits we have printed so far.
+        let mut i = 0;
+        for word in &self.words {
+            let mut word = *word;
+            for _ in 0..WORD_BYTES { // for each byte in `word`:
+                let remain = self.domain_size - i;
+                // If less than a byte remains, then mask just that many bits.
+                let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
+                assert!(mask <= 0xFF);
+                let byte = word & mask;
+
+                result.push_str(&format!("{}{:02x}", sep, byte));
+
+                if remain <= 8 { break; }
+                word >>= 8;
+                i += 8;
+                sep = '-';
+            }
+            sep = '|';
+        }
+        result.push(']');
+
+        result
     }
 }
 
@@ -326,67 +312,78 @@ const SPARSE_MAX: usize = 8;
 ///
 /// This type is used by `HybridBitSet`; do not use directly.
 #[derive(Clone, Debug)]
-pub struct SparseBitSet<T: Idx>(SmallVec<[T; SPARSE_MAX]>);
+pub struct SparseBitSet<T: Idx> {
+    domain_size: usize,
+    elems: SmallVec<[T; SPARSE_MAX]>,
+}
 
 impl<T: Idx> SparseBitSet<T> {
-    fn new_empty() -> Self {
-        SparseBitSet(SmallVec::new())
+    fn new_empty(domain_size: usize) -> Self {
+        SparseBitSet {
+            domain_size,
+            elems: SmallVec::new()
+        }
     }
 
     fn len(&self) -> usize {
-        self.0.len()
+        self.elems.len()
     }
 
     fn is_empty(&self) -> bool {
-        self.0.len() == 0
+        self.elems.len() == 0
     }
 
     fn contains(&self, elem: T) -> bool {
-        self.0.contains(&elem)
+        assert!(elem.index() < self.domain_size);
+        self.elems.contains(&elem)
     }
 
     fn insert(&mut self, elem: T) -> bool {
-        assert!(self.len() < SPARSE_MAX);
-        if let Some(i) = self.0.iter().position(|&e| e >= elem) {
-            if self.0[i] == elem {
+        assert!(elem.index() < self.domain_size);
+        let changed = if let Some(i) = self.elems.iter().position(|&e| e >= elem) {
+            if self.elems[i] == elem {
                 // `elem` is already in the set.
                 false
             } else {
                 // `elem` is smaller than one or more existing elements.
-                self.0.insert(i, elem);
+                self.elems.insert(i, elem);
                 true
             }
         } else {
             // `elem` is larger than all existing elements.
-            self.0.push(elem);
+            self.elems.push(elem);
             true
-        }
+        };
+        assert!(self.len() <= SPARSE_MAX);
+        changed
     }
 
     fn remove(&mut self, elem: T) -> bool {
-        if let Some(i) = self.0.iter().position(|&e| e == elem) {
-            self.0.remove(i);
+        assert!(elem.index() < self.domain_size);
+        if let Some(i) = self.elems.iter().position(|&e| e == elem) {
+            self.elems.remove(i);
             true
         } else {
             false
         }
     }
 
-    fn to_dense(&self, domain_size: usize) -> BitSet<T> {
-        let mut dense = BitSet::new_empty(domain_size);
-        for elem in self.0.iter() {
+    fn to_dense(&self) -> BitSet<T> {
+        let mut dense = BitSet::new_empty(self.domain_size);
+        for elem in self.elems.iter() {
             dense.insert(*elem);
         }
         dense
     }
 
     fn iter(&self) -> slice::Iter<T> {
-        self.0.iter()
+        self.elems.iter()
     }
 }
 
 impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> {
     fn union_into(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
         let mut changed = false;
         for elem in self.iter() {
             changed |= other.insert(*elem);
@@ -397,6 +394,7 @@ impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> {
 
 impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
     fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
         let mut changed = false;
         for elem in self.iter() {
             changed |= other.remove(*elem);
@@ -414,10 +412,14 @@ impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
 ///
 /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
 /// just be `usize`.
+///
+/// All operations that involve an element will panic if the element is equal
+/// to or greater than the domain size. All operations that involve two bitsets
+/// will panic if the bitsets have differing domain sizes.
 #[derive(Clone, Debug)]
 pub enum HybridBitSet<T: Idx> {
-    Sparse(SparseBitSet<T>, usize),
-    Dense(BitSet<T>, usize),
+    Sparse(SparseBitSet<T>),
+    Dense(BitSet<T>),
 }
 
 impl<T: Idx> HybridBitSet<T> {
@@ -427,17 +429,17 @@ impl<T: Idx> HybridBitSet<T> {
     fn dummy() -> Self {
         // The cheapest HybridBitSet to construct, which is only used to get
         // around the borrow checker.
-        HybridBitSet::Sparse(SparseBitSet::new_empty(), 0)
+        HybridBitSet::Sparse(SparseBitSet::new_empty(0))
     }
 
     pub fn new_empty(domain_size: usize) -> Self {
-        HybridBitSet::Sparse(SparseBitSet::new_empty(), domain_size)
+        HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size))
     }
 
-    pub fn domain_size(&self) -> usize {
-        match *self {
-            HybridBitSet::Sparse(_, size) => size,
-            HybridBitSet::Dense(_, size) => size,
+    fn domain_size(&self) -> usize {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.domain_size,
+            HybridBitSet::Dense(dense) => dense.domain_size,
         }
     }
 
@@ -448,83 +450,88 @@ impl<T: Idx> HybridBitSet<T> {
 
     pub fn contains(&self, elem: T) -> bool {
         match self {
-            HybridBitSet::Sparse(sparse, _) => sparse.contains(elem),
-            HybridBitSet::Dense(dense, _) => dense.contains(elem),
+            HybridBitSet::Sparse(sparse) => sparse.contains(elem),
+            HybridBitSet::Dense(dense) => dense.contains(elem),
         }
     }
 
     pub fn superset(&self, other: &HybridBitSet<T>) -> bool {
         match (self, other) {
-            (HybridBitSet::Dense(self_dense, _), HybridBitSet::Dense(other_dense, _)) => {
+            (HybridBitSet::Dense(self_dense), HybridBitSet::Dense(other_dense)) => {
                 self_dense.superset(other_dense)
             }
-            _ => other.iter().all(|elem| self.contains(elem)),
+            _ => {
+                assert!(self.domain_size() == other.domain_size());
+                other.iter().all(|elem| self.contains(elem))
+            }
         }
     }
 
     pub fn is_empty(&self) -> bool {
         match self {
-            HybridBitSet::Sparse(sparse, _) => sparse.is_empty(),
-            HybridBitSet::Dense(dense, _) => dense.is_empty(),
+            HybridBitSet::Sparse(sparse) => sparse.is_empty(),
+            HybridBitSet::Dense(dense) => dense.is_empty(),
         }
     }
 
     pub fn insert(&mut self, elem: T) -> bool {
+        // No need to check `elem` against `self.domain_size` here because all
+        // the match cases check it, one way or another.
         match self {
-            HybridBitSet::Sparse(sparse, _) if sparse.len() < SPARSE_MAX => {
+            HybridBitSet::Sparse(sparse) if sparse.len() < SPARSE_MAX => {
                 // The set is sparse and has space for `elem`.
                 sparse.insert(elem)
             }
-            HybridBitSet::Sparse(sparse, _) if sparse.contains(elem) => {
+            HybridBitSet::Sparse(sparse) if sparse.contains(elem) => {
                 // The set is sparse and does not have space for `elem`, but
                 // that doesn't matter because `elem` is already present.
                 false
             }
-            HybridBitSet::Sparse(_, _) => {
+            HybridBitSet::Sparse(_) => {
                 // The set is sparse and full. Convert to a dense set.
                 match mem::replace(self, HybridBitSet::dummy()) {
-                    HybridBitSet::Sparse(sparse, domain_size) => {
-                        let mut dense = sparse.to_dense(domain_size);
+                    HybridBitSet::Sparse(sparse) => {
+                        let mut dense = sparse.to_dense();
                         let changed = dense.insert(elem);
                         assert!(changed);
-                        *self = HybridBitSet::Dense(dense, domain_size);
+                        *self = HybridBitSet::Dense(dense);
                         changed
                     }
                     _ => unreachable!()
                 }
             }
 
-            HybridBitSet::Dense(dense, _) => dense.insert(elem),
+            HybridBitSet::Dense(dense) => dense.insert(elem),
         }
     }
 
     pub fn insert_all(&mut self) {
         let domain_size = self.domain_size();
         match self {
-            HybridBitSet::Sparse(_, _) => {
-                let dense = BitSet::new_filled(domain_size);
-                *self = HybridBitSet::Dense(dense, domain_size);
+            HybridBitSet::Sparse(_) => {
+                *self = HybridBitSet::Dense(BitSet::new_filled(domain_size));
             }
-            HybridBitSet::Dense(dense, _) => dense.insert_all(),
+            HybridBitSet::Dense(dense) => dense.insert_all(),
         }
     }
 
     pub fn remove(&mut self, elem: T) -> bool {
         // Note: we currently don't bother going from Dense back to Sparse.
         match self {
-            HybridBitSet::Sparse(sparse, _) => sparse.remove(elem),
-            HybridBitSet::Dense(dense, _) => dense.remove(elem),
+            HybridBitSet::Sparse(sparse) => sparse.remove(elem),
+            HybridBitSet::Dense(dense) => dense.remove(elem),
         }
     }
 
     pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
         match self {
-            HybridBitSet::Sparse(_, _) => {
+            HybridBitSet::Sparse(_) => {
                 match other {
-                    HybridBitSet::Sparse(other_sparse, _) => {
+                    HybridBitSet::Sparse(other_sparse) => {
                         // Both sets are sparse. Add the elements in
                         // `other_sparse` to `self_hybrid` one at a time. This
                         // may or may not cause `self_hybrid` to be densified.
+                        assert_eq!(self.domain_size(), other.domain_size());
                         let mut self_hybrid = mem::replace(self, HybridBitSet::dummy());
                         let mut changed = false;
                         for elem in other_sparse.iter() {
@@ -533,14 +540,14 @@ impl<T: Idx> HybridBitSet<T> {
                         *self = self_hybrid;
                         changed
                     }
-                    HybridBitSet::Dense(other_dense, _) => {
+                    HybridBitSet::Dense(other_dense) => {
                         // `self` is sparse and `other` is dense. Densify
                         // `self` and then do the bitwise union.
                         match mem::replace(self, HybridBitSet::dummy()) {
-                            HybridBitSet::Sparse(self_sparse, self_domain_size) => {
-                                let mut new_dense = self_sparse.to_dense(self_domain_size);
+                            HybridBitSet::Sparse(self_sparse) => {
+                                let mut new_dense = self_sparse.to_dense();
                                 let changed = new_dense.union(other_dense);
-                                *self = HybridBitSet::Dense(new_dense, self_domain_size);
+                                *self = HybridBitSet::Dense(new_dense);
                                 changed
                             }
                             _ => unreachable!()
@@ -549,22 +556,22 @@ impl<T: Idx> HybridBitSet<T> {
                 }
             }
 
-            HybridBitSet::Dense(self_dense, _) => self_dense.union(other),
+            HybridBitSet::Dense(self_dense) => self_dense.union(other),
         }
     }
 
     /// Converts to a dense set, consuming itself in the process.
     pub fn to_dense(self) -> BitSet<T> {
         match self {
-            HybridBitSet::Sparse(sparse, domain_size) => sparse.to_dense(domain_size),
-            HybridBitSet::Dense(dense, _) => dense,
+            HybridBitSet::Sparse(sparse) => sparse.to_dense(),
+            HybridBitSet::Dense(dense) => dense,
         }
     }
 
     pub fn iter(&self) -> HybridIter<T> {
         match self {
-            HybridBitSet::Sparse(sparse, _) => HybridIter::Sparse(sparse.iter()),
-            HybridBitSet::Dense(dense, _) => HybridIter::Dense(dense.iter()),
+            HybridBitSet::Sparse(sparse) => HybridIter::Sparse(sparse.iter()),
+            HybridBitSet::Dense(dense) => HybridIter::Dense(dense.iter()),
         }
     }
 }
@@ -572,8 +579,8 @@ impl<T: Idx> HybridBitSet<T> {
 impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> {
     fn union_into(&self, other: &mut BitSet<T>) -> bool {
         match self {
-            HybridBitSet::Sparse(sparse, _) => sparse.union_into(other),
-            HybridBitSet::Dense(dense, _) => dense.union_into(other),
+            HybridBitSet::Sparse(sparse) => sparse.union_into(other),
+            HybridBitSet::Dense(dense) => dense.union_into(other),
         }
     }
 }
@@ -581,8 +588,8 @@ impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> {
 impl<T: Idx> SubtractFromBitSet<T> for HybridBitSet<T> {
     fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
         match self {
-            HybridBitSet::Sparse(sparse, _) => sparse.subtract_from(other),
-            HybridBitSet::Dense(dense, _) => dense.subtract_from(other),
+            HybridBitSet::Sparse(sparse) => sparse.subtract_from(other),
+            HybridBitSet::Dense(dense) => dense.subtract_from(other),
         }
     }
 }
@@ -607,16 +614,24 @@ impl<'a, T: Idx> Iterator for HybridIter<'a, T> {
 ///
 /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
 /// just be `usize`.
+///
+/// All operations that involve an element will panic if the element is equal
+/// to or greater than the domain size.
 #[derive(Clone, Debug, PartialEq)]
 pub struct GrowableBitSet<T: Idx> {
     bit_set: BitSet<T>,
 }
 
 impl<T: Idx> GrowableBitSet<T> {
-    pub fn grow(&mut self, domain_size: T) {
-        let num_words = num_words(domain_size);
-        if self.bit_set.words.len() <= num_words {
-            self.bit_set.words.resize(num_words + 1, 0)
+    /// Ensure that the set can hold at least `min_domain_size` elements.
+    pub fn ensure(&mut self, min_domain_size: usize) {
+        if self.bit_set.domain_size < min_domain_size {
+            self.bit_set.domain_size = min_domain_size;
+        }
+
+        let min_num_words = num_words(min_domain_size);
+        if self.bit_set.words.len() < min_num_words {
+            self.bit_set.words.resize(min_num_words, 0)
         }
     }
 
@@ -631,7 +646,7 @@ impl<T: Idx> GrowableBitSet<T> {
     /// Returns true if the set has changed.
     #[inline]
     pub fn insert(&mut self, elem: T) -> bool {
-        self.grow(elem);
+        self.ensure(elem.index() + 1);
         self.bit_set.insert(elem)
     }
 
@@ -651,31 +666,34 @@ impl<T: Idx> GrowableBitSet<T> {
 /// `R` and `C` are index types used to identify rows and columns respectively;
 /// typically newtyped `usize` wrappers, but they can also just be `usize`.
 ///
+/// All operations that involve a row and/or column index will panic if the
+/// index exceeds the relevant bound.
 #[derive(Clone, Debug)]
 pub struct BitMatrix<R: Idx, C: Idx> {
-    columns: usize,
+    num_rows: usize,
+    num_columns: usize,
     words: Vec<Word>,
     marker: PhantomData<(R, C)>,
 }
 
 impl<R: Idx, C: Idx> BitMatrix<R, C> {
     /// Create a new `rows x columns` matrix, initially empty.
-    pub fn new(rows: usize, columns: usize) -> BitMatrix<R, C> {
+    pub fn new(num_rows: usize, num_columns: usize) -> BitMatrix<R, C> {
         // For every element, we need one bit for every other
         // element. Round up to an even number of words.
-        let words_per_row = num_words(columns);
+        let words_per_row = num_words(num_columns);
         BitMatrix {
-            columns,
-            words: vec![0; rows * words_per_row],
+            num_rows,
+            num_columns,
+            words: vec![0; num_rows * words_per_row],
             marker: PhantomData,
         }
     }
 
     /// The range of bits for a given row.
     fn range(&self, row: R) -> (usize, usize) {
-        let row = row.index();
-        let words_per_row = num_words(self.columns);
-        let start = row * words_per_row;
+        let words_per_row = num_words(self.num_columns);
+        let start = row.index() * words_per_row;
         (start, start + words_per_row)
     }
 
@@ -683,7 +701,8 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
     /// `column` to the bitset for `row`.
     ///
     /// Returns true if this changed the matrix, and false otherwise.
-    pub fn insert(&mut self, row: R, column: R) -> bool {
+    pub fn insert(&mut self, row: R, column: C) -> bool {
+        assert!(row.index() < self.num_rows && column.index() < self.num_columns);
         let (start, _) = self.range(row);
         let (word_index, mask) = word_index_and_mask(column);
         let words = &mut self.words[..];
@@ -697,7 +716,8 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
     /// the matrix cell at `(row, column)` true?  Put yet another way,
     /// if the matrix represents (transitive) reachability, can
     /// `row` reach `column`?
-    pub fn contains(&self, row: R, column: R) -> bool {
+    pub fn contains(&self, row: R, column: C) -> bool {
+        assert!(row.index() < self.num_rows && column.index() < self.num_columns);
         let (start, _) = self.range(row);
         let (word_index, mask) = word_index_and_mask(column);
         (self.words[start + word_index] & mask) != 0
@@ -707,11 +727,12 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
     /// is an O(n) operation where `n` is the number of elements
     /// (somewhat independent from the actual size of the
     /// intersection, in particular).
-    pub fn intersect_rows(&self, a: R, b: R) -> Vec<C> {
-        let (a_start, a_end) = self.range(a);
-        let (b_start, b_end) = self.range(b);
-        let mut result = Vec::with_capacity(self.columns);
-        for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
+    pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> {
+        assert!(row1.index() < self.num_rows && row2.index() < self.num_rows);
+        let (row1_start, row1_end) = self.range(row1);
+        let (row2_start, row2_end) = self.range(row2);
+        let mut result = Vec::with_capacity(self.num_columns);
+        for (base, (i, j)) in (row1_start..row1_end).zip(row2_start..row2_end).enumerate() {
             let mut v = self.words[i] & self.words[j];
             for bit in 0..WORD_BITS {
                 if v == 0 {
@@ -734,6 +755,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
     /// `write` can reach everything that `read` can (and
     /// potentially more).
     pub fn union_rows(&mut self, read: R, write: R) -> bool {
+        assert!(read.index() < self.num_rows && write.index() < self.num_rows);
         let (read_start, read_end) = self.range(read);
         let (write_start, write_end) = self.range(write);
         let words = &mut self.words[..];
@@ -750,6 +772,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
     pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
+        assert!(row.index() < self.num_rows);
         let (start, end) = self.range(row);
         BitIter {
             cur: None,
@@ -865,48 +888,19 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
 }
 
 #[inline]
-fn num_words<T: Idx>(elements: T) -> usize {
-    (elements.index() + WORD_BITS - 1) / WORD_BITS
+fn num_words<T: Idx>(domain_size: T) -> usize {
+    (domain_size.index() + WORD_BITS - 1) / WORD_BITS
 }
 
 #[inline]
-fn word_index_and_mask<T: Idx>(index: T) -> (usize, Word) {
-    let index = index.index();
-    let word_index = index / WORD_BITS;
-    let mask = 1 << (index % WORD_BITS);
+fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
+    let elem = elem.index();
+    let word_index = elem / WORD_BITS;
+    let mask = 1 << (elem % WORD_BITS);
     (word_index, mask)
 }
 
 #[test]
-fn test_clear_above() {
-    use std::cmp;
-
-    for i in 0..256 {
-        let mut idx_buf: BitSet<usize> = BitSet::new_filled(128);
-        idx_buf.clear_above(i);
-
-        let elems: Vec<usize> = idx_buf.iter().collect();
-        let expected: Vec<usize> = (0..cmp::min(i, 128)).collect();
-        assert_eq!(elems, expected);
-    }
-}
-
-#[test]
-fn test_set_up_to() {
-    for i in 0..128 {
-        for mut idx_buf in
-            vec![BitSet::new_empty(128), BitSet::new_filled(128)].into_iter()
-        {
-            idx_buf.set_up_to(i);
-
-            let elems: Vec<usize> = idx_buf.iter().collect();
-            let expected: Vec<usize> = (0..i).collect();
-            assert_eq!(elems, expected);
-        }
-    }
-}
-
-#[test]
 fn test_new_filled() {
     for i in 0..128 {
         let idx_buf = BitSet::new_filled(i);
@@ -936,7 +930,7 @@ fn bitset_iter_works() {
 
 #[test]
 fn bitset_iter_works_2() {
-    let mut bitset: BitSet<usize> = BitSet::new_empty(319);
+    let mut bitset: BitSet<usize> = BitSet::new_empty(320);
     bitset.insert(0);
     bitset.insert(127);
     bitset.insert(191);
@@ -1037,7 +1031,7 @@ fn grow() {
         assert!(set.insert(index));
         assert!(!set.insert(index));
     }
-    set.grow(128);
+    set.ensure(128);
 
     // Check if the bits set before growing are still set
     for index in 0..65 {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index f9e717f8d45..74e7c6c21ed 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1937,8 +1937,7 @@ impl EarlyLintPass for KeywordIdents {
         let next_edition = match cx.sess.edition() {
             Edition::Edition2015 => {
                 match &ident.as_str()[..] {
-                    "async" |
-                    "try" => Edition::Edition2018,
+                    "async" | "try" | "dyn" => Edition::Edition2018,
                     _ => return,
                 }
             }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index dfed41cb1de..67e4394c9aa 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -22,6 +22,7 @@ use std::collections::VecDeque;
 use std::fmt;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
+use syntax::errors::Applicability;
 
 mod region_name;
 mod var_name;
@@ -540,7 +541,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                             RegionName::Named(name) => format!("{}", name),
                             RegionName::Synthesized(_) => "'_".to_string(),
                         };
-                        diag.span_suggestion(
+                        diag.span_suggestion_with_applicability(
                             span,
                             &format!(
                                 "to allow this impl Trait to capture borrowed data with lifetime \
@@ -548,6 +549,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                                 fr_name, suggestable_fr_name,
                             ),
                             format!("{} + {}", snippet, suggestable_fr_name),
+                            Applicability::MachineApplicable,
                         );
                     }
                 }
diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs
index 45baab844ab..1fbeb66be30 100644
--- a/src/librustc_mir/dataflow/graphviz.rs
+++ b/src/librustc_mir/dataflow/graphviz.rs
@@ -216,13 +216,12 @@ where MWF: MirWithFlowState<'tcx>,
         let i = n.index();
 
         let flow = self.mbcx.flow_state();
-        let bits_per_block = flow.sets.bits_per_block();
 
         write!(w, "<tr>")?;
 
         // Entry
         let set = flow.sets.on_entry_set_for(i);
-        write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string(bits_per_block)))?;
+        write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
 
         // Terminator
         write!(w, "<td>")?;
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index 984d1f686d9..efdf9c33023 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -354,7 +354,8 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx>
     // sets on_entry bits for Arg places
     fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
         // set all bits to 1 (uninit) before gathering counterevidence
-        entry_set.set_up_to(self.bits_per_block());
+        assert!(self.bits_per_block() == entry_set.domain_size());
+        entry_set.insert_all();
 
         drop_flag_effects_for_function_entry(
             self.tcx, self.mir, self.mdpe,
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index d50ef2242fa..ea01d17ac13 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -256,7 +256,7 @@ impl<'tcx> InliningMap<'tcx> {
         let new_items_count_total = new_items_count + self.targets.len();
 
         self.targets.reserve(new_items_count);
-        self.inlines.grow(new_items_count_total);
+        self.inlines.ensure(new_items_count_total);
 
         for (i, (target, inline)) in new_targets.enumerate() {
             self.targets.push(target);
diff --git a/src/librustc_target/spec/netbsd_base.rs b/src/librustc_target/spec/netbsd_base.rs
index 8b6bb5dec91..8cb5a33cdb5 100644
--- a/src/librustc_target/spec/netbsd_base.rs
+++ b/src/librustc_target/spec/netbsd_base.rs
@@ -29,6 +29,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         target_family: Some("unix".to_string()),
         linker_is_gnu: true,
+        no_default_libraries: false,
         has_rpath: true,
         pre_link_args: args,
         position_independent_executables: true,
diff --git a/src/librustc_target/spec/x86_64_rumprun_netbsd.rs b/src/librustc_target/spec/x86_64_rumprun_netbsd.rs
index af846653af7..684bf5a6c10 100644
--- a/src/librustc_target/spec/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_target/spec/x86_64_rumprun_netbsd.rs
@@ -21,7 +21,6 @@ pub fn target() -> TargetResult {
     base.has_rpath = false;
     base.position_independent_executables = false;
     base.disable_redzone = true;
-    base.no_default_libraries = false;
     base.exe_allocation_crate = None;
     base.stack_probes = true;
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 093788d2095..b85604d860b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -272,6 +272,7 @@ impl DocAccessLevels for AccessLevels<DefId> {
 pub fn new_handler(error_format: ErrorOutputType,
                    source_map: Option<Lrc<source_map::SourceMap>>,
                    treat_err_as_bug: bool,
+                   ui_testing: bool,
 ) -> errors::Handler {
     // rustdoc doesn't override (or allow to override) anything from this that is relevant here, so
     // stick to the defaults
@@ -283,7 +284,7 @@ pub fn new_handler(error_format: ErrorOutputType,
                 source_map.map(|cm| cm as _),
                 false,
                 sessopts.debugging_opts.teach,
-            ).ui_testing(sessopts.debugging_opts.ui_testing)
+            ).ui_testing(ui_testing)
         ),
         ErrorOutputType::Json(pretty) => {
             let source_map = source_map.unwrap_or_else(
@@ -293,7 +294,7 @@ pub fn new_handler(error_format: ErrorOutputType,
                     None,
                     source_map,
                     pretty,
-                ).ui_testing(sessopts.debugging_opts.ui_testing)
+                ).ui_testing(ui_testing)
             )
         },
         ErrorOutputType::Short(color_config) => Box::new(
@@ -335,6 +336,7 @@ pub fn run_core(search_paths: SearchPaths,
                 mut manual_passes: Vec<String>,
                 mut default_passes: passes::DefaultPassOption,
                 treat_err_as_bug: bool,
+                ui_testing: bool,
 ) -> (clean::Crate, RenderInfo, Vec<String>) {
     // Parse, resolve, and typecheck the given crate.
 
@@ -389,6 +391,8 @@ pub fn run_core(search_paths: SearchPaths,
         actually_rustdoc: true,
         debugging_opts: config::DebuggingOptions {
             force_unstable_if_unmarked,
+            treat_err_as_bug,
+            ui_testing,
             ..config::basic_debugging_options()
         },
         error_format,
@@ -400,7 +404,8 @@ pub fn run_core(search_paths: SearchPaths,
         let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()));
         let diagnostic_handler = new_handler(error_format,
                                              Some(source_map.clone()),
-                                             treat_err_as_bug);
+                                             treat_err_as_bug,
+                                             ui_testing);
 
         let mut sess = session::build_session_(
             sessopts, cpath, diagnostic_handler, source_map,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 18ad862c11b..d14275aeb6b 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -37,6 +37,7 @@ use std::fmt::{self, Write};
 use std::borrow::Cow;
 use std::ops::Range;
 use std::str;
+use syntax::edition::Edition;
 
 use html::toc::TocBuilder;
 use html::highlight;
@@ -170,6 +171,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
         let event = self.inner.next();
         let compile_fail;
         let ignore;
+        let edition;
         if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
             let parse_result = LangString::parse(&lang, self.check_error_codes);
             if !parse_result.rust {
@@ -177,6 +179,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
             }
             compile_fail = parse_result.compile_fail;
             ignore = parse_result.ignore;
+            edition = parse_result.edition;
         } else {
             return event;
         }
@@ -212,6 +215,17 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                 } else {
                     ""
                 };
+
+                let edition_string = if let Some(e @ Edition::Edition2018) = edition {
+                    format!("&amp;edition={}{}", e,
+                            if channel == "&amp;version=nightly" { "" }
+                            else { "&amp;version=nightly" })
+                } else if let Some(e) = edition {
+                    format!("&amp;edition={}", e)
+                } else {
+                    "".to_owned()
+                };
+
                 // These characters don't need to be escaped in a URI.
                 // FIXME: use a library function for percent encoding.
                 fn dont_escape(c: u8) -> bool {
@@ -231,26 +245,44 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                     }
                 }
                 Some(format!(
-                    r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
-                    url, test_escaped, channel
+                    r#"<a class="test-arrow" target="_blank" href="{}?code={}{}{}">Run</a>"#,
+                    url, test_escaped, channel, edition_string
                 ))
             });
+
             let tooltip = if ignore {
-                Some(("This example is not tested", "ignore"))
+                Some(("This example is not tested".to_owned(), "ignore"))
             } else if compile_fail {
-                Some(("This example deliberately fails to compile", "compile_fail"))
+                Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
+            } else if let Some(e) = edition {
+                Some((format!("This code runs with edition {}", e), "edition"))
             } else {
                 None
             };
-            s.push_str(&highlight::render_with_highlighting(
-                        &text,
-                        Some(&format!("rust-example-rendered{}",
-                                      if ignore { " ignore" }
-                                      else if compile_fail { " compile_fail" }
-                                      else { "" })),
-                        playground_button.as_ref().map(String::as_str),
-                        tooltip));
-            Some(Event::Html(s.into()))
+
+            if let Some((s1, s2)) = tooltip {
+                s.push_str(&highlight::render_with_highlighting(
+                    &text,
+                    Some(&format!("rust-example-rendered{}",
+                                  if ignore { " ignore" }
+                                  else if compile_fail { " compile_fail" }
+                                  else if edition.is_some() { " edition " }
+                                  else { "" })),
+                    playground_button.as_ref().map(String::as_str),
+                    Some((s1.as_str(), s2))));
+                Some(Event::Html(s.into()))
+            } else {
+                s.push_str(&highlight::render_with_highlighting(
+                    &text,
+                    Some(&format!("rust-example-rendered{}",
+                                  if ignore { " ignore" }
+                                  else if compile_fail { " compile_fail" }
+                                  else if edition.is_some() { " edition " }
+                                  else { "" })),
+                    playground_button.as_ref().map(String::as_str),
+                    None));
+                Some(Event::Html(s.into()))
+            }
         })
     }
 }
@@ -577,6 +609,7 @@ pub struct LangString {
     pub compile_fail: bool,
     pub error_codes: Vec<String>,
     pub allow_fail: bool,
+    pub edition: Option<Edition>
 }
 
 impl LangString {
@@ -591,6 +624,7 @@ impl LangString {
             compile_fail: false,
             error_codes: Vec::new(),
             allow_fail: false,
+            edition: None,
         }
     }
 
@@ -625,6 +659,11 @@ impl LangString {
                     seen_rust_tags = !seen_other_tags || seen_rust_tags;
                     data.no_run = true;
                 }
+                x if allow_error_code_check && x.starts_with("edition") => {
+                    // allow_error_code_check is true if we're on nightly, which
+                    // is needed for edition support
+                    data.edition = x[7..].parse::<Edition>().ok();
+                }
                 x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => {
                     if x[1..].parse::<u32>().is_ok() {
                         data.error_codes.push(x.to_owned());
@@ -925,12 +964,14 @@ mod tests {
     use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
     use super::plain_summary_line;
     use std::cell::RefCell;
+    use syntax::edition::Edition;
 
     #[test]
     fn test_lang_string_parse() {
         fn t(s: &str,
             should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
-            compile_fail: bool, allow_fail: bool, error_codes: Vec<String>) {
+            compile_fail: bool, allow_fail: bool, error_codes: Vec<String>,
+             edition: Option<Edition>) {
             assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
                 should_panic,
                 no_run,
@@ -941,6 +982,7 @@ mod tests {
                 error_codes,
                 original: s.to_owned(),
                 allow_fail,
+                edition,
             })
         }
 
@@ -948,23 +990,26 @@ mod tests {
             Vec::new()
         }
 
-        // marker                | should_panic| no_run| ignore| rust | test_harness| compile_fail
-        //                       | allow_fail | error_codes
-        t("",                      false,        false,  false,  true,  false, false, false, v());
-        t("rust",                  false,        false,  false,  true,  false, false, false, v());
-        t("sh",                    false,        false,  false,  false, false, false, false, v());
-        t("ignore",                false,        false,  true,   true,  false, false, false, v());
-        t("should_panic",          true,         false,  false,  true,  false, false, false, v());
-        t("no_run",                false,        true,   false,  true,  false, false, false, v());
-        t("test_harness",          false,        false,  false,  true,  true,  false, false, v());
-        t("compile_fail",          false,        true,   false,  true,  false, true,  false, v());
-        t("allow_fail",            false,        false,  false,  true,  false, false, true,  v());
-        t("{.no_run .example}",    false,        true,   false,  true,  false, false, false, v());
-        t("{.sh .should_panic}",   true,         false,  false,  false, false, false, false, v());
-        t("{.example .rust}",      false,        false,  false,  true,  false, false, false, v());
-        t("{.test_harness .rust}", false,        false,  false,  true,  true,  false, false, v());
-        t("text, no_run",          false,        true,   false,  false, false, false, false, v());
-        t("text,no_run",           false,        true,   false,  false, false, false, false, v());
+        // ignore-tidy-linelength
+        // marker                | should_panic | no_run | ignore | rust | test_harness
+        //                       | compile_fail | allow_fail | error_codes | edition
+        t("",                      false,         false,   false,   true,  false, false, false, v(), None);
+        t("rust",                  false,         false,   false,   true,  false, false, false, v(), None);
+        t("sh",                    false,         false,   false,   false, false, false, false, v(), None);
+        t("ignore",                false,         false,   true,    true,  false, false, false, v(), None);
+        t("should_panic",          true,          false,   false,   true,  false, false, false, v(), None);
+        t("no_run",                false,         true,    false,   true,  false, false, false, v(), None);
+        t("test_harness",          false,         false,   false,   true,  true,  false, false, v(), None);
+        t("compile_fail",          false,         true,    false,   true,  false, true,  false, v(), None);
+        t("allow_fail",            false,         false,   false,   true,  false, false, true,  v(), None);
+        t("{.no_run .example}",    false,         true,    false,   true,  false, false, false, v(), None);
+        t("{.sh .should_panic}",   true,          false,   false,   false, false, false, false, v(), None);
+        t("{.example .rust}",      false,         false,   false,   true,  false, false, false, v(), None);
+        t("{.test_harness .rust}", false,         false,   false,   true,  true,  false, false, v(), None);
+        t("text, no_run",          false,         true,    false,   false, false, false, false, v(), None);
+        t("text,no_run",           false,         true,    false,   false, false, false, false, v(), None);
+        t("edition2015",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2015));
+        t("edition2018",           false,         false,   false,   true,  false, false, false, v(), Some(Edition::Edition2018));
     }
 
     #[test]
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 5607c97a496..2456a5ad14a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -409,8 +409,11 @@ fn main_args(args: &[String]) -> isize {
     let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
         *x == "treat-err-as-bug"
     });
+    let ui_testing = matches.opt_strs("Z").iter().any(|x| {
+        *x == "ui-testing"
+    });
 
-    let diag = core::new_handler(error_format, None, treat_err_as_bug);
+    let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
 
     // check for deprecated options
     check_deprecated_options(&matches, &diag);
@@ -565,7 +568,7 @@ fn main_args(args: &[String]) -> isize {
     let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format,
                             move |out| {
         let Output { krate, passes, renderinfo } = out;
-        let diag = core::new_handler(error_format, None, treat_err_as_bug);
+        let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
         info!("going to format");
         match output_format.as_ref().map(|s| &**s) {
             Some("html") | None => {
@@ -702,6 +705,9 @@ where R: 'static + Send,
     let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
         *x == "treat-err-as-bug"
     });
+    let ui_testing = matches.opt_strs("Z").iter().any(|x| {
+        *x == "ui-testing"
+    });
 
     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
@@ -715,7 +721,7 @@ where R: 'static + Send,
                            display_warnings, crate_name.clone(),
                            force_unstable_if_unmarked, edition, cg, error_format,
                            lint_opts, lint_cap, describe_lints, manual_passes, default_passes,
-                           treat_err_as_bug);
+                           treat_err_as_bug, ui_testing);
 
         info!("finished with rustc");
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 8a9ca924ee1..dbebc3ab393 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -545,7 +545,7 @@ impl Collector {
         let opts = self.opts.clone();
         let maybe_sysroot = self.maybe_sysroot.clone();
         let linker = self.linker.clone();
-        let edition = self.edition;
+        let edition = config.edition.unwrap_or(self.edition);
         debug!("Creating test {}: {}", name, test);
         self.tests.push(testing::TestDescAndFn {
             desc: testing::TestDesc {
diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index f0b49c3d9bc..6f1652cdee0 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -16,6 +16,7 @@ Core encoding and decoding interfaces.
 
 use std::borrow::Cow;
 use std::intrinsics;
+use std::marker::PhantomData;
 use std::path;
 use std::rc::Rc;
 use std::cell::{Cell, RefCell};
@@ -547,6 +548,19 @@ impl Decodable for () {
     }
 }
 
+impl<T> Encodable for PhantomData<T> {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_unit()
+    }
+}
+
+impl<T> Decodable for PhantomData<T> {
+    fn decode<D: Decoder>(d: &mut D) -> Result<PhantomData<T>, D::Error> {
+        d.read_nil()?;
+        Ok(PhantomData)
+    }
+}
+
 impl<'a, T: ?Sized + Encodable> Encodable for &'a T {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         (**self).encode(s)
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6ec1ad969ee..7a13beb7852 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1578,8 +1578,9 @@ impl<'a> Parser<'a> {
             impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
             TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
         } else if self.check_keyword(keywords::Dyn) &&
-                  self.look_ahead(1, |t| t.can_begin_bound() &&
-                                         !can_continue_type_after_non_fn_ident(t)) {
+                  (self.span.edition() == Edition::Edition2018 ||
+                   self.look_ahead(1, |t| t.can_begin_bound() &&
+                                         !can_continue_type_after_non_fn_ident(t))) {
             self.bump(); // `dyn`
             // Always parse bounds greedily for better error recovery.
             let bounds = self.parse_generic_bounds()?;
@@ -1780,27 +1781,32 @@ impl<'a> Parser<'a> {
             (pat, self.parse_ty()?)
         } else {
             debug!("parse_arg_general ident_to_pat");
+            let parser_snapshot_before_ty = self.clone();
+            let mut ty = self.parse_ty();
+            if ty.is_ok() && self.token == token::Colon {
+                // This wasn't actually a type, but a pattern looking like a type,
+                // so we are going to rollback and re-parse for recovery.
+                ty = self.unexpected();
+            }
+            match ty {
+                Ok(ty) => {
+                    let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
+                    let pat = P(Pat {
+                        id: ast::DUMMY_NODE_ID,
+                        node: PatKind::Ident(
+                            BindingMode::ByValue(Mutability::Immutable), ident, None),
+                        span: ty.span,
+                    });
+                    (pat, ty)
+                }
+                Err(mut err) => {
+                    // Recover from attempting to parse the argument as a type without pattern.
+                    err.cancel();
+                    mem::replace(self, parser_snapshot_before_ty);
+                    let pat = self.parse_pat()?;
+                    self.expect(&token::Colon)?;
+                    let ty = self.parse_ty()?;
 
-            let parser_snapshot_before_pat = self.clone();
-
-            // Once we can use edition 2018 in the compiler,
-            // replace this with real try blocks.
-            macro_rules! try_block {
-                ($($inside:tt)*) => (
-                    (||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
-                )
-            }
-
-            // We're going to try parsing the argument as a pattern (even though it's not
-            // allowed). This way we can provide better errors to the user.
-            let pat_arg: PResult<'a, _> = try_block! {
-                let pat = self.parse_pat()?;
-                self.expect(&token::Colon)?;
-                (pat, self.parse_ty()?)
-            };
-
-            match pat_arg {
-                Ok((pat, ty)) => {
                     let mut err = self.diagnostic().struct_span_err_with_code(
                         pat.span,
                         "patterns aren't allowed in methods without bodies",
@@ -1813,6 +1819,7 @@ impl<'a> Parser<'a> {
                         Applicability::MachineApplicable,
                     );
                     err.emit();
+
                     // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
                     let pat = P(Pat {
                         node: PatKind::Wild,
@@ -1821,22 +1828,6 @@ impl<'a> Parser<'a> {
                     });
                     (pat, ty)
                 }
-                Err(mut err) => {
-                    err.cancel();
-                    // Recover from attempting to parse the argument as a pattern. This means
-                    // the type is alone, with no name, e.g. `fn foo(u32)`.
-                    mem::replace(self, parser_snapshot_before_pat);
-                    debug!("parse_arg_general ident_to_pat");
-                    let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
-                    let ty = self.parse_ty()?;
-                    let pat = P(Pat {
-                        id: ast::DUMMY_NODE_ID,
-                        node: PatKind::Ident(
-                            BindingMode::ByValue(Mutability::Immutable), ident, None),
-                        span: ty.span,
-                    });
-                    (pat, ty)
-                }
             }
         };
 
@@ -2702,8 +2693,8 @@ impl<'a> Parser<'a> {
                   token::Literal(token::Float(n), _suf) => {
                     self.bump();
                     let fstr = n.as_str();
-                    let mut err = self.diagnostic().struct_span_err(self.prev_span,
-                        &format!("unexpected token: `{}`", n));
+                    let mut err = self.diagnostic()
+                        .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n));
                     err.span_label(self.prev_span, "unexpected token");
                     if fstr.chars().all(|x| "0123456789.".contains(x)) {
                         let float = match fstr.parse::<f64>().ok() {
@@ -2863,8 +2854,8 @@ impl<'a> Parser<'a> {
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
                 let span_of_tilde = lo;
-                let mut err = self.diagnostic().struct_span_err(span_of_tilde,
-                        "`~` cannot be used as a unary operator");
+                let mut err = self.diagnostic()
+                    .struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator");
                 err.span_suggestion_short_with_applicability(
                     span_of_tilde,
                     "use `!` to perform bitwise negation",
@@ -3422,6 +3413,24 @@ impl<'a> Parser<'a> {
             );
             err.emit();
         }
+        let in_span = self.prev_span;
+        if self.eat_keyword(keywords::In) {
+            // a common typo: `for _ in in bar {}`
+            let mut err = self.sess.span_diagnostic.struct_span_err(
+                self.prev_span,
+                "expected iterable, found keyword `in`",
+            );
+            err.span_suggestion_short_with_applicability(
+                in_span.until(self.prev_span),
+                "remove the duplicated `in`",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+            err.note("if you meant to use emplacement syntax, it is obsolete (for now, anyway)");
+            err.note("for more information on the status of emplacement syntax, see <\
+                      https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>");
+            err.emit();
+        }
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
@@ -4765,12 +4774,9 @@ impl<'a> Parser<'a> {
         if !self.eat(&token::OpenDelim(token::Brace)) {
             let sp = self.span;
             let tok = self.this_token_to_string();
-            let mut do_not_suggest_help = false;
             let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok));
-            if self.token.is_keyword(keywords::In) || self.token == token::Colon {
-                do_not_suggest_help = true;
-                e.span_label(sp, "expected `{`");
-            }
+            let do_not_suggest_help =
+                self.token.is_keyword(keywords::In) || self.token == token::Colon;
 
             if self.token.is_ident_named("and") {
                 e.span_suggestion_short_with_applicability(
@@ -4801,6 +4807,7 @@ impl<'a> Parser<'a> {
                         || do_not_suggest_help {
                         // if the next token is an open brace (e.g., `if a b {`), the place-
                         // inside-a-block suggestion would be more likely wrong than right
+                        e.span_label(sp, "expected `{`");
                         return Err(e);
                     }
                     let mut stmt_span = stmt.span;
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 6e8014284ec..01bc7f6ad30 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -136,6 +136,7 @@ fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
         keywords::Unsafe.name(),
         keywords::Extern.name(),
         keywords::Typeof.name(),
+        keywords::Dyn.name(),
     ].contains(&ident.name)
 }
 
diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs
index 7709db72a02..5819cd7f480 100644
--- a/src/libsyntax_pos/edition.rs
+++ b/src/libsyntax_pos/edition.rs
@@ -12,7 +12,7 @@ use std::fmt;
 use std::str::FromStr;
 
 /// The edition of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable, Eq)]
 #[non_exhaustive]
 pub enum Edition {
     // editions must be kept in order, oldest to newest
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index defdca9abd1..d412412fc65 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -414,26 +414,25 @@ declare_keywords! {
     (50, Yield,              "yield")
 
     // Edition-specific keywords reserved for future use.
-    (51, Async,              "async") // >= 2018 Edition Only
-    (52, Try,                "try") // >= 2018 Edition Only
+    (51, Async,              "async") // >= 2018 Edition only
+    (52, Dyn,                "dyn") // >= 2018 Edition only
+    (53, Try,                "try") // >= 2018 Edition only
 
     // Special lifetime names
-    (53, UnderscoreLifetime, "'_")
-    (54, StaticLifetime,     "'static")
+    (54, UnderscoreLifetime, "'_")
+    (55, StaticLifetime,     "'static")
 
     // Weak keywords, have special meaning only in specific contexts.
-    (55, Auto,               "auto")
-    (56, Catch,              "catch")
-    (57, Default,            "default")
-    (58, Dyn,                "dyn")
+    (56, Auto,               "auto")
+    (57, Catch,              "catch")
+    (58, Default,            "default")
     (59, Union,              "union")
     (60, Existential,        "existential")
 }
 
 impl Symbol {
     fn is_unused_keyword_2018(self) -> bool {
-        self >= keywords::Async.name() &&
-        self <= keywords::Try.name()
+        self >= keywords::Async.name() && self <= keywords::Try.name()
     }
 }
 
diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
index 66ee48ed4c9..b82cbc1ab36 100644
--- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
+++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
@@ -1,13 +1,13 @@
 error: `[v2]` cannot be resolved, ignoring it...
   --> $DIR/deny-intra-link-resolution-failure.rs:13:6
    |
-13 | /// [v2] //~ ERROR
+LL | /// [v2] //~ ERROR
    |      ^^ cannot be resolved, ignoring
    |
 note: lint level defined here
   --> $DIR/deny-intra-link-resolution-failure.rs:11:9
    |
-11 | #![deny(intra_doc_link_resolution_failure)]
+LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
 
diff --git a/src/test/rustdoc-ui/deprecated-attrs.stderr b/src/test/rustdoc-ui/deprecated-attrs.stderr
index 77ba4b2a2b6..5bd62d60b48 100644
--- a/src/test/rustdoc-ui/deprecated-attrs.stderr
+++ b/src/test/rustdoc-ui/deprecated-attrs.stderr
@@ -1,9 +1,9 @@
 warning: the `#![doc(no_default_passes)]` attribute is considered deprecated
-  |
-  = warning: please see https://github.com/rust-lang/rust/issues/44136
-  = help: you may want to use `#![doc(document_private_items)]`
+   |
+   = warning: please see https://github.com/rust-lang/rust/issues/44136
+   = help: you may want to use `#![doc(document_private_items)]`
 
 warning: the `#![doc(passes = "...")]` attribute is considered deprecated
-  |
-  = warning: please see https://github.com/rust-lang/rust/issues/44136
+   |
+   = warning: please see https://github.com/rust-lang/rust/issues/44136
 
diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
index 231963976ea..498d02a7d1c 100644
--- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
+++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
@@ -1,13 +1,13 @@
 error: `[TypeAlias::hoge]` cannot be resolved, ignoring it...
   --> $DIR/intra-doc-alias-ice.rs:15:30
    |
-15 | /// [broken cross-reference](TypeAlias::hoge) //~ ERROR
+LL | /// [broken cross-reference](TypeAlias::hoge) //~ ERROR
    |                              ^^^^^^^^^^^^^^^ cannot be resolved, ignoring
    |
 note: lint level defined here
   --> $DIR/intra-doc-alias-ice.rs:11:9
    |
-11 | #![deny(intra_doc_link_resolution_failure)]
+LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
 
diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr
index 2a51e94b1f5..c05f99fadc9 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning.stderr
@@ -1,7 +1,7 @@
 warning: `[Foo::baz]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:13:23
    |
-13 |        //! Test with [Foo::baz], [Bar::foo], ...
+LL |        //! Test with [Foo::baz], [Bar::foo], ...
    |                       ^^^^^^^^ cannot be resolved, ignoring
    |
    = note: #[warn(intra_doc_link_resolution_failure)] on by default
@@ -10,7 +10,7 @@ warning: `[Foo::baz]` cannot be resolved, ignoring it...
 warning: `[Bar::foo]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:13:35
    |
-13 |        //! Test with [Foo::baz], [Bar::foo], ...
+LL |        //! Test with [Foo::baz], [Bar::foo], ...
    |                                   ^^^^^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -18,7 +18,7 @@ warning: `[Bar::foo]` cannot be resolved, ignoring it...
 warning: `[Uniooon::X]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:14:13
    |
-14 |      //! , [Uniooon::X] and [Qux::Z].
+LL |      //! , [Uniooon::X] and [Qux::Z].
    |             ^^^^^^^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -26,7 +26,7 @@ warning: `[Uniooon::X]` cannot be resolved, ignoring it...
 warning: `[Qux::Z]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:14:30
    |
-14 |      //! , [Uniooon::X] and [Qux::Z].
+LL |      //! , [Uniooon::X] and [Qux::Z].
    |                              ^^^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -34,7 +34,7 @@ warning: `[Qux::Z]` cannot be resolved, ignoring it...
 warning: `[Uniooon::X]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:16:14
    |
-16 |       //! , [Uniooon::X] and [Qux::Z].
+LL |       //! , [Uniooon::X] and [Qux::Z].
    |              ^^^^^^^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -42,7 +42,7 @@ warning: `[Uniooon::X]` cannot be resolved, ignoring it...
 warning: `[Qux::Z]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:16:31
    |
-16 |       //! , [Uniooon::X] and [Qux::Z].
+LL |       //! , [Uniooon::X] and [Qux::Z].
    |                               ^^^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -50,7 +50,7 @@ warning: `[Qux::Z]` cannot be resolved, ignoring it...
 warning: `[Qux:Y]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:18:13
    |
-18 |        /// [Qux:Y]
+LL |        /// [Qux:Y]
    |             ^^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -58,7 +58,7 @@ warning: `[Qux:Y]` cannot be resolved, ignoring it...
 warning: `[BarA]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:24:10
    |
-24 | /// bar [BarA] bar
+LL | /// bar [BarA] bar
    |          ^^^^ cannot be resolved, ignoring
    |
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
@@ -66,11 +66,11 @@ warning: `[BarA]` cannot be resolved, ignoring it...
 warning: `[BarB]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:28:1
    |
-28 | / /**
-29 | |  * Foo
-30 | |  * bar [BarB] bar
-31 | |  * baz
-32 | |  */
+LL | / /**
+LL | |  * Foo
+LL | |  * bar [BarB] bar
+LL | |  * baz
+LL | |  */
    | |___^
    |
    = note: the link appears in this line:
@@ -82,13 +82,13 @@ warning: `[BarB]` cannot be resolved, ignoring it...
 warning: `[BarC]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:35:1
    |
-35 | / /** Foo
-36 | |
-37 | | bar [BarC] bar
-38 | | baz
+LL | / /** Foo
+LL | |
+LL | | bar [BarC] bar
+LL | | baz
 ...  |
-44 | |
-45 | | */
+LL | |
+LL | | */
    | |__^
    |
    = note: the link appears in this line:
@@ -100,7 +100,7 @@ warning: `[BarC]` cannot be resolved, ignoring it...
 warning: `[BarD]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:48:1
    |
-48 | #[doc = "Foo/nbar [BarD] bar/nbaz"]
+LL | #[doc = "Foo/nbar [BarD] bar/nbaz"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the link appears in this line:
@@ -112,10 +112,10 @@ warning: `[BarD]` cannot be resolved, ignoring it...
 warning: `[BarF]` cannot be resolved, ignoring it...
   --> $DIR/intra-links-warning.rs:53:9
    |
-53 |         #[doc = $f]
+LL |         #[doc = $f]
    |         ^^^^^^^^^^^
 ...
-57 | f!("Foo/nbar [BarF] bar/nbaz");
+LL | f!("Foo/nbar [BarF] bar/nbaz");
    | ------------------------------- in this macro invocation
    |
    = note: the link appears in this line:
diff --git a/src/test/rustdoc/edition-doctest.rs b/src/test/rustdoc/edition-doctest.rs
new file mode 100644
index 00000000000..322d461f854
--- /dev/null
+++ b/src/test/rustdoc/edition-doctest.rs
@@ -0,0 +1,54 @@
+// Copyright 2018 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.
+
+// compile-flags:--test
+
+/// ```rust,edition2018
+/// #![feature(try_blocks)]
+///
+/// use std::num::ParseIntError;
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert_eq!(result, Ok(6));
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "foo".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert!(result.is_err());
+/// ```
+
+
+/// ```rust,edition2015,compile_fail,E0574
+/// #![feature(try_blocks)]
+///
+/// use std::num::ParseIntError;
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert_eq!(result, Ok(6));
+///
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "foo".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// assert!(result.is_err());
+/// ```
+
+pub fn foo() {}
diff --git a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
index 22845775aed..aa54425efa3 100644
--- a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
+++ b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
@@ -2,16 +2,20 @@ error: expected `{`, found `and`
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:14:10
    |
 LL |     if a and b {
-   |     --   ^^^ help: use `&&` instead of `and` for the boolean operator
-   |     |
+   |     --   ^^^
+   |     |    |
+   |     |    expected `{`
+   |     |    help: use `&&` instead of `and` for the boolean operator
    |     this `if` statement has a condition, but no block
 
 error: expected `{`, found `or`
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:23:10
    |
 LL |     if a or b {
-   |     --   ^^ help: use `||` instead of `or` for the boolean operator
-   |     |
+   |     --   ^^
+   |     |    |
+   |     |    expected `{`
+   |     |    help: use `||` instead of `or` for the boolean operator
    |     this `if` statement has a condition, but no block
 
 error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and`
diff --git a/src/test/ui/issues/issue-38940.rs b/src/test/ui/issues/issue-38940.rs
new file mode 100644
index 00000000000..7f9b141e02e
--- /dev/null
+++ b/src/test/ui/issues/issue-38940.rs
@@ -0,0 +1,46 @@
+// issue-38940: error printed twice for deref recursion limit exceeded
+// Test that the recursion limit can be changed. In this case, we have
+// deeply nested types that will fail the `Send` check by overflow
+// when the recursion limit is set very low.
+#![allow(dead_code)]
+#![recursion_limit="10"]
+macro_rules! link {
+    ($outer:ident, $inner:ident) => {
+        struct $outer($inner);
+        impl $outer {
+            fn new() -> $outer {
+                $outer($inner::new())
+            }
+        }
+        impl std::ops::Deref for $outer {
+            type Target = $inner;
+            fn deref(&self) -> &$inner {
+                &self.0
+            }
+        }
+    }
+}
+struct Bottom;
+impl Bottom {
+    fn new() -> Bottom {
+        Bottom
+    }
+}
+link!(Top, A);
+link!(A, B);
+link!(B, C);
+link!(C, D);
+link!(D, E);
+link!(E, F);
+link!(F, G);
+link!(G, H);
+link!(H, I);
+link!(I, J);
+link!(J, K);
+link!(K, Bottom);
+fn main() {
+    let t = Top::new();
+    let x: &Bottom = &t;
+    //~^ ERROR mismatched types
+    //~| ERROR reached the recursion limit while auto-dereferencing I
+}
diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/issues/issue-38940.stderr
new file mode 100644
index 00000000000..2d3cfda9a5f
--- /dev/null
+++ b/src/test/ui/issues/issue-38940.stderr
@@ -0,0 +1,21 @@
+error[E0055]: reached the recursion limit while auto-dereferencing I
+  --> $DIR/issue-38940.rs:43:22
+   |
+LL |     let x: &Bottom = &t;
+   |                      ^^ deref recursion limit reached
+   |
+   = help: consider adding a `#![recursion_limit="20"]` attribute to your crate
+
+error[E0308]: mismatched types
+  --> $DIR/issue-38940.rs:43:22
+   |
+LL |     let x: &Bottom = &t;
+   |                      ^^ expected struct `Bottom`, found struct `Top`
+   |
+   = note: expected type `&Bottom`
+              found type `&Top`
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0055, E0308.
+For more information about an error, try `rustc --explain E0055`.
diff --git a/src/test/ui/parser/if-in-in.rs b/src/test/ui/parser/if-in-in.rs
new file mode 100644
index 00000000000..9bc9aaff298
--- /dev/null
+++ b/src/test/ui/parser/if-in-in.rs
@@ -0,0 +1,5 @@
+fn main() {
+    for i in in 1..2 {
+        println!("{}", i);
+    }
+}
diff --git a/src/test/ui/parser/if-in-in.stderr b/src/test/ui/parser/if-in-in.stderr
new file mode 100644
index 00000000000..9926fcc0858
--- /dev/null
+++ b/src/test/ui/parser/if-in-in.stderr
@@ -0,0 +1,13 @@
+error: expected iterable, found keyword `in`
+  --> $DIR/if-in-in.rs:2:14
+   |
+LL |     for i in in 1..2 {
+   |           ---^^
+   |           |
+   |           help: remove the duplicated `in`
+   |
+   = note: if you meant to use emplacement syntax, it is obsolete (for now, anyway)
+   = note: for more information on the status of emplacement syntax, see <https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rust-2018/dyn-keyword.fixed b/src/test/ui/rust-2018/dyn-keyword.fixed
new file mode 100644
index 00000000000..e9cda1af939
--- /dev/null
+++ b/src/test/ui/rust-2018/dyn-keyword.fixed
@@ -0,0 +1,10 @@
+// edition:2015
+// run-rustfix
+
+#![allow(unused_variables)]
+#![deny(keyword_idents)]
+
+fn main() {
+    let r#dyn = (); //~ ERROR dyn
+    //~^ WARN hard error in the 2018 edition
+}
diff --git a/src/test/ui/rust-2018/dyn-keyword.rs b/src/test/ui/rust-2018/dyn-keyword.rs
new file mode 100644
index 00000000000..bdd3a90cab9
--- /dev/null
+++ b/src/test/ui/rust-2018/dyn-keyword.rs
@@ -0,0 +1,10 @@
+// edition:2015
+// run-rustfix
+
+#![allow(unused_variables)]
+#![deny(keyword_idents)]
+
+fn main() {
+    let dyn = (); //~ ERROR dyn
+    //~^ WARN hard error in the 2018 edition
+}
diff --git a/src/test/ui/rust-2018/dyn-keyword.stderr b/src/test/ui/rust-2018/dyn-keyword.stderr
new file mode 100644
index 00000000000..5a3e00ab1d9
--- /dev/null
+++ b/src/test/ui/rust-2018/dyn-keyword.stderr
@@ -0,0 +1,16 @@
+error: `dyn` is a keyword in the 2018 edition
+  --> $DIR/dyn-keyword.rs:8:9
+   |
+LL |     let dyn = (); //~ ERROR dyn
+   |         ^^^ help: you can use a raw identifier to stay compatible: `r#dyn`
+   |
+note: lint level defined here
+  --> $DIR/dyn-keyword.rs:5:9
+   |
+LL | #![deny(keyword_idents)]
+   |         ^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rust-2018/dyn-trait-compatibility.rs b/src/test/ui/rust-2018/dyn-trait-compatibility.rs
new file mode 100644
index 00000000000..9548df5959b
--- /dev/null
+++ b/src/test/ui/rust-2018/dyn-trait-compatibility.rs
@@ -0,0 +1,8 @@
+// edition:2018
+
+type A0 = dyn;
+type A1 = dyn::dyn; //~ERROR expected identifier, found reserved keyword
+type A2 = dyn<dyn, dyn>; //~ERROR expected identifier, found `<`
+type A3 = dyn<<dyn as dyn>::dyn>;
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/dyn-trait-compatibility.stderr b/src/test/ui/rust-2018/dyn-trait-compatibility.stderr
new file mode 100644
index 00000000000..ea0483394b5
--- /dev/null
+++ b/src/test/ui/rust-2018/dyn-trait-compatibility.stderr
@@ -0,0 +1,14 @@
+error: expected identifier, found reserved keyword `dyn`
+  --> $DIR/dyn-trait-compatibility.rs:4:16
+   |
+LL | type A1 = dyn::dyn; //~ERROR expected identifier, found reserved keyword
+   |                ^^^ expected identifier, found reserved keyword
+
+error: expected identifier, found `<`
+  --> $DIR/dyn-trait-compatibility.rs:5:14
+   |
+LL | type A2 = dyn<dyn, dyn>; //~ERROR expected identifier, found `<`
+   |              ^ expected identifier
+
+error: aborting due to 2 previous errors
+