diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 6f1d69821f5..6c495666384 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -70,7 +70,6 @@
 #![feature(bound_cloned)]
 #![feature(cfg_target_has_atomic)]
 #![feature(concat_idents)]
-#![feature(const_fn)]
 #![feature(const_if_match)]
 #![feature(const_panic)]
 #![feature(const_fn_union)]
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index aa57c7788c6..c657ce33f60 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -1136,7 +1136,7 @@ impl<T: Deref, E> Result<T, E> {
     ///
     /// Leaves the original `Result` in-place, creating a new one containing a reference to the
     /// `Ok` type's `Deref::Target` type.
-    pub fn as_deref_ok(&self) -> Result<&T::Target, &E> {
+    pub fn as_deref(&self) -> Result<&T::Target, &E> {
         self.as_ref().map(|t| t.deref())
     }
 }
@@ -1152,24 +1152,13 @@ impl<T, E: Deref> Result<T, E> {
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
-impl<T: Deref, E: Deref> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E::Target>`.
-    ///
-    /// Leaves the original `Result` in-place, creating a new one containing a reference to both
-    /// the `Ok` and `Err` types' `Deref::Target` types.
-    pub fn as_deref(&self) -> Result<&T::Target, &E::Target> {
-        self.as_ref().map(|t| t.deref()).map_err(|e| e.deref())
-    }
-}
-
 #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
 impl<T: DerefMut, E> Result<T, E> {
     /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T::Target, &mut E>`.
     ///
     /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
     /// the `Ok` type's `Deref::Target` type.
-    pub fn as_deref_mut_ok(&mut self) -> Result<&mut T::Target, &mut E> {
+    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
         self.as_mut().map(|t| t.deref_mut())
     }
 }
@@ -1185,18 +1174,6 @@ impl<T, E: DerefMut> Result<T, E> {
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
-impl<T: DerefMut, E: DerefMut> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to
-    /// `Result<&mut T::Target, &mut E::Target>`.
-    ///
-    /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
-    /// both the `Ok` and `Err` types' `Deref::Target` types.
-    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E::Target> {
-        self.as_mut().map(|t| t.deref_mut()).map_err(|e| e.deref_mut())
-    }
-}
-
 impl<T, E> Result<Option<T>, E> {
     /// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
     ///
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 09b54857f7d..86cf6fc104c 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -31,7 +31,6 @@
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
 #![feature(int_error_matching)]
-#![feature(const_fn)]
 #![feature(array_value_iter)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_is_partitioned)]
diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs
index 254d4539eac..c835313aae7 100644
--- a/src/libcore/tests/result.rs
+++ b/src/libcore/tests/result.rs
@@ -236,32 +236,18 @@ fn test_try() {
 
 #[test]
 fn test_result_as_deref() {
-    // &Result<T: Deref, E>::Ok(T).as_deref_ok() ->
+    // &Result<T: Deref, E>::Ok(T).as_deref() ->
     //      Result<&T::Deref::Target, &E>::Ok(&*T)
     let ref_ok = &Result::Ok::<&i32, u8>(&42);
     let expected_result = Result::Ok::<&i32, &u8>(&42);
-    assert_eq!(ref_ok.as_deref_ok(), expected_result);
+    assert_eq!(ref_ok.as_deref(), expected_result);
 
     let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
     let expected_result = Result::Ok::<&str, &u32>("a result");
-    assert_eq!(ref_ok.as_deref_ok(), expected_result);
+    assert_eq!(ref_ok.as_deref(), expected_result);
 
     let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
     let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
-    assert_eq!(ref_ok.as_deref_ok(), expected_result);
-
-    // &Result<T: Deref, E: Deref>::Ok(T).as_deref() ->
-    //      Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T)
-    let ref_ok = &Result::Ok::<&i32, &u8>(&42);
-    let expected_result = Result::Ok::<&i32, &u8>(&42);
-    assert_eq!(ref_ok.as_deref(), expected_result);
-
-    let ref_ok = &Result::Ok::<String, &u32>(String::from("a result"));
-    let expected_result = Result::Ok::<&str, &u32>("a result");
-    assert_eq!(ref_ok.as_deref(), expected_result);
-
-    let ref_ok = &Result::Ok::<Vec<i32>, &u32>(vec![1, 2, 3, 4, 5]);
-    let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
     assert_eq!(ref_ok.as_deref(), expected_result);
 
     // &Result<T, E: Deref>::Err(T).as_deref_err() ->
@@ -281,19 +267,21 @@ fn test_result_as_deref() {
     // &Result<T: Deref, E: Deref>::Err(T).as_deref_err() ->
     //      Result<&T, &E::Deref::Target>::Err(&*E)
     let ref_err = &Result::Err::<&u8, &i32>(&41);
-    let expected_result = Result::Err::<&u8, &i32>(&41);
+    let expected_result = Result::Err::<&u8, &&i32>(&&41);
     assert_eq!(ref_err.as_deref(), expected_result);
 
-    let ref_err = &Result::Err::<&u32, String>(String::from("an error"));
-    let expected_result = Result::Err::<&u32, &str>("an error");
+    let s = String::from("an error");
+    let ref_err = &Result::Err::<&u32, String>(s.clone());
+    let expected_result = Result::Err::<&u32, &String>(&s);
     assert_eq!(ref_err.as_deref(), expected_result);
 
-    let ref_err = &Result::Err::<&u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
-    let expected_result = Result::Err::<&u32, &[i32]>([5, 4, 3, 2, 1].as_slice());
+    let v = vec![5, 4, 3, 2, 1];
+    let ref_err = &Result::Err::<&u32, Vec<i32>>(v.clone());
+    let expected_result = Result::Err::<&u32, &Vec<i32>>(&v);
     assert_eq!(ref_err.as_deref(), expected_result);
 
     // The following cases test calling `as_deref_*` with the wrong variant (i.e.
-    // `as_deref_ok()` with a `Result::Err()`, or `as_deref_err()` with a `Result::Ok()`.
+    // `as_deref()` with a `Result::Err()`, or `as_deref_err()` with a `Result::Ok()`.
     // While uncommon, these cases are supported to ensure that an `as_deref_*`
     // call can still be made even when one of the Result types does not implement
     // `Deref` (for example, std::io::Error).
@@ -312,57 +300,39 @@ fn test_result_as_deref() {
     let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]);
     assert_eq!(ref_ok.as_deref_err(), expected_result);
 
-    // &Result<T: Deref, E>::Err(E).as_deref_ok() ->
+    // &Result<T: Deref, E>::Err(E).as_deref() ->
     //      Result<&T::Deref::Target, &E>::Err(&E)
     let ref_err = &Result::Err::<&u8, i32>(41);
     let expected_result = Result::Err::<&u8, &i32>(&41);
-    assert_eq!(ref_err.as_deref_ok(), expected_result);
+    assert_eq!(ref_err.as_deref(), expected_result);
 
     let ref_err = &Result::Err::<&u32, &str>("an error");
     let expected_result = Result::Err::<&u32, &&str>(&"an error");
-    assert_eq!(ref_err.as_deref_ok(), expected_result);
+    assert_eq!(ref_err.as_deref(), expected_result);
 
     let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]);
     let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]);
