about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-13 03:22:20 +0000
committerbors <bors@rust-lang.org>2019-12-13 03:22:20 +0000
commitcf7e019b42cd523d91cb350ab49acbda1b11e571 (patch)
tree72dbc966b84267daf162c1bbfb59e0dc00bb4afb
parent3eeb8d4f2fbae0bb1c587d00b5abeaf938da47f4 (diff)
parentd25197c52d7a1b2e1f06061e0f1b274812c25a30 (diff)
downloadrust-cf7e019b42cd523d91cb350ab49acbda1b11e571.tar.gz
rust-cf7e019b42cd523d91cb350ab49acbda1b11e571.zip
Auto merge of #67271 - Centril:rollup-i71iqkv, r=Centril
Rollup of 6 pull requests

Successful merges:

 - #66341 (Match `VecDeque::extend` to `Vec::extend_desugared`)
 - #67243 (LinkedList: drop remaining items when drop panics)
 - #67247 (Don't suggest wrong snippet in closure)
 - #67250 (Remove the `DelimSpan` from `NamedMatch::MatchedSeq`.)
 - #67251 (Require `allow_internal_unstable` for stable min_const_fn using unsta…)
 - #67269 (parser: recover on `&'lifetime mut? $pat`.)

Failed merges:

r? @ghost
-rw-r--r--src/liballoc/collections/linked_list.rs16
-rw-r--r--src/liballoc/collections/vec_deque.rs17
-rw-r--r--src/liballoc/tests/linked_list.rs107
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs16
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs10
-rw-r--r--src/librustc_parse/parser/pat.rs22
-rw-r--r--src/libsyntax_expand/mbe/macro_parser.rs23
-rw-r--r--src/libsyntax_expand/mbe/macro_rules.rs4
-rw-r--r--src/libsyntax_expand/mbe/transcribe.rs4
-rw-r--r--src/test/ui/consts/const-mut-refs/const_mut_refs.rs1
-rw-r--r--src/test/ui/consts/control-flow/basics.rs1
-rw-r--r--src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs1
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr2
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.rs1
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr50
-rw-r--r--src/test/ui/consts/control-flow/short-circuit-let.rs1
-rw-r--r--src/test/ui/consts/control-flow/single_variant_match_ice.rs2
-rw-r--r--src/test/ui/parser/lifetime-in-pattern-recover.rs6
-rw-r--r--src/test/ui/parser/lifetime-in-pattern-recover.stderr23
-rw-r--r--src/test/ui/parser/lifetime-in-pattern.rs1
-rw-r--r--src/test/ui/parser/lifetime-in-pattern.stderr10
-rw-r--r--src/test/ui/self/self-vs-path-ambiguity.stderr2
-rw-r--r--src/test/ui/suggestions/option-content-move2.rs16
-rw-r--r--src/test/ui/suggestions/option-content-move2.stderr18
24 files changed, 287 insertions, 67 deletions
diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs
index a0c9263673d..6ee22834a46 100644
--- a/src/liballoc/collections/linked_list.rs
+++ b/src/liballoc/collections/linked_list.rs
@@ -808,7 +808,21 @@ impl<T> LinkedList<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
     fn drop(&mut self) {
-        while let Some(_) = self.pop_front_node() {}
+        struct DropGuard<'a, T>(&'a mut LinkedList<T>);
+
+        impl<'a, T> Drop for DropGuard<'a, T> {
+            fn drop(&mut self) {
+                // Continue the same loop we do below. This only runs when a destructor has
+                // panicked. If another one panics this will abort.
+                while let Some(_) = self.0.pop_front_node() {}
+            }
+        }
+
+        while let Some(node) = self.pop_front_node() {
+            let guard = DropGuard(self);
+            drop(node);
+            mem::forget(guard);
+        }
     }
 }
 
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 7795083e058..ebd3f010077 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -2809,7 +2809,22 @@ impl<'a, T> IntoIterator for &'a mut VecDeque<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A> Extend<A> for VecDeque<A> {
     fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
-        iter.into_iter().for_each(move |elt| self.push_back(elt));
+        // This function should be the moral equivalent of:
+        //
+        //      for item in iter.into_iter() {
+        //          self.push_back(item);
+        //      }
+        let mut iter = iter.into_iter();
+        while let Some(element) = iter.next() {
+            if self.len() == self.capacity() {
+                let (lower, _) = iter.size_hint();
+                self.reserve(lower.saturating_add(1));
+            }
+
+            let head = self.head;
+            self.head = self.wrap_add(self.head, 1);
+            unsafe { self.buffer_write(head, element); }
+        }
     }
 }
 
diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs
index daa49c48c6a..54a77d643cb 100644
--- a/src/liballoc/tests/linked_list.rs
+++ b/src/liballoc/tests/linked_list.rs
@@ -1,4 +1,5 @@
 use std::collections::LinkedList;
+use std::panic::catch_unwind;
 
 #[test]
 fn test_basic() {
@@ -529,3 +530,109 @@ fn drain_filter_complex() {
         assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
     }
 }
+
+
+#[test]
+fn test_drop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    drop(ring);
+
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+
+    drop(ring.pop_back());
+    drop(ring.pop_front());
+    assert_eq!(unsafe { DROPS }, 2);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.clear();
+    assert_eq!(unsafe { DROPS }, 4);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 938836db9ae..cc634101f0a 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -223,18 +223,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     fn report(&mut self, error: GroupedMoveError<'tcx>) {
         let (mut err, err_span) = {
-            let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
+            let (span, use_spans, original_path, kind,):
+            (
+                Span,
+                Option<UseSpans>,
+                &Place<'tcx>,
+                &IllegalMoveOriginKind<'_>,
+            ) =
                 match error {
                     GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
                     GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
-                        (span, original_path, kind)
+                        (span, None, original_path, kind)
                     }
                     GroupedMoveError::OtherIllegalMove {
                         use_spans,
                         ref original_path,
                         ref kind
                     } => {
-                        (use_spans.args_or_use(), original_path, kind)
+                        (use_spans.args_or_use(), Some(use_spans), original_path, kind)
                     },
                 };
             debug!("report: original_path={:?} span={:?}, kind={:?} \
@@ -250,6 +256,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             original_path,
                             target_place,
                             span,
+                            use_spans,
                         )
                     }
                     IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
@@ -296,6 +303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         move_place: &Place<'tcx>,
         deref_target_place: &Place<'tcx>,
         span: Span,
+        use_spans: Option<UseSpans>,
     ) -> DiagnosticBuilder<'a> {
         // Inspect the type of the content behind the
         // borrow to provide feedback about why this
@@ -416,7 +424,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
             let is_option = move_ty.starts_with("std::option::Option");
             let is_result = move_ty.starts_with("std::result::Result");
