Auto merge of #80105 - JohnTitor:rollup-8c030u5, r=JohnTitor

Rollup of 11 pull requests

Successful merges:

 - #79051 (Implement if-let match guards)
 - #79877 (Allow `since="TBD"` for rustc_deprecated)
 - #79882 (Fix issue #78496)
 - #80026 (expand-yaml-anchors: Make the output directory separator-insensitive)
 - #80039 (Remove unused `TyEncoder::tcx` required method)
 - #80069 (Test that `core::assert!` is valid)
 - #80072 (Fixed conflict with drop elaboration and coverage)
 - #80073 (Add support for target aliases)
 - #80082 (Revert #78790 - rust-src vendoring)
 - #80097 (Add `popcount` and `popcnt` as doc aliases for `count_ones` methods.)
 - #80103 (Remove docs for non-existent parameters in `rustc_expand`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2020-12-17 03:07:09 +00:00
commit 9b84d36a0b
64 changed files with 633 additions and 285 deletions

View File

@ -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,
}

View File

@ -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
///

View File

@ -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 => "?",

View File

@ -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);

View File

@ -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("=>");

View File

@ -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<Ty<'tcx>, usize> {
&mut self.type_shorthands
}

View File

@ -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<u32> {
// 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<u32> = parse_version(&since);
let rustc: Vec<u32> = 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<u32> = parse_version(&since);
let rustc: Vec<u32> = 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,
)
};

View File

@ -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<Ty<'tcx>, usize>;
fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize>;

View File

@ -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()
}

View File

@ -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.

View File

@ -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

View File

@ -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<Span>,
arm_scope: Option<region::Scope>,
) -> 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<Span>,
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);

View File

@ -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),
);

View File

@ -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 },

View File

@ -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)]

View File

@ -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);
}

View File

@ -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(

View File

@ -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);
}

View File

@ -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::<u64>(), 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::<u64>() {
Err(_) => {
self.tcx.sess.span_err(item_sp, "Invalid stability version found");
break;
}
Ok(stab_vp) => match dep_v.parse::<u64>() {
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;
},
}
}
}

View File

@ -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()),
}
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/40531>.)
("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.

View File

@ -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<hir::Mutability>,
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<hir::Mutability> {
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,
})
}

View File

@ -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 =

View File

@ -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() }
}

View File

@ -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

View File

@ -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()

View File

@ -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);

View File

@ -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 {

View File

@ -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))
}

View File

@ -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=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 18:1-20:2<br/> 19:5-19:9: @0[0]: _0 = const true<br/> 20:2-20:2: @0.Return: return</td></tr><tr><td align="left" balign="left">bb0: Return</td></tr></table>>];
bcb0__Cov_0_4 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 18:1-20:2<br/> 19:5-19:9: @0[0]: Coverage::Counter(1) for $DIR/coverage_graphviz.rs:18:1 - 20:2<br/> 20:2-20:2: @0.Return: return</td></tr><tr><td align="left" balign="left">bb0: Return</td></tr></table>>];
}

View File

@ -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=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb0 - bcb1) at 13:10-13:10<br/> 13:10-13:10: @4[0]: _1 = const ()</td></tr><tr><td align="left" balign="left">bb4: Goto</td></tr></table>>];
bcb2__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb2</td></tr><tr><td align="left" balign="left">Expression(bcb0 - bcb1) at 13:10-13:10<br/> 13:10-13:10: @4[0]: Coverage::Expression(4294967295) = 1 - 2 for $DIR/coverage_graphviz.rs:13:10 - 13:11</td></tr><tr><td align="left" balign="left">bb4: Goto</td></tr></table>>];
bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Counter(bcb1) at 12:13-12:18<br/> 12:13-12:18: @5[0]: _0 = const ()<br/>Expression(bcb1 + 0) at 15:2-15:2<br/> 15:2-15:2: @5.Return: return</td></tr><tr><td align="left" balign="left">bb3: FalseEdge</td></tr><tr><td align="left" balign="left">bb5: Return</td></tr></table>>];
bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-11:17<br/> 11:12-11:17: @1.Call: _2 = bar() -&gt; [return: bb2, unwind: bb6]<br/> 11:12-11:17: @2[0]: FakeRead(ForMatchedPlace, _2)</td></tr><tr><td align="left" balign="left">bb0: FalseUnwind<br/>bb1: Call</td></tr><tr><td align="left" balign="left">bb2: SwitchInt</td></tr></table>>];
bcb2__Cov_0_3 -> bcb0__Cov_0_3 [label=<>];

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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|}

View File

@ -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|}

View File

@ -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|}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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); }

View File

@ -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`
}

View File

@ -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`.

View File

@ -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

View File

@ -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`.

View File

@ -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!(),
}
}

View File

@ -0,0 +1,16 @@
#![feature(if_let_guard)]
#![allow(incomplete_features)]
fn ok() -> Result<Option<bool>, ()> {
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
_ => {}
}
}

View File

@ -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<bool>`
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<bool>`
found type `{integer}`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -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() {}

View File

@ -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

View File

@ -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() { }

View File

@ -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`.

View File

@ -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);

View File

@ -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

View File

@ -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);
},
}

View File

@ -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);
},
}
}

View File

@ -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)))?;