-    assert_eq!(ref_err.as_deref_ok(), expected_result);
+    assert_eq!(ref_err.as_deref(), expected_result);
 }
 
 #[test]
 fn test_result_as_deref_mut() {
-    // &mut Result<T: Deref, E>::Ok(T).as_deref_mut_ok() ->
+    // &mut Result<T: Deref, E>::Ok(T).as_deref_mut() ->
     //      Result<&mut T::Deref::Target, &mut E>::Ok(&mut *T)
     let mut val = 42;
     let mut expected_val = 42;
     let mut_ok = &mut Result::Ok::<&mut i32, u8>(&mut val);
     let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
-    assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_ok.as_deref_mut(), expected_result);
 
     let mut expected_string = String::from("a result");
     let mut_ok = &mut Result::Ok::<String, u32>(expected_string.clone());
     let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
-    assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_ok.as_deref_mut(), expected_result);
 
     let mut expected_vec = vec![1, 2, 3, 4, 5];
     let mut_ok = &mut Result::Ok::<Vec<i32>, u32>(expected_vec.clone());
     let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
-    assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
-
-    // &mut Result<T: Deref, E: Deref>::Ok(T).as_deref_mut() ->
-    //      Result<&mut T::Deref::Target, &mut E::Deref::Target>::Ok(&mut *T)
-    let mut val = 42;
-    let mut expected_val = 42;
-    let mut_ok = &mut Result::Ok::<&mut i32, &mut u8>(&mut val);
-    let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
-    assert_eq!(mut_ok.as_deref_mut(), expected_result);
-
-    let mut expected_string = String::from("a result");
-    let mut_ok = &mut Result::Ok::<String, &mut u32>(expected_string.clone());
-    let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
-    assert_eq!(mut_ok.as_deref_mut(), expected_result);
-
-    let mut expected_vec = vec![1, 2, 3, 4, 5];
-    let mut_ok = &mut Result::Ok::<Vec<i32>, &mut u32>(expected_vec.clone());
-    let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
     assert_eq!(mut_ok.as_deref_mut(), expected_result);
 
     // &mut Result<T, E: Deref>::Err(T).as_deref_mut_err() ->
@@ -386,23 +356,22 @@ fn test_result_as_deref_mut() {
     // &mut Result<T: Deref, E: Deref>::Err(T).as_deref_mut_err() ->
     //      Result<&mut T, &mut E::Deref::Target>::Err(&mut *E)
     let mut val = 41;
-    let mut expected_val = 41;
-    let mut_err = &mut Result::Err::<&mut u8, &mut i32>(&mut val);
-    let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
+    let mut_err = &mut Result::Err::<&mut u8, i32>(val);
+    let expected_result = Result::Err::<&mut u8, &mut i32>(&mut val);
     assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let mut expected_string = String::from("an error");
     let mut_err = &mut Result::Err::<&mut u32, String>(expected_string.clone());
-    let expected_result = Result::Err::<&mut u32, &mut str>(expected_string.as_mut_str());
+    let expected_result = Result::Err::<&mut u32, &mut String>(&mut expected_string);
     assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let mut expected_vec = vec![5, 4, 3, 2, 1];
     let mut_err = &mut Result::Err::<&mut u32, Vec<i32>>(expected_vec.clone());
-    let expected_result = Result::Err::<&mut u32, &mut [i32]>(expected_vec.as_mut_slice());
+    let expected_result = Result::Err::<&mut u32, &mut Vec<i32>>(&mut expected_vec);
     assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     // The following cases test calling `as_deref_mut_*` with the wrong variant (i.e.
-    // `as_deref_mut_ok()` with a `Result::Err()`, or `as_deref_mut_err()` with a `Result::Ok()`.
+    // `as_deref_mut()` with a `Result::Err()`, or `as_deref_mut_err()` with a `Result::Ok()`.
     // While uncommon, these cases are supported to ensure that an `as_deref_mut_*`
     // call can still be made even when one of the Result types does not implement
     // `Deref` (for example, std::io::Error).
@@ -426,22 +395,22 @@ fn test_result_as_deref_mut() {
     let expected_result = Result::Ok::<&mut [i32; 5], &mut u32>(&mut expected_arr);
     assert_eq!(mut_ok.as_deref_mut_err(), expected_result);
 
-    // &mut Result<T: Deref, E>::Err(E).as_deref_mut_ok() ->
+    // &mut Result<T: Deref, E>::Err(E).as_deref_mut() ->
     //      Result<&mut T::Deref::Target, &mut E>::Err(&mut E)
     let mut expected_val = 41;
     let mut_err = &mut Result::Err::<&mut u8, i32>(expected_val.clone());
     let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
-    assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let string = String::from("an error");
     let expected_string = string.clone();
     let mut ref_str = expected_string.as_ref();
     let mut_err = &mut Result::Err::<&mut u32, &str>(string.as_str());
     let expected_result = Result::Err::<&mut u32, &mut &str>(&mut ref_str);
-    assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let mut expected_arr = [5, 4, 3, 2, 1];
     let mut_err = &mut Result::Err::<&mut u32, [i32; 5]>(expected_arr.clone());
     let expected_result = Result::Err::<&mut u32, &mut [i32; 5]>(&mut expected_arr);
-    assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_err.as_deref_mut(), expected_result);
 }
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 0b74a104da4..c51db695a5b 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -21,7 +21,6 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(allow_internal_unstable)]
-#![feature(const_fn)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
 #![feature(in_band_lifetimes)]
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index cf424ffe7b2..3c0160a0452 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -31,7 +31,6 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_fn)]
 #![feature(const_transmute)]
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index ee020c7e589..9a229e709a5 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -202,7 +202,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
         };
 
-        hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: e.span, attrs: e.attrs.clone() }
+        hir::Expr {
+            hir_id: self.lower_node_id(e.id),
+            kind,
+            span: e.span,
+            attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
+        }
     }
 
     fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index 1e396d6fe8e..e6f4535a38d 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -8,37 +8,25 @@ use rustc_span::Span;
 use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
 use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
 use syntax::attr;
-use syntax::sess::{feature_err, leveled_feature_err, GateStrength, ParseSess};
+use syntax::sess::{feature_err, feature_err_issue, ParseSess};
 use syntax::visit::{self, FnKind, Visitor};
 
 use log::debug;
 
 macro_rules! gate_feature_fn {
-    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
-        let (cx, has_feature, span, name, explain, level) =
-            (&*$cx, $has_feature, $span, $name, $explain, $level);
+    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
+        let (cx, has_feature, span, name, explain) = (&*$cx, $has_feature, $span, $name, $explain);
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
         if !has_feature && !span.allows_unstable($name) {
-            leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
-                .emit();
+            feature_err_issue(cx.parse_sess, name, span, GateIssue::Language, explain).emit();
         }
     }};
 }
 
-macro_rules! gate_feature {
+macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
-        gate_feature_fn!(
-            $cx,
-            |x: &Features| x.$feature,
-            $span,
-            sym::$feature,
-            $explain,
-            GateStrength::Hard
-        )
-    };
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
-        gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain, $level)
+        gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain)
     };
 }
 
@@ -51,21 +39,6 @@ struct PostExpansionVisitor<'a> {
     features: &'a Features,
 }
 
-macro_rules! gate_feature_post {
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
-        let (cx, span) = ($cx, $span);
-        if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx, $feature, span, $explain)
-        }
-    }};
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
-        let (cx, span) = ($cx, $span);
-        if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx, $feature, span, $explain, $level)
-        }
-    }};
-}
-
 impl<'a> PostExpansionVisitor<'a> {
     fn check_abi(&self, abi: ast::StrLit) {
         let ast::StrLit { symbol_unescaped, span, .. } = abi;
@@ -257,7 +230,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
         // Check feature gates for built-in attributes.
         if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
-            gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
+            gate_feature_fn!(self, has_feature, attr.span, name, descr);
         }
         // Check unstable flavors of the `#[doc]` attribute.
         if attr.check_name(sym::doc) {
@@ -265,7 +238,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                     $(if nested_meta.check_name(sym::$name) {
                         let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
-                        gate_feature!(self, $feature, attr.span, msg);
+                        gate_feature_post!(self, $feature, attr.span, msg);
                     })*
                 }}
 
@@ -666,7 +639,7 @@ pub fn check_crate(
     macro_rules! gate_all {
         ($gate:ident, $msg:literal) => {
             for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
-                gate_feature!(&visitor, $gate, *span, $msg);
+                gate_feature_post!(&visitor, $gate, *span, $msg);
             }
         };
     }
@@ -688,7 +661,7 @@ pub fn check_crate(
             // disabling these uses of early feature-gatings.
             if false {
                 for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
-                    gate_feature!(&visitor, $gate, *span, $msg);
+                    gate_feature_post!(&visitor, $gate, *span, $msg);
                 }
             }
         };
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index cb44a56d075..d3b524c1a1e 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -13,7 +13,7 @@
 //!   but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
 //!   int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
 
-use super::{LlvmCodegenBackend, ModuleLlvm};
+use super::ModuleLlvm;
 
 use crate::builder::Builder;
 use crate::common;
@@ -29,7 +29,6 @@ use rustc::middle::exported_symbols;
 use rustc::mir::mono::{Linkage, Visibility};
 use rustc::session::config::DebugInfo;
 use rustc::ty::TyCtxt;
-use rustc_codegen_ssa::back::write::submit_codegened_module_to_llvm;
 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
 use rustc_codegen_ssa::mono_item::MonoItemExt;
 use rustc_codegen_ssa::traits::*;
@@ -100,8 +99,7 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
 pub fn compile_codegen_unit(
     tcx: TyCtxt<'tcx>,
     cgu_name: Symbol,
-    tx_to_llvm_workers: &std::sync::mpsc::Sender<Box<dyn std::any::Any + Send>>,
-) {
+) -> (ModuleCodegen<ModuleLlvm>, u64) {
     let prof_timer = tcx.prof.generic_activity("codegen_module");
     let start_time = Instant::now();
 
@@ -115,8 +113,6 @@ pub fn compile_codegen_unit(
     // the time we needed for codegenning it.
     let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
 
-    submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tx_to_llvm_workers, module, cost);
-
     fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
         let cgu = tcx.codegen_unit(cgu_name);
         // Instantiate monomorphizations without filling out definitions yet...
@@ -164,6 +160,8 @@ pub fn compile_codegen_unit(
             kind: ModuleKind::Regular,
         }
     }
+
+    (module, cost)
 }
 
 pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 35c71a66756..a6168128c4d 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -19,6 +19,7 @@
 #![feature(link_args)]
 #![feature(static_nobundle)]
 #![feature(trusted_len)]
+#![recursion_limit = "256"]
 
 use back::write::{create_informational_target_machine, create_target_machine};
 use rustc_span::symbol::Symbol;
@@ -108,9 +109,8 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         &self,
         tcx: TyCtxt<'_>,
         cgu_name: Symbol,
-        tx: &std::sync::mpsc::Sender<Box<dyn Any + Send>>,
-    ) {
-        base::compile_codegen_unit(tcx, cgu_name, tx);
+    ) -> (ModuleCodegen<ModuleLlvm>, u64) {
+        base::compile_codegen_unit(tcx, cgu_name)
     }
     fn target_machine_factory(
         &self,
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index ab5d67e5783..efd56007120 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -14,8 +14,8 @@
 //!   int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
 
 use crate::back::write::{
-    start_async_codegen, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
-    OngoingCodegen,
+    start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm,
+    submit_pre_lto_module_to_llvm, OngoingCodegen,
 };
 use crate::common::{IntPredicate, RealPredicate, TypeKind};
 use crate::meth;
@@ -40,6 +40,7 @@ use rustc::ty::{self, Instance, Ty, TyCtxt};
 use rustc_codegen_utils::{check_for_rustc_errors_attr, symbol_names_test};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::print_time_passes_entry;
+use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_index::vec::Idx;
@@ -606,20 +607,83 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         codegen_units
     };
 
-    let mut total_codegen_time = Duration::new(0, 0);
+    let total_codegen_time = Lock::new(Duration::new(0, 0));
 