-            if is_option || is_result {
+            if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
                 err.span_suggestion(
                     span,
                     &format!("consider borrowing the `{}`'s content", if is_option {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index cf2e1306dc4..1c95155e7ff 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -80,7 +80,7 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> Mc
     for ty in ty.walk() {
         match ty.kind {
             ty::Ref(_, _, hir::Mutability::Mutable) => {
-                if !tcx.features().const_mut_refs {
+                if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
                     return Err((
                         span,
                         "mutable references in const fn are unstable".into(),
@@ -220,7 +220,7 @@ fn check_statement(
         }
 
         | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
-        if !tcx.features().const_if_match
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
         => {
             Err((span, "loops and conditional expressions are not stable in const fn".into()))
         }
@@ -272,7 +272,7 @@ fn check_place(
     while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
         match elem {
-            ProjectionElem::Downcast(..) if !tcx.features().const_if_match
+            ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match)
                 => return Err((span, "`match` or `if let` in `const fn` is unstable".into())),
             ProjectionElem::Downcast(_symbol, _variant_index) => {}
 
@@ -329,7 +329,7 @@ fn check_terminator(
 
         | TerminatorKind::FalseEdges { .. }
         | TerminatorKind::SwitchInt { .. }
-        if !tcx.features().const_if_match
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
         => Err((
             span,
             "loops and conditional expressions are not stable in const fn".into(),
@@ -341,7 +341,7 @@ fn check_terminator(
         }
 
         // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
-        TerminatorKind::Unreachable if tcx.features().const_if_match => Ok(()),
+        TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),
 
         | TerminatorKind::Abort | TerminatorKind::Unreachable => {
             Err((span, "const fn with unreachable code is not stable".into()))
diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 42ece96adb9..117b92dc9a5 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -459,16 +459,26 @@ impl<'a> Parser<'a> {
     /// Parse `&pat` / `&mut pat`.
     fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
         self.expect_and()?;
+        self.recover_lifetime_in_deref_pat();
         let mutbl = self.parse_mutability();
+        let subpat = self.parse_pat_with_range_pat(false, expected)?;
+        Ok(PatKind::Ref(subpat, mutbl))
+    }
 
+    fn recover_lifetime_in_deref_pat(&mut self) {
         if let token::Lifetime(name) = self.token.kind {
-            let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
-            err.span_label(self.token.span, "unexpected lifetime");
-            return Err(err);
-        }
+            self.bump(); // `'a`
 
-        let subpat = self.parse_pat_with_range_pat(false, expected)?;
-        Ok(PatKind::Ref(subpat, mutbl))
+            let span = self.prev_span;
+            self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
+                .span_suggestion(
+                    span,
+                    "remove the lifetime",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
     }
 
     /// Parse a tuple or parenthesis pattern.
diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs
index bf7960f9066..1e2f3f9d1e5 100644
--- a/src/libsyntax_expand/mbe/macro_parser.rs
+++ b/src/libsyntax_expand/mbe/macro_parser.rs
@@ -83,7 +83,7 @@ use syntax::print::pprust;
 use syntax::sess::ParseSess;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::token::{self, DocComment, Nonterminal, Token};
-use syntax::tokenstream::{DelimSpan, TokenStream};
+use syntax::tokenstream::TokenStream;
 
 use errors::{PResult, FatalError};
 use smallvec::{smallvec, SmallVec};
@@ -164,11 +164,6 @@ struct MatcherPos<'root, 'tt> {
     /// The position of the "dot" in this matcher
     idx: usize,
 
-    /// The first span of source that the beginning of this matcher corresponds to. In other
-    /// words, the token in the source whose span is `sp_open` is matched against the first token of
-    /// the matcher.
-    sp_open: Span,
-
     /// For each named metavar in the matcher, we keep track of token trees matched against the
     /// metavar by the black box parser. In particular, there may be more than one match per
     /// metavar if we are in a repetition (each repetition matches each of the variables).
@@ -307,8 +302,8 @@ fn create_matches(len: usize) -> Box<[Lrc<NamedMatchVec>]> {
 }
 
 /// Generates the top-level matcher position in which the "dot" is before the first token of the
-/// matcher `ms` and we are going to start matching at the span `open` in the source.
-fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherPos<'root, 'tt> {
+/// matcher `ms`.
+fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree]) -> MatcherPos<'root, 'tt> {
     let match_idx_hi = count_names(ms);
     let matches = create_matches(match_idx_hi);
     MatcherPos {
@@ -316,8 +311,6 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP
         top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
         // The "dot" is before the first token of the matcher
         idx: 0,
-        // We start matching at the span `open` in the source code
-        sp_open: open,
 
         // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
         // `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
@@ -355,7 +348,7 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP
 /// token tree it was derived from.
 #[derive(Debug, Clone)]
 crate enum NamedMatch {
-    MatchedSeq(Lrc<NamedMatchVec>, DelimSpan),
+    MatchedSeq(Lrc<NamedMatchVec>),
     MatchedNonterminal(Lrc<Nonterminal>),
 }
 
@@ -497,8 +490,7 @@ fn inner_parse_loop<'root, 'tt>(
                     // Add matches from this repetition to the `matches` of `up`
                     for idx in item.match_lo..item.match_hi {
                         let sub = item.matches[idx].clone();
-                        let span = DelimSpan::from_pair(item.sp_open, token.span);
-                        new_pos.push_match(idx, MatchedSeq(sub, span));
+                        new_pos.push_match(idx, MatchedSeq(sub));
                     }
 
                     // Move the "dot" past the repetition in `up`
@@ -552,7 +544,7 @@ fn inner_parse_loop<'root, 'tt>(
                         new_item.match_cur += seq.num_captures;
                         new_item.idx += 1;
                         for idx in item.match_cur..item.match_cur + seq.num_captures {
-                            new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![]), sp));
+                            new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![])));
                         }
                         cur_items.push(new_item);
                     }
@@ -568,7 +560,6 @@ fn inner_parse_loop<'root, 'tt>(
                         match_cur: item.match_cur,
                         match_hi: item.match_cur + seq.num_captures,
                         up: Some(item),
-                        sp_open: sp.open,
                         top_elts: Tt(TokenTree::Sequence(sp, seq)),
                     })));
                 }
@@ -663,7 +654,7 @@ pub(super) fn parse(
     //
     // This MatcherPos instance is allocated on the stack. All others -- and
     // there are frequently *no* others! -- are allocated on the heap.
-    let mut initial = initial_matcher_pos(ms, parser.token.span);
+    let mut initial = initial_matcher_pos(ms);
     let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
     let mut next_items = Vec::new();
 
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index e3c3655bcf8..2dd15872a9f 100644
--- a/src/libsyntax_expand/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -379,7 +379,7 @@ pub fn compile_declarative_macro(
 
     // Extract the arguments:
     let lhses = match argument_map[&lhs_nm] {
-        MatchedSeq(ref s, _) => s
+        MatchedSeq(ref s) => s
             .iter()
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
@@ -402,7 +402,7 @@ pub fn compile_declarative_macro(
     };
 
     let rhses = match argument_map[&rhs_nm] {
-        MatchedSeq(ref s, _) => s
+        MatchedSeq(ref s) => s
             .iter()
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs
index a1157667df1..0605f7ff36d 100644
--- a/src/libsyntax_expand/mbe/transcribe.rs
+++ b/src/libsyntax_expand/mbe/transcribe.rs
@@ -299,7 +299,7 @@ fn lookup_cur_matched<'a>(
         for &(idx, _) in repeats {
             match matched {
                 MatchedNonterminal(_) => break,
-                MatchedSeq(ref ads, _) => matched = ads.get(idx).unwrap(),
+                MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
             }
         }
 
@@ -382,7 +382,7 @@ fn lockstep_iter_size(
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
                     MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
-                    MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
+                    MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
                 },
                 _ => LockstepIterSize::Unconstrained,
             }
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 99006a20b1b..33abfec02a8 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,6 +1,7 @@
 // run-pass
 
 #![feature(const_mut_refs)]
+#![feature(const_fn)]
 
 struct Foo {
     x: usize
diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs
index 8bd1929956f..b9ff0409158 100644
--- a/src/test/ui/consts/control-flow/basics.rs
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -4,6 +4,7 @@
 
 #![feature(const_panic)]
 #![feature(const_if_match)]
+#![feature(const_fn)]
 
 const X: u32 = 4;
 const Y: u32 = 5;
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 6bbbdd972a2..7887fd12e57 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,6 +3,7 @@
 // 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 21e3f2af15a..95096723b3c 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:108:1
+  --> $DIR/feature-gate-const-if-match.rs:109: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 00576d50ac6..e4b65257531 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,6 +6,7 @@
 
 #![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 d3c6a51923f..e846ee4ab6a 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:10:16
+  --> $DIR/feature-gate-const-if-match.rs:11: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:16:16
+  --> $DIR/feature-gate-const-if-match.rs:17: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:22:16
+  --> $DIR/feature-gate-const-if-match.rs:23: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:29:13
+  --> $DIR/feature-gate-const-if-match.rs:30: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:31:13
+  --> $DIR/feature-gate-const-if-match.rs:32: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:33:5
+  --> $DIR/feature-gate-const-if-match.rs:34: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:38:13
+  --> $DIR/feature-gate-const-if-match.rs:39: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:40:13
+  --> $DIR/feature-gate-const-if-match.rs:41: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:42:5
+  --> $DIR/feature-gate-const-if-match.rs:43: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:47:5
+  --> $DIR/feature-gate-const-if-match.rs:48: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:51:5
+  --> $DIR/feature-gate-const-if-match.rs:52: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:59:5
+  --> $DIR/feature-gate-const-if-match.rs:60: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:90:17
+  --> $DIR/feature-gate-const-if-match.rs:91: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:92:17
+  --> $DIR/feature-gate-const-if-match.rs:93: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:94:9
+  --> $DIR/feature-gate-const-if-match.rs:95: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:110:17
+  --> $DIR/feature-gate-const-if-match.rs:111: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:112:17
+  --> $DIR/feature-gate-const-if-match.rs:113: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:114:9
+  --> $DIR/feature-gate-const-if-match.rs:115: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:67:21
+  --> $DIR/feature-gate-const-if-match.rs:68: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:70:25
+  --> $DIR/feature-gate-const-if-match.rs:71: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:73:24
+  --> $DIR/feature-gate-const-if-match.rs:74: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:78:21
+  --> $DIR/feature-gate-const-if-match.rs:79: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:81:25
+  --> $DIR/feature-gate-const-if-match.rs:82: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:84:24
+  --> $DIR/feature-gate-const-if-match.rs:85: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:114:21
+  --> $DIR/feature-gate-const-if-match.rs:115: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 8cee2a54f56..4b20a2124c3 100644
--- a/src/test/ui/consts/control-flow/short-circuit-let.rs
+++ b/src/test/ui/consts/control-flow/short-circuit-let.rs
@@ -4,6 +4,7 @@
 
 #![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 823605ff034..bb0fce66c4d 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)]
+#![feature(const_if_match, const_fn)]
 
 enum Foo {
     Prob,
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.rs b/src/test/ui/parser/lifetime-in-pattern-recover.rs
new file mode 100644
index 00000000000..7fb14b80076
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let &'a x = &0; //~ ERROR unexpected lifetime `'a` in pattern
+    let &'a mut y = &mut 0; //~ ERROR unexpected lifetime `'a` in pattern
+
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.stderr b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
new file mode 100644
index 00000000000..4bf7f57bfb5
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
@@ -0,0 +1,23 @@
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:2:10
+   |
+LL |     let &'a x = &0;
+   |          ^^ help: remove the lifetime
+
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:3:10
+   |
+LL |     let &'a mut y = &mut 0;
+   |          ^^ help: remove the lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/lifetime-in-pattern-recover.rs:5:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/lifetime-in-pattern.rs b/src/test/ui/parser/lifetime-in-pattern.rs
index afee685cd05..d3c638d0cd7 100644
--- a/src/test/ui/parser/lifetime-in-pattern.rs
+++ b/src/test/ui/parser/lifetime-in-pattern.rs
@@ -1,5 +1,6 @@
 fn test(&'a str) {
     //~^ ERROR unexpected lifetime `'a` in pattern
+    //~| ERROR expected one of `:`, `@`, or `|`, found `)`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr
index e525c7b6d68..71fd3cdf723 100644
--- a/src/test/ui/parser/lifetime-in-pattern.stderr
+++ b/src/test/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern.rs:1:10
    |
 LL | fn test(&'a str) {
-   |          ^^ unexpected lifetime
+   |          ^^ help: remove the lifetime
 
-error: aborting due to previous error
+error: expected one of `:`, `@`, or `|`, found `)`
+  --> $DIR/lifetime-in-pattern.rs:1:16
+   |
+LL | fn test(&'a str) {
+   |                ^ expected one of `:`, `@`, or `|`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr
index 5ce6a81bfcf..2beef50cdb5 100644
--- a/src/test/ui/self/self-vs-path-ambiguity.stderr
+++ b/src/test/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,7 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/self-vs-path-ambiguity.rs:9:11
    |
 LL |     fn i(&'a self::S: &S) {}
-   |           ^^ unexpected lifetime
+   |           ^^ help: remove the lifetime
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/option-content-move2.rs b/src/test/ui/suggestions/option-content-move2.rs
new file mode 100644
index 00000000000..88e8a5b7aee
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.rs
@@ -0,0 +1,16 @@
+struct NotCopyable;
+
+fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+
+fn parse() {
+    let mut var = None;
+    func(|| {
+        // Shouldn't suggest `move ||.as_ref()` here
+        move || {
+        //~^ ERROR: cannot move out of `var`
+            var = Some(NotCopyable);
+        }
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
new file mode 100644
index 00000000000..71f745374e5
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+  --> $DIR/option-content-move2.rs:9:9
+   |
+LL |     let mut var = None;
+   |         ------- captured outer variable
+...
+LL |         move || {
+   |         ^^^^^^^ move out of `var` occurs here
+LL |
+LL |             var = Some(NotCopyable);
+   |             ---
+   |             |
+   |             move occurs because `var` has type `std::option::Option<NotCopyable>`, which does not implement the `Copy` trait
+   |             move occurs due to use in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.