From 164d1a205d21e0bc54b60cb4e9badf27b3883ffd Mon Sep 17 00:00:00 2001 From: Charles Gleason Date: Tue, 12 Nov 2019 13:01:10 -0500 Subject: [PATCH 1/6] Match VecDeque::extend to Vec::extend --- src/liballoc/collections/vec_deque.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) 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 @@ fn into_iter(self) -> IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for VecDeque { fn extend>(&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); } + } } } From 5e32da184933e4398a99a3be13d21db857f059b5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 12 Dec 2019 00:14:09 +0100 Subject: [PATCH 2/6] LinkedList: drop remaining items when drop panics --- src/liballoc/collections/linked_list.rs | 16 +++- src/liballoc/tests/linked_list.rs | 107 ++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) 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 @@ pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F> #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T> Drop for LinkedList { fn drop(&mut self) { - while let Some(_) = self.pop_front_node() {} + struct DropGuard<'a, T>(&'a mut LinkedList); + + 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/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![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); +} From fa199c5f27cf09fa02ff7632a713ea613f731944 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 11 Dec 2019 23:04:29 +0900 Subject: [PATCH 3/6] Don't suggest wrong snippet in closure --- .../borrow_check/diagnostics/move_errors.rs | 16 ++++++++++++---- .../ui/suggestions/option-content-move2.rs | 16 ++++++++++++++++ .../ui/suggestions/option-content-move2.stderr | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/suggestions/option-content-move2.rs create mode 100644 src/test/ui/suggestions/option-content-move2.stderr 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 @@ fn append_binding_error( 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, + &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 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) { original_path, target_place, span, + use_spans, ) } IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { @@ -296,6 +303,7 @@ fn report_cannot_move_from_borrowed_content( move_place: &Place<'tcx>, deref_target_place: &Place<'tcx>, span: Span, + use_spans: Option, ) -> DiagnosticBuilder<'a> { // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -416,7 +424,7 @@ fn report_cannot_move_from_borrowed_content( 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/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 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`, 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`. From ffd214299ebfce5b2d4719c3ec762c2ce1574515 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 12 Dec 2019 15:48:30 +1100 Subject: [PATCH 4/6] Remove the `DelimSpan` from `NamedMatch::MatchedSeq`. Because it's unused. This then allows the removal of `MatcherPos::sp_open`. It's a tiny perf win, reducing instruction counts by 0.1% - 0.2% on a few benchmarks. --- src/libsyntax_expand/mbe/macro_parser.rs | 23 +++++++---------------- src/libsyntax_expand/mbe/macro_rules.rs | 4 ++-- src/libsyntax_expand/mbe/transcribe.rs | 4 ++-- 3 files changed, 11 insertions(+), 20 deletions(-) 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::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]> { } /// 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, DelimSpan), + MatchedSeq(Lrc), MatchedNonterminal(Lrc), } @@ -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, } From 0b1e08a9f4b431afcf3076fe41f3b2dbcc6f3548 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 12 Dec 2019 10:22:09 +0100 Subject: [PATCH 5/6] Require `allow_internal_unstable` for stable min_const_fn using unstable features --- .../transform/qualify_min_const_fn.rs | 10 ++-- .../consts/const-mut-refs/const_mut_refs.rs | 1 + src/test/ui/consts/control-flow/basics.rs | 1 + .../exhaustive-c-like-enum-match.rs | 1 + ...eature-gate-const-if-match.if_match.stderr | 2 +- .../feature-gate-const-if-match.rs | 1 + .../feature-gate-const-if-match.stock.stderr | 50 +++++++++---------- .../consts/control-flow/short-circuit-let.rs | 1 + .../control-flow/single_variant_match_ice.rs | 2 +- 9 files changed, 37 insertions(+), 32 deletions(-) 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/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, From 45c1e381473b39e7fece2663638d09288370a821 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 13 Dec 2019 00:59:33 +0100 Subject: [PATCH 6/6] parser: recover on `&'lifetime mut $pat`. --- src/librustc_parse/parser/pat.rs | 24 +++++++++++++------ .../ui/parser/lifetime-in-pattern-recover.rs | 6 +++++ .../parser/lifetime-in-pattern-recover.stderr | 23 ++++++++++++++++++ src/test/ui/parser/lifetime-in-pattern.rs | 1 + src/test/ui/parser/lifetime-in-pattern.stderr | 10 ++++++-- .../ui/self/self-vs-path-ambiguity.stderr | 2 +- 6 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/parser/lifetime-in-pattern-recover.rs create mode 100644 src/test/ui/parser/lifetime-in-pattern-recover.stderr 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,18 +459,28 @@ fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'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(); - - 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); - } - 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 { + self.bump(); // `'a` + + 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. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; 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