-    for cgu in codegen_units.into_iter() {
+    // The non-parallel compiler can only translate codegen units to LLVM IR
+    // on a single thread, leading to a staircase effect where the N LLVM
+    // threads have to wait on the single codegen threads to generate work
+    // for them. The parallel compiler does not have this restriction, so
+    // we can pre-load the LLVM queue in parallel before handing off
+    // coordination to the OnGoingCodegen scheduler.
+    //
+    // This likely is a temporary measure. Once we don't have to support the
+    // non-parallel compiler anymore, we can compile CGUs end-to-end in
+    // parallel and get rid of the complicated scheduling logic.
+    let pre_compile_cgus = |cgu_reuse: &[CguReuse]| {
+        if cfg!(parallel_compiler) {
+            tcx.sess.time("compile_first_CGU_batch", || {
+                // Try to find one CGU to compile per thread.
+                let cgus: Vec<_> = cgu_reuse
+                    .iter()
+                    .enumerate()
+                    .filter(|&(_, reuse)| reuse == &CguReuse::No)
+                    .take(tcx.sess.threads())
+                    .collect();
+
+                // Compile the found CGUs in parallel.
+                par_iter(cgus)
+                    .map(|(i, _)| {
+                        let start_time = Instant::now();
+                        let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
+                        let mut time = total_codegen_time.lock();
+                        *time += start_time.elapsed();
+                        (i, module)
+                    })
+                    .collect()
+            })
+        } else {
+            FxHashMap::default()
+        }
+    };
+
+    let mut cgu_reuse = Vec::new();
+    let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None;
+
+    for (i, cgu) in codegen_units.iter().enumerate() {
         ongoing_codegen.wait_for_signal_to_codegen_item();
         ongoing_codegen.check_for_errors(tcx.sess);
 
-        let cgu_reuse = determine_cgu_reuse(tcx, &cgu);
+        // Do some setup work in the first iteration
+        if pre_compiled_cgus.is_none() {
+            // Calculate the CGU reuse
+            cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
+                codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect()
+            });
+            // Pre compile some CGUs
+            pre_compiled_cgus = Some(pre_compile_cgus(&cgu_reuse));
+        }
+
+        let cgu_reuse = cgu_reuse[i];
         tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
 
         match cgu_reuse {
             CguReuse::No => {
-                let start_time = Instant::now();
-                backend.compile_codegen_unit(tcx, cgu.name(), &ongoing_codegen.coordinator_send);
-                total_codegen_time += start_time.elapsed();
+                let (module, cost) =
+                    if let Some(cgu) = pre_compiled_cgus.as_mut().unwrap().remove(&i) {
+                        cgu
+                    } else {
+                        let start_time = Instant::now();
+                        let module = backend.compile_codegen_unit(tcx, cgu.name());
+                        let mut time = total_codegen_time.lock();
+                        *time += start_time.elapsed();
+                        module
+                    };
+                submit_codegened_module_to_llvm(
+                    &backend,
+                    &ongoing_codegen.coordinator_send,
+                    module,
+                    cost,
+                );
                 false
             }
             CguReuse::PreLto => {
@@ -652,7 +716,11 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 
     // Since the main thread is sometimes blocked during codegen, we keep track
     // -Ztime-passes output manually.
-    print_time_passes_entry(tcx.sess.time_passes(), "codegen_to_LLVM_IR", total_codegen_time);
+    print_time_passes_entry(
+        tcx.sess.time_passes(),
+        "codegen_to_LLVM_IR",
+        total_codegen_time.into_inner(),
+    );
 
     ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
 
diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs
index e0d0a2f32f3..bc3a75250bf 100644
--- a/src/librustc_codegen_ssa/traits/backend.rs
+++ b/src/librustc_codegen_ssa/traits/backend.rs
@@ -1,5 +1,6 @@
 use super::write::WriteBackendMethods;
 use super::CodegenObject;
+use crate::ModuleCodegen;
 
 use rustc::middle::cstore::EncodedMetadata;
 use rustc::session::{config, Session};
@@ -10,7 +11,6 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_span::symbol::Symbol;
 use syntax::expand::allocator::AllocatorKind;
 
-use std::sync::mpsc;
 use std::sync::Arc;
 
 pub trait BackendTypes {
@@ -34,7 +34,7 @@ impl<'tcx, T> Backend<'tcx> for T where
 {
 }
 
-pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
+pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
     fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
     fn write_compressed_metadata<'tcx>(
         &self,
@@ -48,12 +48,13 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
         mods: &mut Self::Module,
         kind: AllocatorKind,
     );
+    /// This generates the codegen unit and returns it along with
+    /// a `u64` giving an estimate of the unit's processing cost.
     fn compile_codegen_unit(
         &self,
         tcx: TyCtxt<'_>,
         cgu_name: Symbol,
-        tx_to_llvm_workers: &mpsc::Sender<Box<dyn std::any::Any + Send>>,
-    );
+    ) -> (ModuleCodegen<Self::Module>, u64);
     // If find_features is true this won't access `sess.crate_types` by assuming
     // that `is_pie_binary` is false. When we discover LLVM target features
     // `sess.crate_types` is uninitialized so we cannot access it.
diff --git a/src/librustc_error_codes/error_codes/E0185.md b/src/librustc_error_codes/error_codes/E0185.md
index f0ad2af144a..944a93ed14e 100644
--- a/src/librustc_error_codes/error_codes/E0185.md
+++ b/src/librustc_error_codes/error_codes/E0185.md
@@ -2,7 +2,7 @@ An associated function for a trait was defined to be static, but an
 implementation of the trait declared the same function to be a method (i.e., to
 take a `self` parameter).
 
-Here's an example of this error:
+Erroneous code example:
 
 ```compile_fail,E0185
 trait Foo {
@@ -17,3 +17,19 @@ impl Foo for Bar {
     fn foo(&self) {}
 }
 ```
+
+When a type implements a trait's associated function, it has to use the same
+signature. So in this case, since `Foo::foo` does not take any argument and
+does not return anything, its implementation on `Bar` should be the same:
+
+```
+trait Foo {
+    fn foo();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo() {} // ok!
+}
+```
diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs
index 66494d0fa73..f54fa291bd6 100644
--- a/src/librustc_hir/lib.rs
+++ b/src/librustc_hir/lib.rs
@@ -3,7 +3,7 @@
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html
 
 #![feature(crate_visibility_modifier)]
-#![feature(const_fn)]
+#![feature(const_fn)] // For the unsizing cast on `&[]`
 #![feature(in_band_lifetimes)]
 #![feature(specialization)]
 #![recursion_limit = "256"]
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 36c6568029d..d2565bf9c63 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -13,7 +13,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
 #![feature(core_intrinsics)]
-#![feature(const_fn)]
 #![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(exhaustive_patterns)]
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 41fbfd22e50..511a5fbc617 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -194,7 +194,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_index::bit_set::GrowableBitSet;
-
+use smallvec::SmallVec;
 use std::iter;
 
 #[derive(PartialEq)]
@@ -227,12 +227,7 @@ impl<'tcx> InliningMap<'tcx> {
         }
     }
 
