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:
commit
9b84d36a0b
64 changed files with 633 additions and 285 deletions
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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 => "?",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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("=>");
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue