diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6ad6e664316f4..9b1642df11401 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -505,14 +505,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { + let pat = self.lower_pat(&arm.pat); + let guard = arm.guard.as_ref().map(|cond| { + if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind { + hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee)) + } else { + hir::Guard::If(self.lower_expr(cond)) + } + }); hir::Arm { hir_id: self.next_id(), attrs: self.lower_attrs(&arm.attrs), - pat: self.lower_pat(&arm.pat), - guard: match arm.guard { - Some(ref x) => Some(hir::Guard::If(self.lower_expr(x))), - _ => None, - }, + pat, + guard, body: self.lower_expr(&arm.body), span: arm.span, } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 92a8f23112679..c37f91256757e 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -1,4 +1,4 @@ -//! This is an NFA-based parser, which calls out to the main rust parser for named non-terminals +//! This is an NFA-based parser, which calls out to the main Rust parser for named non-terminals //! (which it commits to fully when it hits one in a grammar). There's a set of current NFA threads //! and a set of next ones. Instead of NTs, we have a special case for Kleene star. The big-O, in //! pathological cases, is worse than traditional use of NFA or Earley parsing, but it's an easier @@ -422,7 +422,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// /// # Parameters /// -/// - `sess`: the parsing session into which errors are emitted. /// - `cur_items`: the set of current items to be processed. This should be empty by the end of a /// successful execution of this function. /// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in @@ -430,8 +429,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// - `eof_items`: the set of items that would be valid if this was the EOF. /// - `bb_items`: the set of items that are waiting for the black-box parser. /// - `token`: the current token of the parser. -/// - `span`: the `Span` in the source code corresponding to the token trees we are trying to match -/// against the matcher positions in `cur_items`. /// /// # Returns /// diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 280e863d4744d..2abebbd030387 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1160,6 +1160,7 @@ pub struct Arm<'hir> { #[derive(Debug, HashStable_Generic)] pub enum Guard<'hir> { If(&'hir Expr<'hir>), + IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>), } #[derive(Debug, HashStable_Generic)] @@ -1721,6 +1722,8 @@ pub enum MatchSource { IfDesugar { contains_else_clause: bool }, /// An `if let _ = _ { .. }` (optionally with `else { .. }`). IfLetDesugar { contains_else_clause: bool }, + /// An `if let _ = _ => { .. }` match guard. + IfLetGuardDesugar, /// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`). WhileDesugar, /// A `while let _ = _ { .. }` (which was desugared to a @@ -1739,7 +1742,7 @@ impl MatchSource { use MatchSource::*; match self { Normal => "match", - IfDesugar { .. } | IfLetDesugar { .. } => "if", + IfDesugar { .. } | IfLetDesugar { .. } | IfLetGuardDesugar => "if", WhileDesugar | WhileLetDesugar => "while", ForLoopDesugar => "for", TryDesugar => "?", diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3c330c5d6c528..03c8b1738853d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1228,6 +1228,10 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), + Guard::IfLet(ref pat, ref e) => { + visitor.visit_pat(pat); + visitor.visit_expr(e); + } } } visitor.visit_expr(&arm.body); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 597c55b4bd7f3..0b5eb1d82667d 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2002,6 +2002,15 @@ impl<'a> State<'a> { self.print_expr(&e); self.s.space(); } + hir::Guard::IfLet(pat, e) => { + self.word_nbsp("if"); + self.word_nbsp("let"); + self.print_pat(&pat); + self.s.space(); + self.word_space("="); + self.print_expr(&e); + self.s.space(); + } } } self.word_space("=>"); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7b67d15f64a2e..4dfe3e8487762 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -319,10 +319,6 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { self.opaque.position() } - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn type_shorthands(&mut self) -> &mut FxHashMap, usize> { &mut self.type_shorthands } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 47c140e0b1882..4f08057a7e323 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -132,37 +132,37 @@ pub fn report_unstable( /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool { - let since = if let Some(since) = since { - if is_since_rustc_version { - since - } else { - // We assume that the deprecation is in effect if it's not a - // rustc version. - return true; - } - } else { - // If since attribute is not set, then we're definitely in effect. - return true; - }; fn parse_version(ver: &str) -> Vec { // We ignore non-integer components of the version (e.g., "nightly"). ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() } - if let Some(rustc) = option_env!("CFG_RELEASE") { - let since: Vec = parse_version(&since); - let rustc: Vec = parse_version(rustc); - // We simply treat invalid `since` attributes as relating to a previous - // Rust version, thus always displaying the warning. - if since.len() != 3 { - return true; - } - since <= rustc - } else { - // By default, a deprecation warning applies to - // the current version of the compiler. - true + if !is_since_rustc_version { + // The `since` field doesn't have semantic purpose in the stable `deprecated` + // attribute, only in `rustc_deprecated`. + return true; } + + if let Some(since) = since { + if since == "TBD" { + return false; + } + + if let Some(rustc) = option_env!("CFG_RELEASE") { + let since: Vec = parse_version(&since); + let rustc: Vec = parse_version(rustc); + // We simply treat invalid `since` attributes as relating to a previous + // Rust version, thus always displaying the warning. + if since.len() != 3 { + return true; + } + return since <= rustc; + } + }; + + // Assume deprecation is in effect if "since" field is missing + // or if we can't determine the current Rust version. + true } pub fn deprecation_suggestion( @@ -182,19 +182,24 @@ pub fn deprecation_suggestion( } pub fn deprecation_message(depr: &Deprecation, kind: &str, path: &str) -> (String, &'static Lint) { - let (message, lint) = if deprecation_in_effect( - depr.is_since_rustc_version, - depr.since.map(Symbol::as_str).as_deref(), - ) { + let since = depr.since.map(Symbol::as_str); + let (message, lint) = if deprecation_in_effect(depr.is_since_rustc_version, since.as_deref()) { (format!("use of deprecated {} `{}`", kind, path), DEPRECATED) } else { ( - format!( - "use of {} `{}` that will be deprecated in future version {}", - kind, - path, - depr.since.unwrap() - ), + if since.as_deref() == Some("TBD") { + format!( + "use of {} `{}` that will be deprecated in a future Rust version", + kind, path + ) + } else { + format!( + "use of {} `{}` that will be deprecated in future version {}", + kind, + path, + since.unwrap() + ) + }, DEPRECATED_IN_FUTURE, ) }; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index b2fc3710cd673..1983af17dd076 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -69,7 +69,6 @@ impl OpaqueEncoder for rustc_serialize::opaque::Encoder { pub trait TyEncoder<'tcx>: Encoder { const CLEAR_CROSS_CRATE: bool; - fn tcx(&self) -> TyCtxt<'tcx>; fn position(&self) -> usize; fn type_shorthands(&mut self) -> &mut FxHashMap, usize>; fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 3eed94b1ffbc0..e006dfeb66336 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1044,9 +1044,6 @@ where { const CLEAR_CROSS_CRATE: bool = false; - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } fn position(&self) -> usize { self.encoder.encoder_position() } diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 53f7c28ee35be..4590d37c182e4 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -310,7 +310,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { inject_statement( self.mir_body, counter_kind, - self.bcb_last_bb(bcb), + self.bcb_leader_bb(bcb), Some(make_code_region(file_name, &self.source_file, span, body_span)), ); } @@ -470,7 +470,7 @@ fn inject_statement( code_region: some_code_region, }), }; - data.statements.push(statement); + data.statements.insert(0, statement); } // Non-code expressions are injected into the coverage map, without generating executable code. diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 6fbcc140978a7..b16a99d7f0dca 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -284,6 +284,33 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { return None; } + // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. + // for example, this should not be optimized: + // + // ```rust + // enum E<'a> { Empty, Some(&'a E<'a>), } + // let Some(Some(_)) = e; + // ``` + // + // ```mir + // bb0: { + // _2 = discriminant(*_1) + // switchInt(_2) -> [...] + // } + // bb1: { + // _3 = discriminant(*(((*_1) as Some).0: &E)) + // switchInt(_3) -> [...] + // } + // ``` + let discr_place = discr_info.place_of_adt_discr_read; + let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; + if discr_place.local == this_discr_place.local + && this_discr_place.projection.starts_with(discr_place.projection) + { + trace!("NO: one target is the projection of another"); + return None; + } + // if we reach this point, the optimization applies, and we should be able to optimize this case // store the info that is needed to apply the optimization diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6d166bf37f97e..2e108d480932a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -228,6 +228,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option<&Guard<'tcx>>, fake_borrow_temps: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + arm_span: Option, arm_scope: Option, ) -> BasicBlock { if candidate.subcandidates.is_empty() { @@ -239,6 +240,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, fake_borrow_temps, scrutinee_span, + arm_span, true, ) } else { @@ -274,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, &fake_borrow_temps, scrutinee_span, + arm_span, schedule_drops, ); if arm_scope.is_none() { @@ -436,6 +439,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &fake_borrow_temps, irrefutable_pat.span, None, + None, ) .unit() } @@ -817,11 +821,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// For an example of a case where we set `otherwise_block`, even for an /// exhaustive match consider: /// + /// ```rust /// match x { /// (true, true) => (), /// (_, false) => (), /// (false, true) => (), /// } + /// ``` /// /// For this match, we check if `x.0` matches `true` (for the first /// arm). If that's false, we check `x.1`. If it's `true` we check if @@ -935,11 +941,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Link up matched candidates. For example, if we have something like /// this: /// + /// ```rust /// ... /// Some(x) if cond => ... /// Some(x) => ... /// Some(x) if cond => ... /// ... + /// ``` /// /// We generate real edges from: /// * `start_block` to the `prebinding_block` of the first pattern, @@ -1517,7 +1525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Initializes each of the bindings from the candidate by /// moving/copying/ref'ing the source as appropriate. Tests the guard, if /// any, and then branches to the arm. Returns the block for the case where - /// the guard fails. + /// the guard succeeds. /// /// Note: we do not check earlier that if there is a guard, /// there cannot be move bindings. We avoid a use-after-move by only @@ -1529,6 +1537,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option<&Guard<'tcx>>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + arm_span: Option, schedule_drops: bool, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1659,15 +1668,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); } - // the block to branch to if the guard fails; if there is no - // guard, this block is simply unreachable - let guard = match guard { - Guard::If(e) => self.hir.mirror(e.clone()), + let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard { + Guard::If(e) => { + let e = self.hir.mirror(e.clone()); + let source_info = self.source_info(e.span); + (e.span, self.test_bool(block, e, source_info)) + }, + Guard::IfLet(pat, scrutinee) => { + let scrutinee_span = scrutinee.span(); + let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)); + let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false); + let wildcard = Pat::wildcard_from_ty(pat.ty); + let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false); + let fake_borrow_temps = + self.lower_match_tree(block, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate]); + self.declare_bindings( + None, + pat.span.to(arm_span.unwrap()), + pat, + ArmHasGuard(false), + Some((Some(&scrutinee_place), scrutinee.span())), + ); + let post_guard_block = self.bind_pattern( + self.source_info(pat.span), + guard_candidate, + None, + &fake_borrow_temps, + scrutinee.span(), + None, + None, + ); + let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); + (scrutinee_span, (post_guard_block, otherwise_post_guard_block)) + } }; - let source_info = self.source_info(guard.span); - let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span)); - let (post_guard_block, otherwise_post_guard_block) = - self.test_bool(block, guard, source_info); + let source_info = self.source_info(guard_span); + let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span)); let guard_frame = self.guard_context.pop().unwrap(); debug!("Exiting guard building context with locals: {:?}", guard_frame); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 0edd44d4bf1eb..62d2212d10962 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -1197,6 +1197,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm.guard.as_ref(), &fake_borrow_temps, scrutinee_span, + Some(arm.span), Some(arm.scope), ); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index fbdadc67b43ba..417f9bded0988 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -776,10 +776,10 @@ impl ToBorrowKind for hir::Mutability { fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> { Arm { pattern: cx.pattern_from_hir(&arm.pat), - guard: match arm.guard { - Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())), - _ => None, - }, + guard: arm.guard.as_ref().map(|g| match g { + hir::Guard::If(ref e) => Guard::If(e.to_ref()), + hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()), + }), body: arm.body.to_ref(), lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index 1a901746d5086..ace9cad4d2996 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -344,6 +344,7 @@ crate struct Arm<'tcx> { #[derive(Clone, Debug)] crate enum Guard<'tcx> { If(ExprRef<'tcx>), + IfLet(Pat<'tcx>, ExprRef<'tcx>), } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 97edbd83b89ce..29b7e176b0e1a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -164,10 +164,20 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(&arm.pat); + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + self.check_patterns(pat); + } } let mut cx = self.new_cx(scrut.hir_id); + for arm in arms { + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; + check_if_let_guard(&mut cx, &tpat, pat.hir_id); + } + } + let mut have_errors = false; let arms: Vec<_> = arms @@ -360,12 +370,28 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir:: let msg = match source { hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern", hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern", + hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard", _ => bug!(), }; lint.build(msg).emit() }); } +fn check_if_let_guard<'p, 'tcx>( + cx: &mut MatchCheckCtxt<'p, 'tcx>, + pat: &'p super::Pat<'tcx>, + pat_id: HirId, +) { + let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); + report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar); + + if report.non_exhaustiveness_witnesses.is_empty() { + // The match is exhaustive, i.e. the if let pattern is irrefutable. + irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar) + } +} + /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, @@ -390,6 +416,11 @@ fn report_arm_reachability<'p, 'tcx>( } } + hir::MatchSource::IfLetGuardDesugar => { + assert_eq!(arm_index, 0); + unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None); + } + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall); } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index e37c6418eb81c..2d6bbff460d7f 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -45,6 +45,8 @@ impl NonConstExpr { return None; } + Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"), + // All other expressions are allowed. Self::Loop(Loop | While | WhileLet) | Self::Match( diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index a161ad16b8c20..86ce35c6d9909 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -360,6 +360,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { self.add_from_pat(&arm.pat); + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + self.add_from_pat(pat); + } intravisit::walk_arm(self, arm); } @@ -866,10 +869,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for arm in arms { let body_succ = self.propagate_through_expr(&arm.body, succ); - let guard_succ = self.propagate_through_opt_expr( - arm.guard.as_ref().map(|hir::Guard::If(e)| *e), - body_succ, - ); + let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g { + hir::Guard::If(e) => self.propagate_through_expr(e, body_succ), + hir::Guard::IfLet(pat, e) => { + let let_bind = self.define_bindings_in_pat(pat, body_succ); + self.propagate_through_expr(e, let_bind) + } + }); let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); self.merge_from_succ(ln, arm_succ); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index f6bbbd80bf1eb..3c2462aab26b7 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -182,28 +182,32 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { for (dep_v, stab_v) in dep_since.as_str().split('.').zip(stab_since.as_str().split('.')) { - if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::(), stab_v.parse()) { - match dep_v.cmp(&stab_v) { - Ordering::Less => { - self.tcx.sess.span_err( - item_sp, - "An API can't be stabilized \ - after it is deprecated", - ); + match stab_v.parse::() { + Err(_) => { + self.tcx.sess.span_err(item_sp, "Invalid stability version found"); + break; + } + Ok(stab_vp) => match dep_v.parse::() { + Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { + Ordering::Less => { + self.tcx.sess.span_err( + item_sp, + "An API can't be stabilized after it is deprecated", + ); + break; + } + Ordering::Equal => continue, + Ordering::Greater => break, + }, + Err(_) => { + if dep_v != "TBD" { + self.tcx + .sess + .span_err(item_sp, "Invalid deprecation version found"); + } break; } - Ordering::Equal => continue, - Ordering::Greater => break, - } - } else { - // Act like it isn't less because the question is now nonsensical, - // and this makes us not do anything else interesting. - self.tcx.sess.span_err( - item_sp, - "Invalid stability or deprecation \ - version found", - ); - break; + }, } } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c20b11656b229..c9ddcbdb5f5cc 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1491,7 +1491,7 @@ fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType early_error(error_format, &format!("target file {:?} does not exist", path)) }) } - Some(target) => TargetTriple::TargetTriple(target), + Some(target) => TargetTriple::from_alias(target), _ => TargetTriple::from_triple(host_triple()), } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8d749493d0a42..8d72df6850fc2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1800,6 +1800,24 @@ impl TargetTriple { Ok(TargetTriple::TargetPath(canonicalized_path)) } + /// Creates a target triple from its alias + pub fn from_alias(triple: String) -> Self { + macro_rules! target_aliases { + ( $(($alias:literal, $target:literal ),)+ ) => { + match triple.as_str() { + $( $alias => TargetTriple::from_triple($target), )+ + _ => TargetTriple::TargetTriple(triple), + } + } + } + + target_aliases! { + // `x86_64-pc-solaris` is an alias for `x86_64_sun_solaris` for backwards compatibility reasons. + // (See .) + ("x86_64-pc-solaris", "x86_64-sun-solaris"), + } + } + /// Returns a string triple for this target. /// /// If this target is a path, the file name (without extension) is returned. diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 3a5eeb5381bec..3106f19cf86f3 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(60707): Consider removing hack with principled solution. self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {}) } else { - self.demand_scrutinee_type(arms, scrut) + self.demand_scrutinee_type(scrut, arms_contain_ref_bindings(arms), arms.is_empty()) }; // If there are no arms, that is a diverging match; a special case. @@ -98,7 +98,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.diverges.set(Diverges::Maybe); match g { hir::Guard::If(e) => { - self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}) + self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); + } + hir::Guard::IfLet(pat, e) => { + let scrutinee_ty = self.demand_scrutinee_type( + e, + pat.contains_explicit_ref_binding(), + false, + ); + self.check_pat_top(&pat, scrutinee_ty, None, true); } }; } @@ -450,8 +458,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn demand_scrutinee_type( &self, - arms: &'tcx [hir::Arm<'tcx>], scrut: &'tcx hir::Expr<'tcx>, + contains_ref_bindings: Option, + no_arms: bool, ) -> Ty<'tcx> { // Not entirely obvious: if matches may create ref bindings, we want to // use the *precise* type of the scrutinee, *not* some supertype, as @@ -505,17 +514,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // (once introduced) is populated by the time we get here. // // See #44848. - let contains_ref_bindings = arms - .iter() - .filter_map(|a| a.pat.contains_explicit_ref_binding()) - .max_by_key(|m| match *m { - hir::Mutability::Mut => 1, - hir::Mutability::Not => 0, - }); - if let Some(m) = contains_ref_bindings { self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m)) - } else if arms.is_empty() { + } else if no_arms { self.check_expr(scrut) } else { // ...but otherwise we want to use any supertype of the @@ -546,3 +547,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +fn arms_contain_ref_bindings(arms: &'tcx [hir::Arm<'tcx>]) -> Option { + arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m { + hir::Mutability::Mut => 1, + hir::Mutability::Not => 0, + }) +} diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 602b79802b33d..5bc40d617d044 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -246,6 +246,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { Guard::If(ref e) => { self.visit_expr(e); } + Guard::IfLet(ref pat, ref e) => { + self.visit_pat(pat); + self.visit_expr(e); + } } let mut scope_var_ids = diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 4fa48427ec6e6..2cde5d9995b62 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -92,6 +92,8 @@ $EndFeature, " "), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 390c1b7e9e871..ae8fc18a83882 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -90,6 +90,8 @@ assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[inline] pub const fn count_ones(self) -> u32 { intrinsics::ctpop(self as $ActualT) as u32 diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 5324dfdeddde2..77c9a93008c91 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -453,6 +453,8 @@ let n = Wrapping(0b01001100", stringify!($t), "); assert_eq!(n.count_ones(), 3); ```"), #[inline] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn count_ones(self) -> u32 { self.0.count_ones() diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b1bb97cf83ba5..8ccb9dbdf0166 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1043,30 +1043,6 @@ impl Step for Src { builder.copy(&builder.src.join(file), &dst_src.join(file)); } - // libtest includes std and everything else, so vendoring it - // creates exactly what's needed for `cargo -Zbuild-std` or any - // other analysis of the stdlib's source. Cargo also needs help - // finding the lock, so we copy it to libtest temporarily. - // - // Note that this requires std to only have one version of each - // crate. e.g. two versions of getopts won't be patchable. - let dst_libtest = dst_src.join("library/test"); - let dst_vendor = dst_src.join("vendor"); - let root_lock = dst_src.join("Cargo.lock"); - let temp_lock = dst_libtest.join("Cargo.lock"); - - // `cargo vendor` will delete everything from the lockfile that - // isn't used by libtest, so we need to not use any links! - builder.really_copy(&root_lock, &temp_lock); - - let mut cmd = Command::new(&builder.initial_cargo); - cmd.arg("vendor").arg(dst_vendor).current_dir(&dst_libtest); - builder.info("Dist src"); - let _time = timeit(builder); - builder.run(&mut cmd); - - builder.remove(&temp_lock); - // Create source tarball in rust-installer format let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -1083,6 +1059,8 @@ impl Step for Src { .arg("--component-name=rust-src") .arg("--legacy-manifest-dirs=rustlib,cargo"); + builder.info("Dist src"); + let _time = timeit(builder); builder.run(&mut cmd); builder.remove_dir(&image); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 06ccd72186dd1..ece9bdc7a6499 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1182,27 +1182,6 @@ impl Build { paths } - /// Copies a file from `src` to `dst` and doesn't use links, so - /// that the copy can be modified without affecting the original. - pub fn really_copy(&self, src: &Path, dst: &Path) { - if self.config.dry_run { - return; - } - self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst)); - if src == dst { - return; - } - let _ = fs::remove_file(&dst); - let metadata = t!(src.symlink_metadata()); - if let Err(e) = fs::copy(src, dst) { - panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) - } - t!(fs::set_permissions(dst, metadata.permissions())); - let atime = FileTime::from_last_access_time(&metadata); - let mtime = FileTime::from_last_modification_time(&metadata); - t!(filetime::set_file_times(dst, atime, mtime)); - } - /// Copies a file from `src` to `dst` pub fn copy(&self, src: &Path, dst: &Path) { if self.config.dry_run { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 88c5e94c27671..00294878fe5fb 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2279,7 +2279,11 @@ fn short_item_info(item: &clean::Item, cx: &Context, parent: Option<&clean::Item let mut message = if let Some(since) = since { let since = &since.as_str(); if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) { - format!("Deprecating in {}", Escape(since)) + if *since == "TBD" { + format!("Deprecating in a future Rust version") + } else { + format!("Deprecating in {}", Escape(since)) + } } else { format!("Deprecated since {}", Escape(since)) } diff --git a/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot index 124f2d8b97a00..c00eae96e0838 100644 --- a/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot +++ b/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot @@ -2,5 +2,5 @@ digraph Cov_0_4 { graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb0__Cov_0_4 [shape="none", label=<
bcb0
Counter(bcb0) at 18:1-20:2
19:5-19:9: @0[0]: _0 = const true
20:2-20:2: @0.Return: return
bb0: Return
>]; + bcb0__Cov_0_4 [shape="none", label=<
bcb0
Counter(bcb0) at 18:1-20:2
19:5-19:9: @0[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:18:1 - 20:2
20:2-20:2: @0.Return: return
bb0: Return
>]; } diff --git a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot index d88193da4fb19..5b6d73a7deefb 100644 --- a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot +++ b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot @@ -2,7 +2,7 @@ digraph Cov_0_3 { graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 13:10-13:10
13:10-13:10: @4[0]: _1 = const ()
bb4: Goto
>]; + bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 13:10-13:10
13:10-13:10: @4[0]: Coverage::Expression(4294967295) = 1 - 2 for $DIR/coverage_graphviz.rs:13:10 - 13:11
bb4: Goto
>]; bcb1__Cov_0_3 [shape="none", label=<
bcb1
Counter(bcb1) at 12:13-12:18
12:13-12:18: @5[0]: _0 = const ()
Expression(bcb1 + 0) at 15:2-15:2
15:2-15:2: @5.Return: return
bb3: FalseEdge
bb5: Return
>]; bcb0__Cov_0_3 [shape="none", label=<
bcb0
Counter(bcb0) at 9:1-11:17
11:12-11:17: @1.Call: _2 = bar() -> [return: bb2, unwind: bb6]
11:12-11:17: @2[0]: FakeRead(ForMatchedPlace, _2)
bb0: FalseUnwind
bb1: Call
bb2: SwitchInt
>]; bcb2__Cov_0_3 -> bcb0__Cov_0_3 [label=<>]; diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 112a698309276..fef696df770b6 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -5,8 +5,8 @@ let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:19:13: 19:17 bb0: { - _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 + Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 + _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 83dee7efa6db4..9bd8c9cf61331 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -8,6 +8,7 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 falseUnwind -> [real: bb1, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } @@ -21,26 +22,25 @@ bb2: { FakeRead(ForMatchedPlace, _2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 switchInt(_2) -> [false: bb4, otherwise: bb3]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } bb3: { ++ Coverage::Expression(4294967294) = 2 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 ++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } bb4: { ++ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:14:10: 14:10 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 -+ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb5: { _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 -+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 -+ Coverage::Expression(4294967294) = 2 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json index 024b5f11179ac..bb857ba3f3b3f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json @@ -17,14 +17,14 @@ }, "lines": { "count": 15, - "covered": 12, - "percent": 80 + "covered": 13, + "percent": 86.66666666666667 }, "regions": { "count": 14, - "covered": 12, - "notcovered": 2, - "percent": 85.71428571428571 + "covered": 13, + "notcovered": 1, + "percent": 92.85714285714286 } } } @@ -42,14 +42,14 @@ }, "lines": { "count": 15, - "covered": 12, - "percent": 80 + "covered": 13, + "percent": 86.66666666666667 }, "regions": { "count": 14, - "covered": 12, - "notcovered": 2, - "percent": 85.71428571428571 + "covered": 13, + "notcovered": 1, + "percent": 92.85714285714286 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json index 030d7b033f009..128f5888ed113 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json @@ -17,14 +17,14 @@ }, "lines": { "count": 23, - "covered": 19, - "percent": 82.6086956521739 + "covered": 21, + "percent": 91.30434782608695 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } @@ -42,14 +42,14 @@ }, "lines": { "count": 23, - "covered": 19, - "percent": 82.6086956521739 + "covered": 21, + "percent": 91.30434782608695 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json index b1d44fdfeac54..9c08dfd41a12b 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json @@ -17,14 +17,14 @@ }, "lines": { "count": 19, - "covered": 16, - "percent": 84.21052631578947 + "covered": 17, + "percent": 89.47368421052632 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } @@ -42,14 +42,14 @@ }, "lines": { "count": 19, - "covered": 16, - "percent": 84.21052631578947 + "covered": 17, + "percent": 89.47368421052632 }, "regions": { "count": 13, - "covered": 11, - "notcovered": 2, - "percent": 84.61538461538461 + "covered": 12, + "notcovered": 1, + "percent": 92.3076923076923 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt index 355b53f7f3b69..405688806eaae 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt @@ -9,13 +9,13 @@ 8| | 9| 1|fn main() -> Result<(),u8> { 10| 1| let mut countdown = 10; - 11| 10| while countdown > 0 { - 12| 10| if countdown == 1 { - 13| 0| might_fail_assert(3); + 11| 11| while countdown > 0 { + 12| 11| if countdown == 1 { + 13| 1| might_fail_assert(3); 14| 10| } else if countdown < 5 { 15| 3| might_fail_assert(2); 16| 6| } - 17| 9| countdown -= 1; + 17| 10| countdown -= 1; 18| | } 19| 0| Ok(()) 20| 0|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt index 4dccb3413eae9..25e822bffd11f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt @@ -14,15 +14,15 @@ 14| | 15| 1|fn main() -> Result<(),u8> { 16| 1| let mut countdown = 10; - 17| 10| while countdown > 0 { - 18| 10| if countdown == 1 { - 19| 0| let result = might_overflow(10); - 20| 0| println!("Result: {}", result); + 17| 11| while countdown > 0 { + 18| 11| if countdown == 1 { + 19| 1| let result = might_overflow(10); + 20| 1| println!("Result: {}", result); 21| 10| } else if countdown < 5 { 22| 3| let result = might_overflow(1); 23| 3| println!("Result: {}", result); 24| 6| } - 25| 9| countdown -= 1; + 25| 10| countdown -= 1; 26| | } 27| 0| Ok(()) 28| 0|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt index 9ae78fee4b5e1..c77ee5ddc207b 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt @@ -12,13 +12,13 @@ 12| | 13| 1|fn main() -> Result<(), u8> { 14| 1| let mut countdown = 10; - 15| 10| while countdown > 0 { - 16| 10| if countdown == 1 { - 17| 0| might_panic(true); + 15| 11| while countdown > 0 { + 16| 11| if countdown == 1 { + 17| 1| might_panic(true); 18| 10| } else if countdown < 5 { 19| 3| might_panic(false); 20| 6| } - 21| 9| countdown -= 1; + 21| 10| countdown -= 1; 22| | } 23| 0| Ok(()) 24| 0|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt index 916ebbbcc29d3..0866a9a59a11d 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt @@ -20,13 +20,13 @@ Combined regions: 6:37 -> 6:61 (count=1) 7:1 -> 7:2 (count=3) 9:1 -> 10:27 (count=1) - 11:11 -> 11:24 (count=10) - 12:12 -> 12:26 (count=10) - 12:27 -> 14:10 (count=0) + 11:11 -> 11:24 (count=11) + 12:12 -> 12:26 (count=11) + 12:27 -> 14:10 (count=1) 14:19 -> 14:32 (count=10) 14:33 -> 16:10 (count=3) 16:10 -> 16:11 (count=6) - 17:9 -> 17:23 (count=9) + 17:9 -> 17:23 (count=10) 19:5 -> 20:2 (count=0) Segment at 4:1 (count = 4), RegionEntry Segment at 4:41 (count = 0), Skipped @@ -40,18 +40,18 @@ Segment at 7:1 (count = 3), RegionEntry Segment at 7:2 (count = 0), Skipped Segment at 9:1 (count = 1), RegionEntry Segment at 10:27 (count = 0), Skipped -Segment at 11:11 (count = 10), RegionEntry +Segment at 11:11 (count = 11), RegionEntry Segment at 11:24 (count = 0), Skipped -Segment at 12:12 (count = 10), RegionEntry +Segment at 12:12 (count = 11), RegionEntry Segment at 12:26 (count = 0), Skipped -Segment at 12:27 (count = 0), RegionEntry +Segment at 12:27 (count = 1), RegionEntry Segment at 14:10 (count = 0), Skipped Segment at 14:19 (count = 10), RegionEntry Segment at 14:32 (count = 0), Skipped Segment at 14:33 (count = 3), RegionEntry Segment at 16:10 (count = 6), RegionEntry Segment at 16:11 (count = 0), Skipped -Segment at 17:9 (count = 9), RegionEntry +Segment at 17:9 (count = 10), RegionEntry Segment at 17:23 (count = 0), Skipped Segment at 19:5 (count = 0), RegionEntry Segment at 20:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt index fbc3adbfb6d70..380bb7cf17016 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt @@ -18,13 +18,13 @@ Combined regions: 7:6 -> 7:7 (count=3) 8:9 -> 13:2 (count=4) 15:1 -> 16:27 (count=1) - 17:11 -> 17:24 (count=10) - 18:12 -> 18:26 (count=10) - 18:27 -> 21:10 (count=0) + 17:11 -> 17:24 (count=11) + 18:12 -> 18:26 (count=11) + 18:27 -> 21:10 (count=1) 21:19 -> 21:32 (count=10) 21:33 -> 24:10 (count=3) 24:10 -> 24:11 (count=6) - 25:9 -> 25:23 (count=9) + 25:9 -> 25:23 (count=10) 27:5 -> 28:2 (count=0) Segment at 4:1 (count = 4), RegionEntry Segment at 5:18 (count = 0), Skipped @@ -35,18 +35,18 @@ Segment at 8:9 (count = 4), RegionEntry Segment at 13:2 (count = 0), Skipped Segment at 15:1 (count = 1), RegionEntry Segment at 16:27 (count = 0), Skipped -Segment at 17:11 (count = 10), RegionEntry +Segment at 17:11 (count = 11), RegionEntry Segment at 17:24 (count = 0), Skipped -Segment at 18:12 (count = 10), RegionEntry +Segment at 18:12 (count = 11), RegionEntry Segment at 18:26 (count = 0), Skipped -Segment at 18:27 (count = 0), RegionEntry +Segment at 18:27 (count = 1), RegionEntry Segment at 21:10 (count = 0), Skipped Segment at 21:19 (count = 10), RegionEntry Segment at 21:32 (count = 0), Skipped Segment at 21:33 (count = 3), RegionEntry Segment at 24:10 (count = 6), RegionEntry Segment at 24:11 (count = 0), Skipped -Segment at 25:9 (count = 9), RegionEntry +Segment at 25:9 (count = 10), RegionEntry Segment at 25:23 (count = 0), Skipped Segment at 27:5 (count = 0), RegionEntry Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt index ad87f03026d38..b3f61ad325d1c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt @@ -18,13 +18,13 @@ Combined regions: 6:9 -> 7:26 (count=1) 8:12 -> 11:2 (count=3) 13:1 -> 14:27 (count=1) - 15:11 -> 15:24 (count=10) - 16:12 -> 16:26 (count=10) - 16:27 -> 18:10 (count=0) + 15:11 -> 15:24 (count=11) + 16:12 -> 16:26 (count=11) + 16:27 -> 18:10 (count=1) 18:19 -> 18:32 (count=10) 18:33 -> 20:10 (count=3) 20:10 -> 20:11 (count=6) - 21:9 -> 21:23 (count=9) + 21:9 -> 21:23 (count=10) 23:5 -> 24:2 (count=0) Segment at 4:1 (count = 4), RegionEntry Segment at 4:36 (count = 0), Skipped @@ -36,18 +36,18 @@ Segment at 8:12 (count = 3), RegionEntry Segment at 11:2 (count = 0), Skipped Segment at 13:1 (count = 1), RegionEntry Segment at 14:27 (count = 0), Skipped -Segment at 15:11 (count = 10), RegionEntry +Segment at 15:11 (count = 11), RegionEntry Segment at 15:24 (count = 0), Skipped -Segment at 16:12 (count = 10), RegionEntry +Segment at 16:12 (count = 11), RegionEntry Segment at 16:26 (count = 0), Skipped -Segment at 16:27 (count = 0), RegionEntry +Segment at 16:27 (count = 1), RegionEntry Segment at 18:10 (count = 0), Skipped Segment at 18:19 (count = 10), RegionEntry Segment at 18:32 (count = 0), Skipped Segment at 18:33 (count = 3), RegionEntry Segment at 20:10 (count = 6), RegionEntry Segment at 20:11 (count = 0), Skipped -Segment at 21:9 (count = 9), RegionEntry +Segment at 21:9 (count = 10), RegionEntry Segment at 21:23 (count = 0), Skipped Segment at 23:5 (count = 0), RegionEntry Segment at 24:2 (count = 0), Skipped diff --git a/src/test/rustdoc/rustc_deprecated-future.rs b/src/test/rustdoc/rustc_deprecated-future.rs index 3133775706b8d..95a767a8329ac 100644 --- a/src/test/rustdoc/rustc_deprecated-future.rs +++ b/src/test/rustdoc/rustc_deprecated-future.rs @@ -4,8 +4,16 @@ // @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \ // 'Deprecation planned' -// @has rustc_deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \ +// @has rustc_deprecated_future/struct.S1.html '//*[@class="stab deprecated"]' \ // 'Deprecating in 99.99.99: effectively never' #[rustc_deprecated(since = "99.99.99", reason = "effectively never")] #[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")] -pub struct S; +pub struct S1; + +// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \ +// 'Deprecation planned' +// @has rustc_deprecated_future/struct.S2.html '//*[@class="stab deprecated"]' \ +// 'Deprecating in a future Rust version: literally never' +#[rustc_deprecated(since = "TBD", reason = "literally never")] +#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")] +pub struct S2; diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.rs b/src/test/ui/deprecation/rustc_deprecation-in-future.rs index 6a619bcc49c2d..11f7960b75786 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.rs +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.rs @@ -8,8 +8,13 @@ #[rustc_deprecated(since = "99.99.99", reason = "effectively never")] #[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] -pub struct S; +pub struct S1; + +#[rustc_deprecated(since = "TBD", reason = "literally never")] +#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] +pub struct S2; fn main() { - let _ = S; //~ ERROR use of unit struct `S` that will be deprecated in future version 99.99.99: effectively never + let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never + let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never } diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr index e4f50d10dadd2..b5a7dd3c28daf 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr @@ -1,8 +1,8 @@ -error: use of unit struct `S` that will be deprecated in future version 99.99.99: effectively never - --> $DIR/rustc_deprecation-in-future.rs:14:13 +error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never + --> $DIR/rustc_deprecation-in-future.rs:18:13 | -LL | let _ = S; - | ^ +LL | let _ = S1; + | ^^ | note: the lint level is defined here --> $DIR/rustc_deprecation-in-future.rs:3:9 @@ -10,5 +10,11 @@ note: the lint level is defined here LL | #![deny(deprecated_in_future)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never + --> $DIR/rustc_deprecation-in-future.rs:19:13 + | +LL | let _ = S2; + | ^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs index c76726414df8a..5c10a7c781183 100644 --- a/src/test/ui/generator/yielding-in-match-guards.rs +++ b/src/test/ui/generator/yielding-in-match-guards.rs @@ -10,6 +10,9 @@ // Thus, `&'_ u8` should be included in type signature // of the underlying generator. +#![feature(if_let_guard)] +#![allow(incomplete_features)] + async fn f() -> u8 { 1 } async fn foo() -> [bool; 10] { [false; 10] } @@ -36,8 +39,16 @@ async fn i(x: u8) { } } +async fn j(x: u8) { + match x { + y if let (1, 42) = (f().await, y) => (), + _ => (), + } +} + fn main() { let _ = g(10); let _ = h(9); let _ = i(8); + let _ = j(7); } diff --git a/src/test/ui/mir/issue-78496.rs b/src/test/ui/mir/issue-78496.rs new file mode 100644 index 0000000000000..1b0687cfac3f6 --- /dev/null +++ b/src/test/ui/mir/issue-78496.rs @@ -0,0 +1,16 @@ +// run-pass +// compile-flags: -Z mir-opt-level=2 -C opt-level=0 + +// example from #78496 +pub enum E<'a> { + Empty, + Some(&'a E<'a>), +} + +fn f(e: &E) -> u32 { + if let E::Some(E::Some(_)) = e { 1 } else { 2 } +} + +fn main() { + assert_eq!(f(&E::Empty), 2); +} diff --git a/src/test/ui/no-std-macros.rs b/src/test/ui/no-std-macros.rs new file mode 100644 index 0000000000000..ada643c7ac041 --- /dev/null +++ b/src/test/ui/no-std-macros.rs @@ -0,0 +1,13 @@ +// compile-flags: --crate-type=lib +// check-pass +// issue #55482 +#![no_std] + +macro_rules! foo { + ($e:expr) => { + $crate::core::assert!($e); + $crate::core::assert_eq!($e, true); + }; +} + +pub fn foo() { foo!(true); } diff --git a/src/test/ui/rfc-2294-if-let-guard/bindings.rs b/src/test/ui/rfc-2294-if-let-guard/bindings.rs new file mode 100644 index 0000000000000..4e2d70e3290ec --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/bindings.rs @@ -0,0 +1,10 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn main() { + match Some(None) { + Some(x) if let Some(y) = x => (x, y), + _ => y, //~ ERROR cannot find value `y` + } + y //~ ERROR cannot find value `y` +} diff --git a/src/test/ui/rfc-2294-if-let-guard/bindings.stderr b/src/test/ui/rfc-2294-if-let-guard/bindings.stderr new file mode 100644 index 0000000000000..9c5d92a33ada7 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/bindings.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:7:14 + | +LL | _ => y, + | ^ not found in this scope + +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:9:5 + | +LL | y + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index c0a9bbc36b24b..311d1afcfc0ee 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -6,7 +6,6 @@ fn _if_let_guard() { match () { () if let 0 = 1 => {} //~^ ERROR `if let` guard is not implemented - //~| ERROR `let` expressions are not supported here () if (let 0 = 1) => {} //~^ ERROR `let` expressions in this position are experimental diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index 5c7f8190dd6ec..1670078e0d38b 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `let` - --> $DIR/feature-gate.rs:81:15 + --> $DIR/feature-gate.rs:80:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -17,7 +17,7 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable error[E0658]: `if let` guard is not implemented - --> $DIR/feature-gate.rs:77:12 + --> $DIR/feature-gate.rs:76:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:11:16 + --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} | ^^^^^^^^^ @@ -35,7 +35,7 @@ LL | () if (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:15:18 + --> $DIR/feature-gate.rs:14:18 | LL | () if (((let 0 = 1))) => {} | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | () if (((let 0 = 1))) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:19:23 + --> $DIR/feature-gate.rs:18:23 | LL | () if true && let 0 = 1 => {} | ^^^^^^^^^ @@ -53,7 +53,7 @@ LL | () if true && let 0 = 1 => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:23:15 + --> $DIR/feature-gate.rs:22:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -62,7 +62,7 @@ LL | () if let 0 = 1 && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:27:16 + --> $DIR/feature-gate.rs:26:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -71,7 +71,7 @@ LL | () if (let 0 = 1) && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:31:24 + --> $DIR/feature-gate.rs:30:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -80,7 +80,7 @@ LL | () if true && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:35:16 + --> $DIR/feature-gate.rs:34:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:35:31 + --> $DIR/feature-gate.rs:34:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -98,7 +98,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:15 + --> $DIR/feature-gate.rs:40:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -107,7 +107,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:28 + --> $DIR/feature-gate.rs:40:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -116,7 +116,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:42 + --> $DIR/feature-gate.rs:40:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:55 + --> $DIR/feature-gate.rs:40:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -134,7 +134,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:68 + --> $DIR/feature-gate.rs:40:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -143,7 +143,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:53:15 + --> $DIR/feature-gate.rs:52:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:69:16 + --> $DIR/feature-gate.rs:68:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -161,7 +161,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:72:16 + --> $DIR/feature-gate.rs:71:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -170,16 +170,7 @@ LL | use_expr!((let 0 = 1)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:7:15 - | -LL | () if let 0 = 1 => {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if`- and `while`-expressions - = note: as well as when nested within `&&` and parenthesis in those conditions - -error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:11:16 + --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} | ^^^^^^^^^ @@ -188,7 +179,7 @@ LL | () if (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:15:18 + --> $DIR/feature-gate.rs:14:18 | LL | () if (((let 0 = 1))) => {} | ^^^^^^^^^ @@ -197,7 +188,7 @@ LL | () if (((let 0 = 1))) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:19:23 + --> $DIR/feature-gate.rs:18:23 | LL | () if true && let 0 = 1 => {} | ^^^^^^^^^ @@ -206,7 +197,7 @@ LL | () if true && let 0 = 1 => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:23:15 + --> $DIR/feature-gate.rs:22:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -215,7 +206,7 @@ LL | () if let 0 = 1 && true => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:27:16 + --> $DIR/feature-gate.rs:26:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -224,7 +215,7 @@ LL | () if (let 0 = 1) && true => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:31:24 + --> $DIR/feature-gate.rs:30:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -233,7 +224,7 @@ LL | () if true && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:35:16 + --> $DIR/feature-gate.rs:34:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -242,7 +233,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:35:31 + --> $DIR/feature-gate.rs:34:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -251,7 +242,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:15 + --> $DIR/feature-gate.rs:40:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -260,7 +251,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:28 + --> $DIR/feature-gate.rs:40:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -269,7 +260,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:42 + --> $DIR/feature-gate.rs:40:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -278,7 +269,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:55 + --> $DIR/feature-gate.rs:40:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -287,7 +278,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:68 + --> $DIR/feature-gate.rs:40:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -296,7 +287,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:53:15 + --> $DIR/feature-gate.rs:52:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -305,7 +296,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:69:16 + --> $DIR/feature-gate.rs:68:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -314,7 +305,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:72:16 + --> $DIR/feature-gate.rs:71:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -322,6 +313,6 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if`- and `while`-expressions = note: as well as when nested within `&&` and parenthesis in those conditions -error: aborting due to 36 previous errors +error: aborting due to 35 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2294-if-let-guard/run-pass.rs b/src/test/ui/rfc-2294-if-let-guard/run-pass.rs new file mode 100644 index 0000000000000..a3663003790f7 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/run-pass.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +enum Foo { + Bar, + Baz, + Qux(u8), +} + +fn bar(x: bool) -> Foo { + if x { Foo::Baz } else { Foo::Bar } +} + +fn baz(x: u8) -> Foo { + if x % 2 == 0 { Foo::Bar } else { Foo::Baz } +} + +fn qux(x: u8) -> Foo { + Foo::Qux(x.rotate_left(1)) +} + +fn main() { + match Some((true, 3)) { + Some((x, _)) if let Foo::Bar = bar(x) => panic!(), + Some((_, x)) if let Foo::Baz = baz(x) => {}, + _ => panic!(), + } + match Some(42) { + Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84), + _ => panic!(), + } +} diff --git a/src/test/ui/rfc-2294-if-let-guard/typeck.rs b/src/test/ui/rfc-2294-if-let-guard/typeck.rs new file mode 100644 index 0000000000000..a4fc7f8cf2b26 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/typeck.rs @@ -0,0 +1,16 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn ok() -> Result, ()> { + Ok(Some(true)) +} + +fn main() { + match ok() { + Ok(x) if let Err(_) = x => {}, + //~^ ERROR mismatched types + Ok(x) if let 0 = x => {}, + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/rfc-2294-if-let-guard/typeck.stderr b/src/test/ui/rfc-2294-if-let-guard/typeck.stderr new file mode 100644 index 0000000000000..7ce93fe7348fd --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/typeck.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/typeck.rs:10:22 + | +LL | Ok(x) if let Err(_) = x => {}, + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` + | + = note: expected enum `Option` + found enum `std::result::Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/typeck.rs:12:22 + | +LL | Ok(x) if let 0 = x => {}, + | ^ expected enum `Option`, found integer + | + = note: expected enum `Option` + found type `{integer}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.rs b/src/test/ui/rfc-2294-if-let-guard/warns.rs new file mode 100644 index 0000000000000..9691a12f45b05 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/warns.rs @@ -0,0 +1,22 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +#[deny(irrefutable_let_patterns)] +fn irrefutable_let_guard() { + match Some(()) { + Some(x) if let () = x => {} + //~^ ERROR irrefutable if-let guard + _ => {} + } +} + +#[deny(unreachable_patterns)] +fn unreachable_pattern() { + match Some(()) { + x if let None | None = x => {} + //~^ ERROR unreachable pattern + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr new file mode 100644 index 0000000000000..45720f9fbc551 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr @@ -0,0 +1,26 @@ +error: irrefutable if-let guard + --> $DIR/warns.rs:7:24 + | +LL | Some(x) if let () = x => {} + | ^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:4:8 + | +LL | #[deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/warns.rs:16:25 + | +LL | x if let None | None = x => {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:13:8 + | +LL | #[deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs index abd603b356ee6..0c40f8ae1c67e 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs @@ -63,7 +63,11 @@ fn multiple3() { } #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels pub const fn multiple4() { } -//~^ ERROR Invalid stability or deprecation version found +//~^ ERROR Invalid stability version found + +#[stable(feature = "a", since = "1.0.0")] +#[rustc_deprecated(since = "invalid", reason = "text")] +fn invalid_deprecation_version() {} //~ ERROR Invalid deprecation version found #[rustc_deprecated(since = "a", reason = "text")] fn deprecated_without_unstable_or_stable() { } diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 97089f7df5263..ee9a93359f032 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -96,19 +96,25 @@ error[E0544]: multiple stability levels LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Invalid stability or deprecation version found +error: Invalid stability version found --> $DIR/stability-attribute-sanity.rs:65:1 | LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: Invalid deprecation version found + --> $DIR/stability-attribute-sanity.rs:70:1 + | +LL | fn invalid_deprecation_version() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:68:1 + --> $DIR/stability-attribute-sanity.rs:72:1 | LL | #[rustc_deprecated(since = "a", reason = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: aborting due to 19 previous errors Some errors have detailed explanations: E0539, E0541, E0546, E0550. For more information about an error, try `rustc --explain E0539`. diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 225fe58906f73..f839659267825 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -342,6 +342,10 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut if let Some(ref guard) = arm.guard { match guard { Guard::If(if_expr) => check_expr(cx, if_expr, bindings), + Guard::IfLet(guard_pat, guard_expr) => { + check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings); + check_expr(cx, guard_expr, bindings); + }, } } check_expr(cx, &arm.body, bindings); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 7250de3a41c04..4249dbb4e6519 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -372,6 +372,18 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = if_expr_pat; self.visit_expr(if_expr); }, + hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => { + let if_let_pat_pat = self.next("pat"); + let if_let_expr_pat = self.next("expr"); + println!( + " if let Guard::IfLet(ref {}, ref {}) = {};", + if_let_pat_pat, if_let_expr_pat, guard_pat + ); + self.current = if_let_expr_pat; + self.visit_expr(if_let_expr); + self.current = if_let_pat_pat; + self.visit_pat(if_let_pat); + }, } } self.current = format!("{}[{}].pat", arms_pat, i); @@ -730,6 +742,7 @@ fn desugaring_name(des: hir::MatchSource) -> String { "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", contains_else_clause ), + hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(), hir::MatchSource::IfDesugar { contains_else_clause } => format!( "MatchSource::IfDesugar {{ contains_else_clause: {} }}", contains_else_clause diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index d942d4e12b106..a8fbb2ffaf0b4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -169,6 +169,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool { match (left, right) { (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r), + (Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re), + _ => false, } } @@ -669,7 +671,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_guard(&mut self, g: &Guard<'_>) { match g { - Guard::If(ref expr) => { + Guard::If(ref expr) | Guard::IfLet(_, ref expr) => { self.hash_expr(expr); }, } diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 323d874553885..5d946e4bd495d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -560,5 +560,10 @@ fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) { println!("{}If", ind); print_expr(cx, expr, indent + 1); }, + hir::Guard::IfLet(pat, expr) => { + println!("{}IfLet", ind); + print_pat(cx, pat, indent + 1); + print_expr(cx, expr, indent + 1); + }, } } diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs index f7ff64036a1a9..f8cf18a9309ec 100644 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ b/src/tools/expand-yaml-anchors/src/main.rs @@ -87,7 +87,8 @@ impl App { let content = std::fs::read_to_string(source) .with_context(|| format!("failed to read {}", self.path(source)))?; - let mut buf = HEADER_MESSAGE.replace("{source}", &self.path(source).to_string()); + let mut buf = + HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/")); let documents = YamlLoader::load_from_str(&content) .with_context(|| format!("failed to parse {}", self.path(source)))?;