-    fn record_accesses<I>(&mut self, source: MonoItem<'tcx>, new_targets: I)
-    where
-        I: Iterator<Item = (MonoItem<'tcx>, bool)> + ExactSizeIterator,
-    {
-        assert!(!self.index.contains_key(&source));
-
+    fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) {
         let start_index = self.targets.len();
         let new_items_count = new_targets.len();
         let new_items_count_total = new_items_count + self.targets.len();
@@ -240,15 +235,15 @@ impl<'tcx> InliningMap<'tcx> {
         self.targets.reserve(new_items_count);
         self.inlines.ensure(new_items_count_total);
 
-        for (i, (target, inline)) in new_targets.enumerate() {
-            self.targets.push(target);
-            if inline {
+        for (i, (target, inline)) in new_targets.iter().enumerate() {
+            self.targets.push(*target);
+            if *inline {
                 self.inlines.insert(i + start_index);
             }
         }
 
         let end_index = self.targets.len();
-        self.index.insert(source, (start_index, end_index));
+        assert!(self.index.insert(source, (start_index, end_index)).is_none());
     }
 
     // Internally iterate over all items referenced by `source` which will be
@@ -403,10 +398,15 @@ fn record_accesses<'tcx>(
         mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
     };
 
-    let accesses =
-        callees.into_iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item)));
+    // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock.
+    // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
+    // instead to avoid creating this `SmallVec`.
+    let accesses: SmallVec<[_; 128]> = callees
+        .into_iter()
+        .map(|mono_item| (*mono_item, is_inlining_candidate(mono_item)))
+        .collect();
 
-    inlining_map.lock_mut().record_accesses(caller, accesses);
+    inlining_map.lock_mut().record_accesses(caller, &accesses);
 }
 
 fn check_recursion_limit<'tcx>(
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 8fa41cab190..0def51a6a33 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -104,6 +104,7 @@ use rustc::ty::print::characteristic_def_id_of_type;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, DefIdTree, InstanceDef, TyCtxt};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_span::symbol::Symbol;
@@ -796,6 +797,8 @@ where
     I: Iterator<Item = &'a MonoItem<'tcx>>,
     'tcx: 'a,
 {
+    let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct");
+
     let mut symbols: Vec<_> =
         mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect();
 
@@ -869,18 +872,23 @@ fn collect_and_partition_mono_items(
 
     tcx.sess.abort_if_errors();
 
-    assert_symbols_are_distinct(tcx, items.iter());
+    let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || {
+        sync::join(
+            || {
+                let strategy = if tcx.sess.opts.incremental.is_some() {
+                    PartitioningStrategy::PerModule
+                } else {
+                    PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
+                };
 
-    let strategy = if tcx.sess.opts.incremental.is_some() {
-        PartitioningStrategy::PerModule
-    } else {
-        PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
-    };
-
-    let codegen_units = partition(tcx, items.iter().cloned(), strategy, &inlining_map)
-        .into_iter()
-        .map(Arc::new)
-        .collect::<Vec<_>>();
+                partition(tcx, items.iter().cloned(), strategy, &inlining_map)
+                    .into_iter()
+                    .map(Arc::new)
+                    .collect::<Vec<_>>()
+            },
+            || assert_symbols_are_distinct(tcx, items.iter()),
+        )
+    });
 
     let mono_items: DefIdSet = items
         .iter()
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index fcdabb29cd0..c2c1625001d 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -281,8 +281,22 @@ fn check_place(
     Ok(())
 }
 
-/// Returns whether `allow_internal_unstable(..., <feature_gate>, ...)` is present.
+/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`.
 fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
+    // All features require that the corresponding gate be enabled,
+    // even if the function has `#[allow_internal_unstable(the_gate)]`.
+    if !tcx.features().enabled(feature_gate) {
+        return false;
+    }
+
+    // If this crate is not using stability attributes, or this function is not claiming to be a
+    // stable `const fn`, that is all that is required.
+    if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
+        return true;
+    }
+
+    // However, we cannot allow stable `const fn`s to use unstable features without an explicit
+    // opt-in via `allow_internal_unstable`.
     attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
         .map_or(false, |mut features| features.any(|name| name == feature_gate))
 }
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index b0c78ad7e4b..dd2b6ab9971 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -1966,7 +1966,7 @@ impl<'a> Parser<'a> {
         limits: RangeLimits,
     ) -> PResult<'a, ExprKind> {
         if end.is_none() && limits == RangeLimits::Closed {
-            self.error_inclusive_range_with_no_end(self.token.span);
+            self.error_inclusive_range_with_no_end(self.prev_span);
             Ok(ExprKind::Err)
         } else {
             Ok(ExprKind::Range(start, end, limits))
diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 50756ddec9f..0c2cfc20daf 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -661,14 +661,34 @@ impl<'a> Parser<'a> {
     pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) {
         use rustc_error_codes::E0586;
         struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
-            .help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
+            .span_suggestion_short(
+                span,
+                "use `..` instead",
+                "..".to_string(),
+                Applicability::MachineApplicable,
+            )
+            .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
             .emit();
     }
 
-    /// Parse a range-to pattern, e.g. `..X` and `..=X` where `X` remains to be parsed.
-    fn parse_pat_range_to(&mut self, re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
+    /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
+    ///
+    /// The form `...X` is prohibited to reduce confusion with the potential
+    /// expression syntax `...expr` for splatting in expressions.
+    fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
         let end = self.parse_pat_range_end()?;
         self.sess.gated_spans.gate(sym::half_open_range_patterns, re.span.to(self.prev_span));
+        if let RangeEnd::Included(ref mut syn @ RangeSyntax::DotDotDot) = &mut re.node {
+            *syn = RangeSyntax::DotDotEq;
+            self.struct_span_err(re.span, "range-to patterns with `...` are not allowed")
+                .span_suggestion_short(
+                    re.span,
+                    "use `..=` instead",
+                    "..=".to_string(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
         Ok(PatKind::Range(None, Some(end), re))
     }
 
diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs
index 946e77d3559..a98cf929095 100644
--- a/src/librustc_session/parse.rs
+++ b/src/librustc_session/parse.rs
@@ -62,16 +62,6 @@ impl GatedSpans {
     }
 }
 
-/// The strenght of a feature gate.
-/// Either it is a `Hard` error, or only a `Soft` warning.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum GateStrength {
-    /// A hard error. (Most feature gates should use this.)
-    Hard,
-    /// Only a warning. (Use this only as backwards-compatibility demands.)
-    Soft,
-}
-
 /// Construct a diagnostic for a language feature error due to the given `span`.
 /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
 pub fn feature_err<'a>(
@@ -94,26 +84,7 @@ pub fn feature_err_issue<'a>(
     issue: GateIssue,
     explain: &str,
 ) -> DiagnosticBuilder<'a> {
-    leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
-}
-
-/// Construct a diagnostic for a feature gate error / warning.
-///
-/// You should typically just use `feature_err` instead.
-pub fn leveled_feature_err<'a>(
-    sess: &'a ParseSess,
-    feature: Symbol,
-    span: impl Into<MultiSpan>,
-    issue: GateIssue,
-    explain: &str,
-    level: GateStrength,
-) -> DiagnosticBuilder<'a> {
-    let diag = &sess.span_diagnostic;
-
-    let mut err = match level {
-        GateStrength::Hard => diag.struct_span_err_with_code(span, explain, error_code!(E0658)),
-        GateStrength::Soft => diag.struct_span_warn(span, explain),
-    };
+    let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
 
     if let Some(n) = find_feature_issue(feature, issue) {
         err.note(&format!(
@@ -127,13 +98,6 @@ pub fn leveled_feature_err<'a>(
         err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
     }
 
-    // If we're on stable and only emitting a "soft" warning, add a note to
-    // clarify that the feature isn't "on" (rather than being on but
-    // warning-worthy).
-    if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
-        err.help("a nightly build of the compiler is required to enable this feature");
-    }
-
     err
 }
 
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index 8cca59df338..1dc7fc5aa3a 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -5,7 +5,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(const_fn)]
 #![feature(crate_visibility_modifier)]
 #![feature(nll)]
 #![feature(optin_builtin_traits)]
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index b15dae452ff..0fcbd4e0b58 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -12,7 +12,6 @@
 #![feature(test)]
 #![feature(ptr_offset_from)]
 #![feature(crate_visibility_modifier)]
-#![feature(const_fn)]
 #![feature(drain_filter)]
 #![feature(never_type)]
 #![feature(unicode_internals)]
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index a96fee0cf8f..0184a3214b5 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -7,7 +7,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
-#![feature(const_fn)]
+#![feature(const_fn)] // For the `transmute` in `P::new`
 #![feature(const_transmute)]
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
index 33abfec02a8..99006a20b1b 100644
--- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 
 struct Foo {
     x: usize
diff --git a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
index 7887fd12e57..6bbbdd972a2 100644
--- a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
+++ b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
@@ -3,7 +3,6 @@
 // check-pass
 
 #![feature(const_if_match)]
-#![feature(const_fn)]
 
 enum E {
     A,
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
index 95096723b3c..21e3f2af15a 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
@@ -1,5 +1,5 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate-const-if-match.rs:109:1
+  --> $DIR/feature-gate-const-if-match.rs:108:1
    |
 LL | / fn main() {
 LL | |     let _ = [0; {
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
index e4b65257531..00576d50ac6 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
@@ -6,7 +6,6 @@
 
 #![feature(rustc_attrs)]
 #![cfg_attr(if_match, feature(const_if_match))]
-#![feature(const_fn)]
 
 const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
     5
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
index e846ee4ab6a..d3c6a51923f 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:11:16
+  --> $DIR/feature-gate-const-if-match.rs:10:16
    |
 LL |   const _: i32 = if true {
    |  ________________^
@@ -13,7 +13,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:17:16
+  --> $DIR/feature-gate-const-if-match.rs:16:16
    |
 LL |   const _: i32 = if let Some(true) = Some(false) {
    |  ________________^
@@ -27,7 +27,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:23:16
+  --> $DIR/feature-gate-const-if-match.rs:22:16
    |
 LL |   const _: i32 = match 1 {
    |  ________________^
@@ -41,7 +41,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:30:13
+  --> $DIR/feature-gate-const-if-match.rs:29:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |     let x = if true { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:32:13
+  --> $DIR/feature-gate-const-if-match.rs:31:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL |     let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:34:5
+  --> $DIR/feature-gate-const-if-match.rs:33:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:39:13
+  --> $DIR/feature-gate-const-if-match.rs:38:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     let x = if true { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:41:13
+  --> $DIR/feature-gate-const-if-match.rs:40:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@ LL |     let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:43:5
+  --> $DIR/feature-gate-const-if-match.rs:42:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL |     if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:48:5
+  --> $DIR/feature-gate-const-if-match.rs:47:5
    |
 LL |     if true { 5 } else { 6 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |     if true { 5 } else { 6 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:52:5
+  --> $DIR/feature-gate-const-if-match.rs:51:5
    |
 LL | /     if let Some(true) = a {
 LL | |         0
@@ -117,7 +117,7 @@ LL | |     }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:60:5
+  --> $DIR/feature-gate-const-if-match.rs:59:5
    |
 LL | /     match i {
 LL | |         i if i > 10 => i,
@@ -130,7 +130,7 @@ LL | |     }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:91:17
+  --> $DIR/feature-gate-const-if-match.rs:90:17
    |
 LL |         let x = if y { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL |         let x = if y { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:93:17
+  --> $DIR/feature-gate-const-if-match.rs:92:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL |         let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:95:9
+  --> $DIR/feature-gate-const-if-match.rs:94:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:111:17
+  --> $DIR/feature-gate-const-if-match.rs:110:17
    |
 LL |         let x = if false { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@ LL |         let x = if false { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:113:17
+  --> $DIR/feature-gate-const-if-match.rs:112:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@ LL |         let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:115:9
+  --> $DIR/feature-gate-const-if-match.rs:114:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@ LL |         if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:68:21
+  --> $DIR/feature-gate-const-if-match.rs:67:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL |     const IF: i32 = if true { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:71:25
+  --> $DIR/feature-gate-const-if-match.rs:70:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +202,7 @@ LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:74:24
+  --> $DIR/feature-gate-const-if-match.rs:73:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:79:21
+  --> $DIR/feature-gate-const-if-match.rs:78:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL |     const IF: i32 = if true { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:82:25
+  --> $DIR/feature-gate-const-if-match.rs:81:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:85:24
+  --> $DIR/feature-gate-const-if-match.rs:84:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -238,7 +238,7 @@ LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/feature-gate-const-if-match.rs:115:21
+  --> $DIR/feature-gate-const-if-match.rs:114:21
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |                     ^
diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs
index 4b20a2124c3..8cee2a54f56 100644
--- a/src/test/ui/consts/control-flow/short-circuit-let.rs
+++ b/src/test/ui/consts/control-flow/short-circuit-let.rs
@@ -4,7 +4,6 @@
 
 #![feature(const_if_match)]
 #![feature(const_panic)]
-#![feature(const_fn)]
 
 const X: i32 = {
     let mut x = 0;
diff --git a/src/test/ui/consts/control-flow/single_variant_match_ice.rs b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
index bb0fce66c4d..823605ff034 100644
--- a/src/test/ui/consts/control-flow/single_variant_match_ice.rs
+++ b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_if_match, const_fn)]
+#![feature(const_if_match)]
 
 enum Foo {
     Prob,
diff --git a/src/test/ui/error-codes/E0586.stderr b/src/test/ui/error-codes/E0586.stderr
index d1e7e3f4744..0bbf9a60803 100644
--- a/src/test/ui/error-codes/E0586.stderr
+++ b/src/test/ui/error-codes/E0586.stderr
@@ -1,10 +1,10 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/E0586.rs:3:22
+  --> $DIR/E0586.rs:3:19
    |
 LL |     let x = &tmp[1..=];
-   |                      ^
+   |                   ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs b/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs
index 4cb8230a7b6..1733012b9c5 100644
--- a/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs
+++ b/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs
@@ -8,6 +8,7 @@ fn foo() {
     //~^ ERROR half-open range patterns are unstable
     if let ...5 = 0 {}
     //~^ ERROR half-open range patterns are unstable
+    //~| ERROR range-to patterns with `...` are not allowed
     if let ..5 = 0 {}
     //~^ ERROR half-open range patterns are unstable
     if let 5.. = 0 {}
diff --git a/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr b/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr
index 68ba654de76..99db339cf74 100644
--- a/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr
+++ b/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr
@@ -1,18 +1,24 @@
-error[E0586]: inclusive range with no end
-  --> $DIR/feature-gate-half-open-range-patterns.rs:15:13
+error: range-to patterns with `...` are not allowed
+  --> $DIR/feature-gate-half-open-range-patterns.rs:9:12
    |
-LL |     if let 5..= = 0 {}
-   |             ^^^
-   |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+LL |     if let ...5 = 0 {}
+   |            ^^^ help: use `..=` instead
 
 error[E0586]: inclusive range with no end
-  --> $DIR/feature-gate-half-open-range-patterns.rs:18:13
+  --> $DIR/feature-gate-half-open-range-patterns.rs:16:13
+   |
+LL |     if let 5..= = 0 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/feature-gate-half-open-range-patterns.rs:19:13
    |
 LL |     if let 5... = 0 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0658]: half-open range patterns are unstable
   --> $DIR/feature-gate-half-open-range-patterns.rs:7:12
@@ -33,7 +39,7 @@ LL |     if let ...5 = 0 {}
    = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
 
 error[E0658]: half-open range patterns are unstable
-  --> $DIR/feature-gate-half-open-range-patterns.rs:11:12
+  --> $DIR/feature-gate-half-open-range-patterns.rs:12:12
    |
 LL |     if let ..5 = 0 {}
    |            ^^^
@@ -42,7 +48,7 @@ LL |     if let ..5 = 0 {}
    = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
 
 error[E0658]: half-open range patterns are unstable
-  --> $DIR/feature-gate-half-open-range-patterns.rs:13:12
+  --> $DIR/feature-gate-half-open-range-patterns.rs:14:12
    |
 LL |     if let 5.. = 0 {}
    |            ^^^
@@ -51,7 +57,7 @@ LL |     if let 5.. = 0 {}
    = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
 
 error[E0658]: half-open range patterns are unstable
-  --> $DIR/feature-gate-half-open-range-patterns.rs:15:12
+  --> $DIR/feature-gate-half-open-range-patterns.rs:16:12
    |
 LL |     if let 5..= = 0 {}
    |            ^^^^
@@ -60,7 +66,7 @@ LL |     if let 5..= = 0 {}
    = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
 
 error[E0658]: half-open range patterns are unstable
-  --> $DIR/feature-gate-half-open-range-patterns.rs:18:12
+  --> $DIR/feature-gate-half-open-range-patterns.rs:19:12
    |
 LL |     if let 5... = 0 {}
    |            ^^^^
@@ -68,7 +74,7 @@ LL |     if let 5... = 0 {}
    = note: for more information, see https://github.com/rust-lang/rust/issues/67264
    = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0586, E0658.
 For more information about an error, try `rustc --explain E0586`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
new file mode 100644
index 00000000000..daed775cf7c
--- /dev/null
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
@@ -0,0 +1,32 @@
+// Test that `...X` range-to patterns are syntactically invalid.
+//
+// See https://github.com/rust-lang/rust/pull/67258#issuecomment-565656155
+// for the reason why. To summarize, we might want to introduce `...expr` as
+// an expression form for splatting (or "untupling") in an expression context.
+// While there is no syntactic ambiguity with `...X` in a pattern context,
+// there's a potential confusion factor here, and we would prefer to keep patterns
+// and expressions in-sync. As such, we do not allow `...X` in patterns either.
+
+#![feature(half_open_range_patterns)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match scrutinee {
+        ...X => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...0 => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...'a' => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...0.0f32 => {} //~ ERROR range-to patterns with `...` are not allowed
+    }
+}
+
+fn syntax2() {
+    macro_rules! mac {
+        ($e:expr) => {
+            let ...$e; //~ ERROR range-to patterns with `...` are not allowed
+        }
+    }
+
+    mac!(0);
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
new file mode 100644
index 00000000000..ba2e7ea8b53
--- /dev/null
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
@@ -0,0 +1,35 @@
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:17:9
+   |
+LL |         ...X => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:18:9
+   |
+LL |         ...0 => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:19:9
+   |
+LL |         ...'a' => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:20:9
+   |
+LL |         ...0.0f32 => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:27:17
+   |
+LL |             let ...$e;
+   |                 ^^^ help: use `..=` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
index 03166e36755..9ace0c357b2 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
@@ -13,3 +13,14 @@ fn foo() {
     if let X... = 1 {} //~ ERROR inclusive range with no end
     if let X..= = 1 {} //~ ERROR inclusive range with no end
 }
+
+fn bar() {
+    macro_rules! mac {
+        ($e:expr) => {
+            let $e...; //~ ERROR inclusive range with no end
+            let $e..=; //~ ERROR inclusive range with no end
+        }
+    }
+
+    mac!(0);
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
index 2b4d95f6842..2bdb8ea5766 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
@@ -2,34 +2,56 @@ error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:10:13
    |
 LL |     if let 0... = 1 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:11:13
    |
 LL |     if let 0..= = 1 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:13:13
    |
 LL |     if let X... = 1 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:14:13
    |
 LL |     if let X..= = 1 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: aborting due to 4 previous errors
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:19
+   |
+LL |             let $e...;
+   |                   ^^^ help: use `..` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:21:19
+   |
+LL |             let $e..=;
+   |                   ^^^ help: use `..` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0586`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
index e9a5361e63d..f054bbea4e3 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
@@ -20,5 +20,7 @@ fn syntax() {
         &..=0 | _ => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
         &...0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~| ERROR range-to patterns with `...` are not allowed
     }
 }
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
index 5d3aded0222..a5f7c390627 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
@@ -8,9 +8,9 @@ error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:10:11
    |
 LL |         &0..= | _ => {}
-   |           ^^^
+   |           ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:10:10
@@ -22,9 +22,9 @@ error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:13:11
    |
 LL |         &0... | _ => {}
-   |           ^^^
+   |           ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:18:10
@@ -38,6 +38,18 @@ error: the range pattern here has ambiguous interpretation
 LL |         &..=0 | _ => {}
    |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
 
-error: aborting due to 6 previous errors
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:22:10
+   |
+LL |         &...0 | _ => {}
+   |          ^^^ help: use `..=` instead
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:22:10
+   |
+LL |         &...0 | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0586`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
index a663acd2d19..8bb98d3b5c5 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
@@ -11,22 +11,20 @@ fn main() {}
 fn syntax() {
     match scrutinee {
         X.. | 0.. | 'a'.. | 0.0f32.. => {}
-        ..=X | ...X | ..X => {}
-        ..=0 | ...0 | ..0 => {}
-        ..='a' | ...'a' | ..'a' => {}
-        ..=0.0f32 | ...0.0f32 | ..0.0f32 => {}
+        ..=X | ..X => {}
+        ..=0 | ..0 => {}
+        ..='a' | ..'a' => {}
+        ..=0.0f32 | ..0.0f32 => {}
     }
+}
 
+fn syntax2() {
     macro_rules! mac {
         ($e:expr) => {
-            let ..$e;
-            let ...$e;
-            let ..=$e;
-            let $e..;
-            let $e...;
-            let $e..=;
+            match 0u8 { ..$e => {}, _ => {} }
+            match 0u8 { ..=$e => {}, _ => {} }
+            match 0u8 { $e.. => {}, _ => {} }
         }
     }
-
-    mac!(0);
+    mac!(42u8);
 }
diff --git a/src/test/ui/impossible_range.rs b/src/test/ui/impossible_range.rs
index 6345af00111..21e5c03eb16 100644
--- a/src/test/ui/impossible_range.rs
+++ b/src/test/ui/impossible_range.rs
@@ -1,4 +1,4 @@
-// Make sure that invalid ranges generate an error during HIR lowering, not an ICE
+// Make sure that invalid ranges generate an error during parsing, not an ICE
 
 pub fn main() {
     ..;
@@ -6,12 +6,12 @@ pub fn main() {
     ..1;
     0..1;
     ..=; //~ERROR inclusive range with no end
-         //~^HELP bounded at the end
+         //~^HELP use `..` instead
 }
 
 fn _foo1() {
     ..=1;
     0..=1;
     0..=; //~ERROR inclusive range with no end
-          //~^HELP bounded at the end
+          //~^HELP use `..` instead
 }
diff --git a/src/test/ui/impossible_range.stderr b/src/test/ui/impossible_range.stderr
index 091fe37c7a1..ea2ab0f299d 100644
--- a/src/test/ui/impossible_range.stderr
+++ b/src/test/ui/impossible_range.stderr
@@ -1,18 +1,18 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/impossible_range.rs:8:8
+  --> $DIR/impossible_range.rs:8:5
    |
 LL |     ..=;
-   |        ^
+   |     ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/impossible_range.rs:15:9
+  --> $DIR/impossible_range.rs:15:6
    |
 LL |     0..=;
-   |         ^
+   |      ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/internal/internal-unstable-const.rs b/src/test/ui/internal/internal-unstable-const.rs
new file mode 100644
index 00000000000..ce306c84517
--- /dev/null
+++ b/src/test/ui/internal/internal-unstable-const.rs
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![feature(const_if_match)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+const fn foo() -> i32 {
+    if true { 4 } else { 5 } //~ loops and conditional expressions are not stable in const fn
+}
+
+fn main() {}
diff --git a/src/test/ui/internal/internal-unstable-const.stderr b/src/test/ui/internal/internal-unstable-const.stderr
new file mode 100644
index 00000000000..58bbe798b00
--- /dev/null
+++ b/src/test/ui/internal/internal-unstable-const.stderr
@@ -0,0 +1,12 @@
+error[E0723]: loops and conditional expressions are not stable in const fn
+  --> $DIR/internal-unstable-const.rs:7:5
+   |
+LL |     if true { 4 } else { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr
index 48a662e98b5..1d98361c461 100644
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr
+++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `as_deref_err` found for enum `std::result::Result
   --> $DIR/result-as_deref_err.rs:4:28
    |
 LL |     let _result = &Err(41).as_deref_err();
-   |                            ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_ok`
+   |                            ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut`
    |
    = note: the method `as_deref_err` exists but the following trait bounds were not satisfied:
            `{integer} : std::ops::Deref`
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr
index 8a5c2f40060..950a050ea9f 100644
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr
+++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `as_deref_mut_err` found for enum `std::result::Re
   --> $DIR/result-as_deref_mut_err.rs:4:32
    |
 LL |     let _result = &mut Err(41).as_deref_mut_err();
-   |                                ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut_ok`
+   |                                ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut`
    |
    = note: the method `as_deref_mut_err` exists but the following trait bounds were not satisfied:
            `{integer} : std::ops::DerefMut`
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.rs
deleted file mode 100644
index 54b695a0865..00000000000
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(inner_deref)]
-
-fn main() {
-    let _result = &mut Ok(42).as_deref_mut_ok();
-//~^ ERROR no method named `as_deref_mut_ok` found
-}
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.stderr
deleted file mode 100644
index af8d657999c..00000000000
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0599]: no method named `as_deref_mut_ok` found for enum `std::result::Result<{integer}, _>` in the current scope
-  --> $DIR/result-as_deref_mut_ok.rs:4:31
-   |
-LL |     let _result = &mut Ok(42).as_deref_mut_ok();
-   |                               ^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut_err`
-   |
-   = note: the method `as_deref_mut_ok` exists but the following trait bounds were not satisfied:
-           `{integer} : std::ops::DerefMut`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.rs
deleted file mode 100644
index ebb0500e819..00000000000
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(inner_deref)]
-
-fn main() {
-    let _result = &Ok(42).as_deref_ok();
-//~^ ERROR no method named `as_deref_ok` found
-}
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.stderr
deleted file mode 100644
index 145e610d52c..00000000000
--- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0599]: no method named `as_deref_ok` found for enum `std::result::Result<{integer}, _>` in the current scope
-  --> $DIR/result-as_deref_ok.rs:4:27
-   |
-LL |     let _result = &Ok(42).as_deref_ok();
-   |                           ^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err`
-   |
-   = note: the method `as_deref_ok` exists but the following trait bounds were not satisfied:
-           `{integer} : std::ops::Deref`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/macros/issue-68058.rs b/src/test/ui/macros/issue-68058.rs
new file mode 100644
index 00000000000..24da2620c2e
--- /dev/null
+++ b/src/test/ui/macros/issue-68058.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+macro_rules! foo {
+    ($doc: expr) => {
+        fn f() {
+            #[doc = $doc]
+            ()
+        }
+    };
+}
+
+foo!("doc");
+
+fn main() {}
diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
index 654b49ab620..4775b9b7bc0 100644
--- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
+++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
@@ -342,9 +342,9 @@ error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:94:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-   |                                   ^^^
+   |                                   ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:94:38
@@ -356,9 +356,9 @@ error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:97:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-   |                                   ^^^
+   |                                   ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:97:38
@@ -376,9 +376,9 @@ error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:102:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-   |                                   ^^^
+   |                                   ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:102:38
diff --git a/src/test/ui/parser/range_inclusive.rs b/src/test/ui/parser/range_inclusive.rs
index bc61c5b49ea..7c3b906b47f 100644
--- a/src/test/ui/parser/range_inclusive.rs
+++ b/src/test/ui/parser/range_inclusive.rs
@@ -2,5 +2,5 @@
 
 pub fn main() {
     for _ in 1..= {} //~ERROR inclusive range with no end
-                     //~^HELP bounded at the end
+                     //~^HELP use `..` instead
 }
diff --git a/src/test/ui/parser/range_inclusive.stderr b/src/test/ui/parser/range_inclusive.stderr
index 12b7edae79f..1dd47994596 100644
--- a/src/test/ui/parser/range_inclusive.stderr
+++ b/src/test/ui/parser/range_inclusive.stderr
@@ -1,10 +1,10 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/range_inclusive.rs:4:19
+  --> $DIR/range_inclusive.rs:4:15
    |
 LL |     for _ in 1..= {}
-   |                   ^
+   |               ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/recover-range-pats.rs b/src/test/ui/parser/recover-range-pats.rs
index a5aae2861b2..e07ea6221d7 100644
--- a/src/test/ui/parser/recover-range-pats.rs
+++ b/src/test/ui/parser/recover-range-pats.rs
@@ -107,15 +107,15 @@ fn inclusive_to() {
 
 fn inclusive2_to() {
     if let ...3 = 0 {}
-    //~^ ERROR `...` range patterns are deprecated
+    //~^ ERROR range-to patterns with `...` are not allowed
     if let ...Y = 0 {}
-    //~^ ERROR `...` range patterns are deprecated
+    //~^ ERROR range-to patterns with `...` are not allowed
     if let ...true = 0 {}
-    //~^ ERROR `...` range patterns are deprecated
+    //~^ ERROR range-to patterns with `...` are not allowed
     //~| ERROR only char and numeric types
     if let ....3 = 0 {}
     //~^ ERROR float literals must have an integer part
-    //~| ERROR `...` range patterns are deprecated
+    //~| ERROR range-to patterns with `...` are not allowed
     //~| ERROR mismatched types
 }
 
@@ -135,7 +135,7 @@ fn with_macro_expr_var() {
         ($e:expr) => {
             let ..$e;
             let ...$e;
-            //~^ ERROR `...` range patterns are deprecated
+            //~^ ERROR range-to patterns with `...` are not allowed
             let ..=$e;
             let $e..;
             let $e...; //~ ERROR inclusive range with no end
diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr
index d3d3169022a..f43f9bf3012 100644
--- a/src/test/ui/parser/recover-range-pats.stderr
+++ b/src/test/ui/parser/recover-range-pats.stderr
@@ -44,25 +44,25 @@ error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:69:13
    |
 LL |     if let 0..= = 0 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:70:13
    |
 LL |     if let X..= = 0 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:71:16
    |
 LL |     if let true..= = 0 {}
-   |                ^^^
+   |                ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:73:12
@@ -74,33 +74,33 @@ error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:73:14
    |
 LL |     if let .0..= = 0 {}
-   |              ^^^
+   |              ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:79:13
    |
 LL |     if let 0... = 0 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:80:13
    |
 LL |     if let X... = 0 {}
-   |             ^^^
+   |             ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:81:16
    |
 LL |     if let true... = 0 {}
-   |                ^^^
+   |                ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:83:12
@@ -112,9 +112,9 @@ error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:83:14
    |
 LL |     if let .0... = 0 {}
-   |              ^^^
+   |              ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:93:15
@@ -128,33 +128,66 @@ error: float literals must have an integer part
 LL |     if let ..=.0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:109:12
+   |
+LL |     if let ...3 = 0 {}
+   |            ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:111:12
+   |
+LL |     if let ...Y = 0 {}
+   |            ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:113:12
+   |
+LL |     if let ...true = 0 {}
+   |            ^^^ help: use `..=` instead
+
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:116:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ help: must have an integer part: `0.3`
 
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:116:12
+   |
+LL |     if let ....3 = 0 {}
+   |            ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:137:17
+   |
+LL |             let ...$e;
+   |                 ^^^ help: use `..=` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:141:19
    |
 LL |             let $e...;
-   |                   ^^^
+   |                   ^^^ help: use `..` instead
 ...
 LL |     mac!(0);
    |     -------- in this macro invocation
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:142:19
    |
 LL |             let $e..=;
-   |                   ^^^
+   |                   ^^^ help: use `..` instead
 ...
 LL |     mac!(0);
    |     -------- in this macro invocation
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: `...` range patterns are deprecated
   --> $DIR/recover-range-pats.rs:42:13
@@ -210,30 +243,6 @@ error: `...` range patterns are deprecated
 LL |     if let X... .0 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
 
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:109:12
-   |
-LL |     if let ...3 = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:111:12
-   |
-LL |     if let ...Y = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:113:12
-   |
-LL |     if let ...true = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:116:12
-   |
-LL |     if let ....3 = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
 error: `...` range patterns are deprecated
   --> $DIR/recover-range-pats.rs:126:20
    |
@@ -243,15 +252,6 @@ LL |             let $e1...$e2;
 LL |     mac2!(0, 1);
    |     ------------ in this macro invocation
 
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:137:17
-   |
-LL |             let ...$e;
-   |                 ^^^ help: use `..=` for an inclusive range
-...
-LL |     mac!(0);
-   |     -------- in this macro invocation
-
 error[E0029]: only char and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:20:12
    |