Auto merge of #81271 - m-ou-se:rollup-xv7gq3w, r=m-ou-se
Rollup of 10 pull requests Successful merges: - #80573 (Deny rustc::internal lints for rustdoc and clippy) - #81173 (Expand docs on Iterator::intersperse) - #81194 (Stabilize std::panic::panic_any.) - #81202 (Don't prefix 0x for each segments in `dbg!(Ipv6)`) - #81225 (Make 'docs' nullable in rustdoc-json output) - #81227 (Remove doctree::StructType) - #81233 (Document why not use concat! in dbg! macro) - #81236 (Gracefully handle loop labels missing leading `'` in different positions) - #81241 (Turn alloc's force_expr macro into a regular macro_rules.) - #81242 (Enforce statically that `MIN_NON_ZERO_CAP` is calculated at compile time) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b814b63983
59 changed files with 682 additions and 267 deletions
|
@ -10,9 +10,9 @@ use rustc_errors::struct_span_err;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::hygiene::ForLoopLoc;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
|
||||
use rustc_target::asm;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::Write;
|
||||
|
@ -102,6 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.lower_block(body, false),
|
||||
opt_label,
|
||||
hir::LoopSource::Loop,
|
||||
DUMMY_SP,
|
||||
)
|
||||
}),
|
||||
ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
|
||||
|
@ -453,7 +454,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
|
||||
|
||||
// `[opt_ident]: loop { ... }`
|
||||
hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source)
|
||||
hir::ExprKind::Loop(
|
||||
self.block_expr(self.arena.alloc(match_expr)),
|
||||
opt_label,
|
||||
source,
|
||||
span.with_hi(cond.span.hi()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
|
||||
|
@ -748,7 +754,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// loop { .. }
|
||||
let loop_expr = self.arena.alloc(hir::Expr {
|
||||
hir_id: loop_hir_id,
|
||||
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop),
|
||||
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span),
|
||||
span,
|
||||
attrs: ThinVec::new(),
|
||||
});
|
||||
|
@ -1709,7 +1715,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
|
||||
// `[opt_ident]: loop { ... }`
|
||||
let kind = hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::ForLoop);
|
||||
let kind = hir::ExprKind::Loop(
|
||||
loop_block,
|
||||
opt_label,
|
||||
hir::LoopSource::ForLoop,
|
||||
e.span.with_hi(orig_head_span.hi()),
|
||||
);
|
||||
let loop_expr = self.arena.alloc(hir::Expr {
|
||||
hir_id: self.lower_node_id(e.id),
|
||||
kind,
|
||||
|
|
|
@ -1617,7 +1617,9 @@ pub enum ExprKind<'hir> {
|
|||
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||
///
|
||||
/// I.e., `'label: loop { <block> }`.
|
||||
Loop(&'hir Block<'hir>, Option<Label>, LoopSource),
|
||||
///
|
||||
/// The `Span` is the loop header (`for x in y`/`while let pat = expr`).
|
||||
Loop(&'hir Block<'hir>, Option<Label>, LoopSource, Span),
|
||||
/// A `match` block, with a source that indicates whether or not it is
|
||||
/// the result of a desugaring, and if so, which kind.
|
||||
Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
|
||||
|
|
|
@ -1151,7 +1151,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
visitor.visit_expr(then);
|
||||
walk_list!(visitor, visit_expr, else_opt);
|
||||
}
|
||||
ExprKind::Loop(ref block, ref opt_label, _) => {
|
||||
ExprKind::Loop(ref block, ref opt_label, _, _) => {
|
||||
walk_list!(visitor, visit_label, opt_label);
|
||||
visitor.visit_block(block);
|
||||
}
|
||||
|
|
|
@ -1396,7 +1396,7 @@ impl<'a> State<'a> {
|
|||
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
||||
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
|
||||
}
|
||||
hir::ExprKind::Loop(ref blk, opt_label, _) => {
|
||||
hir::ExprKind::Loop(ref blk, opt_label, _, _) => {
|
||||
if let Some(label) = opt_label {
|
||||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
|
|
|
@ -96,18 +96,24 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
|
|||
|
||||
impl EarlyLintPass for WhileTrue {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
if let ast::ExprKind::While(cond, ..) = &e.kind {
|
||||
if let ast::ExprKind::While(cond, _, label) = &e.kind {
|
||||
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
|
||||
if let ast::LitKind::Bool(true) = lit.kind {
|
||||
if !lit.span.from_expansion() {
|
||||
let msg = "denote infinite loops with `loop { ... }`";
|
||||
let condition_span = cx.sess.source_map().guess_head_span(e.span);
|
||||
let condition_span = e.span.with_hi(cond.span.hi());
|
||||
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
|
||||
lint.build(msg)
|
||||
.span_suggestion_short(
|
||||
condition_span,
|
||||
"use `loop`",
|
||||
"loop".to_owned(),
|
||||
format!(
|
||||
"{}loop",
|
||||
label.map_or_else(String::new, |label| format!(
|
||||
"{}: ",
|
||||
label.ident,
|
||||
))
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
|
|
@ -546,9 +546,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
|||
scrutinee: discr.to_ref(),
|
||||
arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
|
||||
},
|
||||
hir::ExprKind::Loop(ref body, _, _) => {
|
||||
ExprKind::Loop { body: block::to_expr_ref(cx, body) }
|
||||
}
|
||||
hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) },
|
||||
hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
|
||||
lhs: source.to_ref(),
|
||||
name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
|
||||
|
|
|
@ -585,7 +585,7 @@ impl<'a> Parser<'a> {
|
|||
lhs_span: Span,
|
||||
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let mk_expr = |this: &mut Self, rhs: P<Ty>| {
|
||||
let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
|
||||
this.mk_expr(
|
||||
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
|
||||
expr_kind(lhs, rhs),
|
||||
|
@ -597,13 +597,49 @@ impl<'a> Parser<'a> {
|
|||
// LessThan comparison after this cast.
|
||||
let parser_snapshot_before_type = self.clone();
|
||||
let cast_expr = match self.parse_ty_no_plus() {
|
||||
Ok(rhs) => mk_expr(self, rhs),
|
||||
Ok(rhs) => mk_expr(self, lhs, rhs),
|
||||
Err(mut type_err) => {
|
||||
// Rewind to before attempting to parse the type with generics, to recover
|
||||
// from situations like `x as usize < y` in which we first tried to parse
|
||||
// `usize < y` as a type with generic arguments.
|
||||
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
|
||||
|
||||
// Check for typo of `'a: loop { break 'a }` with a missing `'`.
|
||||
match (&lhs.kind, &self.token.kind) {
|
||||
(
|
||||
// `foo: `
|
||||
ExprKind::Path(None, ast::Path { segments, .. }),
|
||||
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
|
||||
) if segments.len() == 1 => {
|
||||
let snapshot = self.clone();
|
||||
let label = Label {
|
||||
ident: Ident::from_str_and_span(
|
||||
&format!("'{}", segments[0].ident),
|
||||
segments[0].ident.span,
|
||||
),
|
||||
};
|
||||
match self.parse_labeled_expr(label, AttrVec::new(), false) {
|
||||
Ok(expr) => {
|
||||
type_err.cancel();
|
||||
self.struct_span_err(label.ident.span, "malformed loop label")
|
||||
.span_suggestion(
|
||||
label.ident.span,
|
||||
"use the correct loop label format",
|
||||
label.ident.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
return Ok(expr);
|
||||
}
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
*self = snapshot;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.parse_path(PathStyle::Expr) {
|
||||
Ok(path) => {
|
||||
let (op_noun, op_verb) = match self.token.kind {
|
||||
|
@ -630,7 +666,8 @@ impl<'a> Parser<'a> {
|
|||
op_noun,
|
||||
);
|
||||
let span_after_type = parser_snapshot_after_type.token.span;
|
||||
let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||
let expr =
|
||||
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||
|
||||
let expr_str = self
|
||||
.span_to_snippet(expr.span)
|
||||
|
@ -1067,7 +1104,7 @@ impl<'a> Parser<'a> {
|
|||
} else if self.eat_keyword(kw::While) {
|
||||
self.parse_while_expr(None, self.prev_token.span, attrs)
|
||||
} else if let Some(label) = self.eat_label() {
|
||||
self.parse_labeled_expr(label, attrs)
|
||||
self.parse_labeled_expr(label, attrs, true)
|
||||
} else if self.eat_keyword(kw::Loop) {
|
||||
self.parse_loop_expr(None, self.prev_token.span, attrs)
|
||||
} else if self.eat_keyword(kw::Continue) {
|
||||
|
@ -1228,7 +1265,12 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Parse `'label: $expr`. The label is already parsed.
|
||||
fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
fn parse_labeled_expr(
|
||||
&mut self,
|
||||
label: Label,
|
||||
attrs: AttrVec,
|
||||
consume_colon: bool,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let lo = label.ident.span;
|
||||
let label = Some(label);
|
||||
let ate_colon = self.eat(&token::Colon);
|
||||
|
@ -1247,7 +1289,7 @@ impl<'a> Parser<'a> {
|
|||
self.parse_expr()
|
||||
}?;
|
||||
|
||||
if !ate_colon {
|
||||
if !ate_colon && consume_colon {
|
||||
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
|||
// Skip the following checks if we are not currently in a const context.
|
||||
_ if self.const_kind.is_none() => {}
|
||||
|
||||
hir::ExprKind::Loop(_, _, source) => {
|
||||
hir::ExprKind::Loop(_, _, source, _) => {
|
||||
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
|
||||
}
|
||||
|
||||
|
|
|
@ -844,7 +844,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
|
||||
// Note that labels have been resolved, so we don't need to look
|
||||
// at the label ident
|
||||
hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ),
|
||||
hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
|
||||
|
||||
hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||
//
|
||||
|
|
|
@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
match e.kind {
|
||||
hir::ExprKind::Loop(ref b, _, source) => {
|
||||
hir::ExprKind::Loop(ref b, _, source, _) => {
|
||||
self.with_context(Loop(source), |v| v.visit_block(&b));
|
||||
}
|
||||
hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
|
||||
|
@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
hir::ExprKind::Block(ref b, Some(_label)) => {
|
||||
self.with_context(LabeledBlock, |v| v.visit_block(&b));
|
||||
}
|
||||
hir::ExprKind::Break(label, ref opt_expr) => {
|
||||
hir::ExprKind::Break(break_label, ref opt_expr) => {
|
||||
if let Some(e) = opt_expr {
|
||||
self.visit_expr(e);
|
||||
}
|
||||
|
||||
if self.require_label_in_labeled_block(e.span, &label, "break") {
|
||||
if self.require_label_in_labeled_block(e.span, &break_label, "break") {
|
||||
// If we emitted an error about an unlabeled break in a labeled
|
||||
// block, we don't need any further checking for this break any more
|
||||
return;
|
||||
}
|
||||
|
||||
let loop_id = match label.target_id {
|
||||
let loop_id = match break_label.target_id {
|
||||
Ok(loop_id) => Some(loop_id),
|
||||
Err(hir::LoopIdError::OutsideLoopScope) => None,
|
||||
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
|
||||
|
@ -89,49 +89,89 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
Err(hir::LoopIdError::UnresolvedLabel) => None,
|
||||
};
|
||||
|
||||
if let Some(loop_id) = loop_id {
|
||||
if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
|
||||
return;
|
||||
}
|
||||
if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if opt_expr.is_some() {
|
||||
let loop_kind = if let Some(loop_id) = loop_id {
|
||||
Some(match self.hir_map.expect_expr(loop_id).kind {
|
||||
hir::ExprKind::Loop(_, _, source) => source,
|
||||
if let Some(break_expr) = opt_expr {
|
||||
let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id {
|
||||
match self.hir_map.expect_expr(loop_id).kind {
|
||||
hir::ExprKind::Loop(_, label, source, sp) => {
|
||||
(Some(sp), label, Some(source))
|
||||
}
|
||||
ref r => {
|
||||
span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
None
|
||||
(None, None, None)
|
||||
};
|
||||
match loop_kind {
|
||||
None | Some(hir::LoopSource::Loop) => (),
|
||||
Some(kind) => {
|
||||
struct_span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
e.span,
|
||||
E0571,
|
||||
"`break` with value from a `{}` loop",
|
||||
kind.name()
|
||||
)
|
||||
.span_label(
|
||||
);
|
||||
err.span_label(
|
||||
e.span,
|
||||
"can only break with a value inside \
|
||||
`loop` or breakable block",
|
||||
)
|
||||
.span_suggestion(
|
||||
"can only break with a value inside `loop` or breakable block",
|
||||
);
|
||||
if let Some(head) = head {
|
||||
err.span_label(
|
||||
head,
|
||||
&format!(
|
||||
"you can't `break` with a value in a `{}` loop",
|
||||
kind.name()
|
||||
),
|
||||
);
|
||||
}
|
||||
err.span_suggestion(
|
||||
e.span,
|
||||
&format!(
|
||||
"instead, use `break` on its own \
|
||||
without a value inside this `{}` loop",
|
||||
kind.name()
|
||||
"use `break` on its own without a value inside this `{}` loop",
|
||||
kind.name(),
|
||||
),
|
||||
format!(
|
||||
"break{}",
|
||||
break_label
|
||||
.label
|
||||
.map_or_else(String::new, |l| format!(" {}", l.ident))
|
||||
),
|
||||
"break".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
if let (Some(label), None) = (loop_label, break_label.label) {
|
||||
match break_expr.kind {
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
hir::Path {
|
||||
segments: [segment],
|
||||
res: hir::def::Res::Err,
|
||||
..
|
||||
},
|
||||
)) if label.ident.to_string()
|
||||
== format!("'{}", segment.ident) =>
|
||||
{
|
||||
// This error is redundant, we will have already emitted a
|
||||
// suggestion to use the label when `segment` wasn't found
|
||||
// (hence the `Res::Err` check).
|
||||
err.delay_as_bug();
|
||||
}
|
||||
_ => {
|
||||
err.span_suggestion(
|
||||
break_expr.span,
|
||||
"alternatively, you might have meant to use the \
|
||||
available loop label",
|
||||
label.ident.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
terminating(then.hir_id.local_id);
|
||||
}
|
||||
|
||||
hir::ExprKind::Loop(ref body, _, _) => {
|
||||
hir::ExprKind::Loop(ref body, _, _, _) => {
|
||||
terminating(body.hir_id.local_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -2266,6 +2266,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Break(None, Some(ref e)) => {
|
||||
// We use this instead of `visit::walk_expr` to keep the parent expr around for
|
||||
// better diagnostics.
|
||||
self.resolve_expr(e, Some(&expr));
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
self.visit_expr(scrutinee);
|
||||
self.resolve_pattern_top(pat, PatternSource::Let);
|
||||
|
|
|
@ -545,17 +545,23 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
if let Some(err_code) = &err.code {
|
||||
if err_code == &rustc_errors::error_code!(E0425) {
|
||||
for label_rib in &self.label_ribs {
|
||||
for (label_ident, _) in &label_rib.bindings {
|
||||
for (label_ident, node_id) in &label_rib.bindings {
|
||||
if format!("'{}", ident) == label_ident.to_string() {
|
||||
let msg = "a label with a similar name exists";
|
||||
// FIXME: consider only emitting this suggestion if a label would be valid here
|
||||
// which is pretty much only the case for `break` expressions.
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&msg,
|
||||
label_ident.name.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.span_label(label_ident.span, "a label with a similar name exists");
|
||||
if let PathSource::Expr(Some(Expr {
|
||||
kind: ExprKind::Break(None, Some(_)),
|
||||
..
|
||||
})) = source
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use the similarly named label",
|
||||
label_ident.name.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
// Do not lint against unused label when we suggest them.
|
||||
self.diagnostic_metadata.unused_labels.remove(node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1173,7 +1173,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
|
|||
}
|
||||
|
||||
fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
|
||||
if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None }
|
||||
if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None }
|
||||
}
|
||||
|
||||
fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
|
||||
|
|
|
@ -266,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
|
||||
ExprKind::Loop(ref body, _, source) => {
|
||||
ExprKind::Loop(ref body, _, source, _) => {
|
||||
self.check_expr_loop(body, source, expected, expr)
|
||||
}
|
||||
ExprKind::Match(ref discrim, ref arms, match_src) => {
|
||||
|
|
|
@ -289,7 +289,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
| hir::ExprKind::ConstBlock(..)
|
||||
| hir::ExprKind::Err => {}
|
||||
|
||||
hir::ExprKind::Loop(ref blk, _, _) => {
|
||||
hir::ExprKind::Loop(ref blk, ..) => {
|
||||
self.walk_block(blk);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,11 +189,4 @@ pub mod vec;
|
|||
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
|
||||
pub mod __export {
|
||||
pub use core::format_args;
|
||||
|
||||
/// Force AST node to an expression to improve diagnostics in pattern position.
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
|
||||
pub macro force_expr($e:expr) {
|
||||
$e
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,13 +40,13 @@
|
|||
#[allow_internal_unstable(box_syntax, liballoc_internals)]
|
||||
macro_rules! vec {
|
||||
() => (
|
||||
$crate::__export::force_expr!($crate::vec::Vec::new())
|
||||
$crate::__rust_force_expr!($crate::vec::Vec::new())
|
||||
);
|
||||
($elem:expr; $n:expr) => (
|
||||
$crate::__export::force_expr!($crate::vec::from_elem($elem, $n))
|
||||
$crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
|
||||
);
|
||||
($($x:expr),+ $(,)?) => (
|
||||
$crate::__export::force_expr!(<[_]>::into_vec(box [$($x),+]))
|
||||
$crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -111,3 +111,13 @@ macro_rules! format {
|
|||
res
|
||||
}}
|
||||
}
|
||||
|
||||
/// Force AST node to an expression to improve diagnostics in pattern position.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
|
||||
macro_rules! __rust_force_expr {
|
||||
($e:expr) => {
|
||||
$e
|
||||
};
|
||||
}
|
||||
|
|
|
@ -114,6 +114,19 @@ impl<T> RawVec<T, Global> {
|
|||
}
|
||||
|
||||
impl<T, A: Allocator> RawVec<T, A> {
|
||||
// Tiny Vecs are dumb. Skip to:
|
||||
// - 8 if the element size is 1, because any heap allocators is likely
|
||||
// to round up a request of less than 8 bytes to at least 8 bytes.
|
||||
// - 4 if elements are moderate-sized (<= 1 KiB).
|
||||
// - 1 otherwise, to avoid wasting too much space for very short Vecs.
|
||||
const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
|
||||
8
|
||||
} else if mem::size_of::<T>() <= 1024 {
|
||||
4
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
/// Like `new`, but parameterized over the choice of allocator for
|
||||
/// the returned `RawVec`.
|
||||
#[rustc_allow_const_fn_unstable(const_fn)]
|
||||
|
@ -399,22 +412,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
// This guarantees exponential growth. The doubling cannot overflow
|
||||
// because `cap <= isize::MAX` and the type of `cap` is `usize`.
|
||||
let cap = cmp::max(self.cap * 2, required_cap);
|
||||
|
||||
// Tiny Vecs are dumb. Skip to:
|
||||
// - 8 if the element size is 1, because any heap allocators is likely
|
||||
// to round up a request of less than 8 bytes to at least 8 bytes.
|
||||
// - 4 if elements are moderate-sized (<= 1 KiB).
|
||||
// - 1 otherwise, to avoid wasting too much space for very short Vecs.
|
||||
// Note that `min_non_zero_cap` is computed statically.
|
||||
let elem_size = mem::size_of::<T>();
|
||||
let min_non_zero_cap = if elem_size == 1 {
|
||||
8
|
||||
} else if elem_size <= 1024 {
|
||||
4
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let cap = cmp::max(min_non_zero_cap, cap);
|
||||
let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
|
||||
|
||||
let new_layout = Layout::array::<T>(cap);
|
||||
|
||||
|
|
|
@ -151,12 +151,10 @@ where
|
|||
{
|
||||
let (lo, hi) = iter.size_hint();
|
||||
let next_is_elem = !needs_sep;
|
||||
let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
|
||||
let hi = match hi {
|
||||
Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
|
||||
None => None,
|
||||
};
|
||||
(lo, hi)
|
||||
(
|
||||
lo.saturating_sub(next_is_elem as usize).saturating_add(lo),
|
||||
hi.and_then(|hi| hi.saturating_sub(next_is_elem as usize).checked_add(hi)),
|
||||
)
|
||||
}
|
||||
|
||||
fn intersperse_fold<I, B, F, G>(
|
||||
|
|
|
@ -567,9 +567,10 @@ pub trait Iterator {
|
|||
Zip::new(self, other.into_iter())
|
||||
}
|
||||
|
||||
/// Places a copy of `separator` between all elements.
|
||||
/// Creates a new iterator which places a copy of `separator` between adjacent
|
||||
/// items of the original iterator.
|
||||
///
|
||||
/// In case the separator does not implement [`Clone`] or needs to be
|
||||
/// In case `separator` does not implement [`Clone`] or needs to be
|
||||
/// computed every time, use [`intersperse_with`].
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -579,6 +580,19 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// #![feature(iter_intersperse)]
|
||||
///
|
||||
/// let mut a = [0, 1, 2].iter().intersperse(&100);
|
||||
/// assert_eq!(a.next(), Some(&0)); // The first element from `a`.
|
||||
/// assert_eq!(a.next(), Some(&100)); // The separator.
|
||||
/// assert_eq!(a.next(), Some(&1)); // The next element from `a`.
|
||||
/// assert_eq!(a.next(), Some(&100)); // The separator.
|
||||
/// assert_eq!(a.next(), Some(&2)); // The last element from `a`.
|
||||
/// assert_eq!(a.next(), None); // The iterator is finished.
|
||||
/// ```
|
||||
///
|
||||
/// `intersperse` can be very useful to join an iterator's items using a common element:
|
||||
/// ```
|
||||
/// #![feature(iter_intersperse)]
|
||||
///
|
||||
/// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::<String>();
|
||||
/// assert_eq!(hello, "Hello World !");
|
||||
/// ```
|
||||
|
@ -595,7 +609,16 @@ pub trait Iterator {
|
|||
Intersperse::new(self, separator)
|
||||
}
|
||||
|
||||
/// Places an element generated by `separator` between all elements.
|
||||
/// Creates a new iterator which places an item generated by `separator`
|
||||
/// between adjacent items of the original iterator.
|
||||
///
|
||||
/// The closure will be called exactly once each time an item is placed
|
||||
/// between two adjacent items from the underlying iterator; specifically,
|
||||
/// the closure is not called if the underlying iterator yields less than
|
||||
/// two items and after the last item is yielded.
|
||||
///
|
||||
/// If the iterator's item implements [`Clone`], it may be easier to use
|
||||
/// [`intersperse`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -604,14 +627,36 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// #![feature(iter_intersperse)]
|
||||
///
|
||||
/// #[derive(PartialEq, Debug)]
|
||||
/// struct NotClone(usize);
|
||||
///
|
||||
/// let v = vec![NotClone(0), NotClone(1), NotClone(2)];
|
||||
/// let mut it = v.into_iter().intersperse_with(|| NotClone(99));
|
||||
///
|
||||
/// assert_eq!(it.next(), Some(NotClone(0))); // The first element from `v`.
|
||||
/// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
|
||||
/// assert_eq!(it.next(), Some(NotClone(1))); // The next element from `v`.
|
||||
/// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
|
||||
/// assert_eq!(it.next(), Some(NotClone(2))); // The last element from from `v`.
|
||||
/// assert_eq!(it.next(), None); // The iterator is finished.
|
||||
/// ```
|
||||
///
|
||||
/// `intersperse_with` can be used in situations where the separator needs
|
||||
/// to be computed:
|
||||
/// ```
|
||||
/// #![feature(iter_intersperse)]
|
||||
///
|
||||
/// let src = ["Hello", "to", "all", "people", "!!"].iter().copied();
|
||||
///
|
||||
/// // The closure mutably borrows its context to generate an item.
|
||||
/// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied();
|
||||
/// let separator = || happy_emojis.next().unwrap_or(" 🦀 ");
|
||||
///
|
||||
/// let result = src.intersperse_with(separator).collect::<String>();
|
||||
/// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!");
|
||||
/// ```
|
||||
/// [`Clone`]: crate::clone::Clone
|
||||
/// [`intersperse`]: Iterator::intersperse
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
|
||||
fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
|
||||
|
|
|
@ -282,6 +282,10 @@ macro_rules! eprintln {
|
|||
#[macro_export]
|
||||
#[stable(feature = "dbg_macro", since = "1.32.0")]
|
||||
macro_rules! dbg {
|
||||
// NOTE: We cannot use `concat!` to make a static string as a format argument
|
||||
// of `eprintln!` because `file!` could contain a `{` or
|
||||
// `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
|
||||
// will be malformed.
|
||||
() => {
|
||||
$crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
|
||||
};
|
||||
|
|
|
@ -1610,11 +1610,11 @@ impl fmt::Display for Ipv6Addr {
|
|||
/// Write a colon-separated part of the address
|
||||
#[inline]
|
||||
fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
|
||||
if let Some(first) = chunk.first() {
|
||||
fmt::LowerHex::fmt(first, f)?;
|
||||
for segment in &chunk[1..] {
|
||||
if let Some((first, tail)) = chunk.split_first() {
|
||||
write!(f, "{:x}", first)?;
|
||||
for segment in tail {
|
||||
f.write_char(':')?;
|
||||
fmt::LowerHex::fmt(segment, f)?;
|
||||
write!(f, "{:x}", segment)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -166,6 +166,9 @@ fn ipv6_addr_to_string() {
|
|||
|
||||
// two runs of zeros, equal length
|
||||
assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
|
||||
|
||||
// don't prefix `0x` to each segment in `dbg!`.
|
||||
assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -31,9 +31,9 @@ pub use core::panic::{Location, PanicInfo};
|
|||
/// accessed later using [`PanicInfo::payload`].
|
||||
///
|
||||
/// See the [`panic!`] macro for more information about panicking.
|
||||
#[unstable(feature = "panic_any", issue = "78500")]
|
||||
#[stable(feature = "panic_any", since = "1.51.0")]
|
||||
#[inline]
|
||||
pub fn panic_any<M: Any + Send>(msg: M) -> ! {
|
||||
pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
|
||||
crate::panicking::begin_panic(msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -320,6 +320,13 @@ macro_rules! tool_check_step {
|
|||
cargo.arg("--all-targets");
|
||||
}
|
||||
|
||||
// Enable internal lints for clippy and rustdoc
|
||||
// NOTE: this intentionally doesn't enable lints for any other tools,
|
||||
// see https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
|
||||
if $path == "src/tools/rustdoc" || $path == "src/tools/clippy" {
|
||||
cargo.rustflag("-Zunstable-options");
|
||||
}
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} {} artifacts ({} -> {})",
|
||||
builder.top_stage,
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::iter::once;
|
|||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_metadata::creader::LoadedMacro;
|
||||
|
@ -17,7 +17,6 @@ use rustc_span::Span;
|
|||
|
||||
use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind};
|
||||
use crate::core::DocContext;
|
||||
use crate::doctree;
|
||||
|
||||
use super::Clean;
|
||||
|
||||
|
@ -246,11 +245,7 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
|
|||
let variant = cx.tcx.adt_def(did).non_enum_variant();
|
||||
|
||||
clean::Struct {
|
||||
struct_type: match variant.ctor_kind {
|
||||
CtorKind::Fictive => doctree::Plain,
|
||||
CtorKind::Fn => doctree::Tuple,
|
||||
CtorKind::Const => doctree::Unit,
|
||||
},
|
||||
struct_type: variant.ctor_kind,
|
||||
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
|
||||
fields: variant.fields.clean(cx),
|
||||
fields_stripped: false,
|
||||
|
@ -262,7 +257,6 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
|
|||
let variant = cx.tcx.adt_def(did).non_enum_variant();
|
||||
|
||||
clean::Union {
|
||||
struct_type: doctree::Plain,
|
||||
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
|
||||
fields: variant.fields.clean(cx),
|
||||
fields_stripped: false,
|
||||
|
|
|
@ -1827,7 +1827,7 @@ impl Clean<Visibility> for ty::Visibility {
|
|||
impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
|
||||
VariantStruct {
|
||||
struct_type: doctree::struct_type_from_def(self),
|
||||
struct_type: CtorKind::from_hir(self),
|
||||
fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
|
||||
fields_stripped: false,
|
||||
}
|
||||
|
@ -1842,7 +1842,7 @@ impl Clean<Item> for ty::VariantDef {
|
|||
self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect(),
|
||||
),
|
||||
CtorKind::Fictive => Variant::Struct(VariantStruct {
|
||||
struct_type: doctree::Plain,
|
||||
struct_type: CtorKind::Fictive,
|
||||
fields_stripped: false,
|
||||
fields: self
|
||||
.fields
|
||||
|
@ -1996,13 +1996,12 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
|
|||
bounds: bounds.clean(cx),
|
||||
}),
|
||||
ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
|
||||
struct_type: doctree::struct_type_from_def(&variant_data),
|
||||
generics: generics.clean(cx),
|
||||
fields: variant_data.fields().clean(cx),
|
||||
fields_stripped: false,
|
||||
}),
|
||||
ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
|
||||
struct_type: doctree::struct_type_from_def(&variant_data),
|
||||
struct_type: CtorKind::from_hir(variant_data),
|
||||
generics: generics.clean(cx),
|
||||
fields: variant_data.fields().clean(cx),
|
||||
fields_stripped: false,
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
|
|||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::Mutability;
|
||||
|
@ -37,7 +37,6 @@ use crate::clean::inline;
|
|||
use crate::clean::types::Type::{QPath, ResolvedPath};
|
||||
use crate::clean::Clean;
|
||||
use crate::core::DocContext;
|
||||
use crate::doctree;
|
||||
use crate::formats::cache::cache;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::render::cache::ExternalLocation;
|
||||
|
@ -1685,7 +1684,7 @@ impl Visibility {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct Struct {
|
||||
crate struct_type: doctree::StructType,
|
||||
crate struct_type: CtorKind,
|
||||
crate generics: Generics,
|
||||
crate fields: Vec<Item>,
|
||||
crate fields_stripped: bool,
|
||||
|
@ -1693,7 +1692,6 @@ crate struct Struct {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct Union {
|
||||
crate struct_type: doctree::StructType,
|
||||
crate generics: Generics,
|
||||
crate fields: Vec<Item>,
|
||||
crate fields_stripped: bool,
|
||||
|
@ -1704,7 +1702,7 @@ crate struct Union {
|
|||
/// only as a variant in an enum.
|
||||
#[derive(Clone, Debug)]
|
||||
crate struct VariantStruct {
|
||||
crate struct_type: doctree::StructType,
|
||||
crate struct_type: CtorKind,
|
||||
crate fields: Vec<Item>,
|
||||
crate fields_stripped: bool,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
|
@ -219,7 +219,7 @@ crate struct RenderOptions {
|
|||
crate extern_html_root_urls: BTreeMap<String, String>,
|
||||
/// A map of the default settings (values are as for DOM storage API). Keys should lack the
|
||||
/// `rustdoc-` prefix.
|
||||
crate default_settings: HashMap<String, String>,
|
||||
crate default_settings: FxHashMap<String, String>,
|
||||
/// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
|
||||
crate resource_suffix: String,
|
||||
/// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{ColorConfig, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
|
@ -16,7 +17,6 @@ use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
|
|||
use rustc_target::spec::TargetTriple;
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::panic;
|
||||
|
@ -704,7 +704,7 @@ crate struct Collector {
|
|||
position: Span,
|
||||
source_map: Option<Lrc<SourceMap>>,
|
||||
filename: Option<PathBuf>,
|
||||
visited_tests: HashMap<(String, usize), usize>,
|
||||
visited_tests: FxHashMap<(String, usize), usize>,
|
||||
}
|
||||
|
||||
impl Collector {
|
||||
|
@ -728,7 +728,7 @@ impl Collector {
|
|||
position: DUMMY_SP,
|
||||
source_map,
|
||||
filename,
|
||||
visited_tests: HashMap::new(),
|
||||
visited_tests: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1010,7 +1010,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
|
|||
self.codes,
|
||||
self.collector.enable_per_target_ignores,
|
||||
Some(&crate::html::markdown::ExtraInfo::new(
|
||||
&self.tcx,
|
||||
self.tcx,
|
||||
hir_id,
|
||||
span_of_attrs(&attrs).unwrap_or(sp),
|
||||
)),
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! This module is used to store stuff from Rust's AST in a more convenient
|
||||
//! manner (and with prettier names) before cleaning.
|
||||
crate use self::StructType::*;
|
||||
|
||||
use rustc_span::{self, Span, Symbol};
|
||||
|
||||
use rustc_hir as hir;
|
||||
|
@ -34,21 +32,3 @@ impl Module<'hir> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
crate enum StructType {
|
||||
/// A braced struct
|
||||
Plain,
|
||||
/// A tuple struct
|
||||
Tuple,
|
||||
/// A unit struct
|
||||
Unit,
|
||||
}
|
||||
|
||||
crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
|
||||
match *vdata {
|
||||
hir::VariantData::Struct(..) => Plain,
|
||||
hir::VariantData::Tuple(..) => Tuple,
|
||||
hir::VariantData::Unit(..) => Unit,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::edition::Edition;
|
||||
|
||||
use crate::clean;
|
||||
|
@ -20,7 +20,7 @@ crate trait FormatRenderer<'tcx>: Clone {
|
|||
render_info: RenderInfo,
|
||||
edition: Edition,
|
||||
cache: &mut Cache,
|
||||
tcx: ty::TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Result<(Self, clean::Crate), Error>;
|
||||
|
||||
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
|
||||
|
@ -55,7 +55,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
|
|||
render_info: RenderInfo,
|
||||
diag: &rustc_errors::Handler,
|
||||
edition: Edition,
|
||||
tcx: ty::TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Result<(), Error> {
|
||||
let (krate, mut cache) = Cache::from_krate(
|
||||
render_info.clone(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
||||
use crate::externalfiles::ExternalHtml;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{Buffer, Print};
|
||||
|
@ -11,7 +12,7 @@ crate struct Layout {
|
|||
crate logo: String,
|
||||
crate favicon: String,
|
||||
crate external_html: ExternalHtml,
|
||||
crate default_settings: HashMap<String, String>,
|
||||
crate default_settings: FxHashMap<String, String>,
|
||||
crate krate: String,
|
||||
/// The given user css file which allow to customize the generated
|
||||
/// documentation theme.
|
||||
|
|
|
@ -620,7 +620,7 @@ crate fn find_testable_code<T: doctest::Tester>(
|
|||
tests: &mut T,
|
||||
error_codes: ErrorCodes,
|
||||
enable_per_target_ignores: bool,
|
||||
extra_info: Option<&ExtraInfo<'_, '_>>,
|
||||
extra_info: Option<&ExtraInfo<'_>>,
|
||||
) {
|
||||
let mut parser = Parser::new(doc).into_offset_iter();
|
||||
let mut prev_offset = 0;
|
||||
|
@ -681,19 +681,19 @@ crate fn find_testable_code<T: doctest::Tester>(
|
|||
}
|
||||
}
|
||||
|
||||
crate struct ExtraInfo<'a, 'b> {
|
||||
crate struct ExtraInfo<'tcx> {
|
||||
hir_id: Option<HirId>,
|
||||
item_did: Option<DefId>,
|
||||
sp: Span,
|
||||
tcx: &'a TyCtxt<'b>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ExtraInfo<'a, 'b> {
|
||||
crate fn new(tcx: &'a TyCtxt<'b>, hir_id: HirId, sp: Span) -> ExtraInfo<'a, 'b> {
|
||||
impl<'tcx> ExtraInfo<'tcx> {
|
||||
crate fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> {
|
||||
ExtraInfo { hir_id: Some(hir_id), item_did: None, sp, tcx }
|
||||
}
|
||||
|
||||
crate fn new_did(tcx: &'a TyCtxt<'b>, did: DefId, sp: Span) -> ExtraInfo<'a, 'b> {
|
||||
crate fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> {
|
||||
ExtraInfo { hir_id: None, item_did: Some(did), sp, tcx }
|
||||
}
|
||||
|
||||
|
@ -775,7 +775,7 @@ impl LangString {
|
|||
string: &str,
|
||||
allow_error_code_check: ErrorCodes,
|
||||
enable_per_target_ignores: bool,
|
||||
extra: Option<&ExtraInfo<'_, '_>>,
|
||||
extra: Option<&ExtraInfo<'_>>,
|
||||
) -> LangString {
|
||||
let allow_error_code_check = allow_error_code_check.as_bool();
|
||||
let mut seen_rust_tags = false;
|
||||
|
@ -1208,7 +1208,7 @@ crate struct RustCodeBlock {
|
|||
|
||||
/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
|
||||
/// untagged (and assumed to be rust).
|
||||
crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_, '_>) -> Vec<RustCodeBlock> {
|
||||
crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeBlock> {
|
||||
let mut code_blocks = vec![];
|
||||
|
||||
if md.is_empty() {
|
||||
|
|
|
@ -52,10 +52,10 @@ use rustc_attr::{Deprecation, StabilityLevel};
|
|||
use rustc_data_structures::flock;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
|
@ -68,7 +68,6 @@ use serde::{Serialize, Serializer};
|
|||
use crate::clean::{self, AttributesExt, GetDefId, RenderedLink, SelfTy, TypeKind};
|
||||
use crate::config::{RenderInfo, RenderOptions};
|
||||
use crate::docfs::{DocFS, PathError};
|
||||
use crate::doctree;
|
||||
use crate::error::Error;
|
||||
use crate::formats::cache::{cache, Cache};
|
||||
use crate::formats::item_type::ItemType;
|
||||
|
@ -390,7 +389,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||
_render_info: RenderInfo,
|
||||
edition: Edition,
|
||||
cache: &mut Cache,
|
||||
tcx: ty::TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Result<(Self, clean::Crate), Error> {
|
||||
// need to save a copy of the options for rendering the index page
|
||||
let md_opts = options.clone();
|
||||
|
@ -3104,7 +3103,7 @@ fn item_struct(
|
|||
_ => None,
|
||||
})
|
||||
.peekable();
|
||||
if let doctree::Plain = s.struct_type {
|
||||
if let CtorKind::Fictive = s.struct_type {
|
||||
if fields.peek().is_some() {
|
||||
write!(
|
||||
w,
|
||||
|
@ -3354,7 +3353,7 @@ fn render_struct(
|
|||
w: &mut Buffer,
|
||||
it: &clean::Item,
|
||||
g: Option<&clean::Generics>,
|
||||
ty: doctree::StructType,
|
||||
ty: CtorKind,
|
||||
fields: &[clean::Item],
|
||||
tab: &str,
|
||||
structhead: bool,
|
||||
|
@ -3371,7 +3370,7 @@ fn render_struct(
|
|||
write!(w, "{}", g.print())
|
||||
}
|
||||
match ty {
|
||||
doctree::Plain => {
|
||||
CtorKind::Fictive => {
|
||||
if let Some(g) = g {
|
||||
write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })
|
||||
}
|
||||
|
@ -3403,7 +3402,7 @@ fn render_struct(
|
|||
}
|
||||
write!(w, "}}");
|
||||
}
|
||||
doctree::Tuple => {
|
||||
CtorKind::Fn => {
|
||||
write!(w, "(");
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
|
@ -3428,7 +3427,7 @@ fn render_struct(
|
|||
}
|
||||
write!(w, ";");
|
||||
}
|
||||
doctree::Unit => {
|
||||
CtorKind::Const => {
|
||||
// Needed for PhantomData.
|
||||
if let Some(g) = g {
|
||||
write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })
|
||||
|
@ -4463,7 +4462,7 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
|
|||
let fields = get_struct_fields_name(&s.fields);
|
||||
|
||||
if !fields.is_empty() {
|
||||
if let doctree::Plain = s.struct_type {
|
||||
if let CtorKind::Fictive = s.struct_type {
|
||||
sidebar.push_str(&format!(
|
||||
"<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
|
||||
<div class=\"sidebar-links\">{}</div>",
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
use std::convert::From;
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_span::Pos;
|
||||
|
||||
use crate::clean;
|
||||
use crate::doctree;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::json::types::*;
|
||||
use crate::json::JsonRenderer;
|
||||
|
@ -27,7 +27,7 @@ impl JsonRenderer<'_> {
|
|||
name: name.map(|sym| sym.to_string()),
|
||||
source: self.convert_span(source),
|
||||
visibility: self.convert_visibility(visibility),
|
||||
docs: attrs.collapsed_doc_value().unwrap_or_default(),
|
||||
docs: attrs.collapsed_doc_value(),
|
||||
links: attrs
|
||||
.links
|
||||
.into_iter()
|
||||
|
@ -210,9 +210,9 @@ impl From<clean::Struct> for Struct {
|
|||
|
||||
impl From<clean::Union> for Struct {
|
||||
fn from(struct_: clean::Union) -> Self {
|
||||
let clean::Union { struct_type, generics, fields, fields_stripped } = struct_;
|
||||
let clean::Union { generics, fields, fields_stripped } = struct_;
|
||||
Struct {
|
||||
struct_type: struct_type.into(),
|
||||
struct_type: StructType::Union,
|
||||
generics: generics.into(),
|
||||
fields_stripped,
|
||||
fields: ids(fields),
|
||||
|
@ -221,13 +221,12 @@ impl From<clean::Union> for Struct {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<doctree::StructType> for StructType {
|
||||
fn from(struct_type: doctree::StructType) -> Self {
|
||||
use doctree::StructType::*;
|
||||
impl From<CtorKind> for StructType {
|
||||
fn from(struct_type: CtorKind) -> Self {
|
||||
match struct_type {
|
||||
Plain => StructType::Plain,
|
||||
Tuple => StructType::Tuple,
|
||||
Unit => StructType::Unit,
|
||||
CtorKind::Fictive => StructType::Plain,
|
||||
CtorKind::Fn => StructType::Tuple,
|
||||
CtorKind::Const => StructType::Unit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
|
||||
|
@ -26,7 +26,7 @@ use crate::html::render::cache::ExternalLocation;
|
|||
|
||||
#[derive(Clone)]
|
||||
crate struct JsonRenderer<'tcx> {
|
||||
tcx: ty::TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// A mapping of IDs that contains all local items for this crate which gets output as a top
|
||||
/// level field of the JSON blob.
|
||||
index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
|
||||
|
@ -131,7 +131,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||
_render_info: RenderInfo,
|
||||
_edition: Edition,
|
||||
_cache: &mut Cache,
|
||||
tcx: ty::TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Result<(Self, clean::Crate), Error> {
|
||||
debug!("Initializing json renderer");
|
||||
Ok((
|
||||
|
@ -241,7 +241,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
format_version: 1,
|
||||
format_version: 2,
|
||||
};
|
||||
let mut p = self.out_path.clone();
|
||||
p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
|
||||
|
|
|
@ -68,8 +68,9 @@ pub struct Item {
|
|||
/// By default all documented items are public, but you can tell rustdoc to output private items
|
||||
/// so this field is needed to differentiate.
|
||||
pub visibility: Visibility,
|
||||
/// The full markdown docstring of this item.
|
||||
pub docs: String,
|
||||
/// The full markdown docstring of this item. Absent if there is no documentation at all,
|
||||
/// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`).
|
||||
pub docs: Option<String>,
|
||||
/// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
|
||||
pub links: FxHashMap<String, Id>,
|
||||
/// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
|
||||
|
@ -269,6 +270,7 @@ pub enum StructType {
|
|||
Plain,
|
||||
Tuple,
|
||||
Unit,
|
||||
Union,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#![feature(str_split_once)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::internal)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
@ -65,7 +66,7 @@ use std::process;
|
|||
use rustc_driver::abort_on_err;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_interface::interface;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
|
||||
use rustc_session::getopts;
|
||||
use rustc_session::{early_error, early_warn};
|
||||
|
@ -471,7 +472,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
|
|||
render_info: config::RenderInfo,
|
||||
diag: &rustc_errors::Handler,
|
||||
edition: rustc_span::edition::Edition,
|
||||
tcx: ty::TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> MainResult {
|
||||
match formats::run_format::<T>(krate, renderopts, render_info, &diag, edition, tcx) {
|
||||
Ok(_) => Ok(()),
|
||||
|
|
|
@ -108,7 +108,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
|
|||
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
||||
if let Some(dox) = &item.attrs.collapsed_doc_value() {
|
||||
let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
|
||||
let extra = crate::html::markdown::ExtraInfo::new_did(&self.cx.tcx, item.def_id, sp);
|
||||
let extra = crate::html::markdown::ExtraInfo::new_did(self.cx.tcx, item.def_id, sp);
|
||||
for code_block in markdown::rust_code_blocks(&dox, &extra) {
|
||||
self.check_rust_syntax(&item, &dox, code_block);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use rustc_hir::def::{
|
|||
PerNS,
|
||||
};
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_resolve::ParentScope;
|
||||
use rustc_session::lint::{
|
||||
|
@ -85,7 +86,7 @@ impl Res {
|
|||
}
|
||||
}
|
||||
|
||||
fn name(self, tcx: ty::TyCtxt<'_>) -> String {
|
||||
fn name(self, tcx: TyCtxt<'_>) -> String {
|
||||
match self {
|
||||
Res::Def(_, id) => tcx.item_name(id).to_string(),
|
||||
Res::Primitive(prim) => prim.as_str().to_string(),
|
||||
|
@ -865,12 +866,11 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
|||
|
||||
// FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
|
||||
let self_name = self_id.and_then(|self_id| {
|
||||
use ty::TyKind;
|
||||
if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) {
|
||||
// using `ty.to_string()` (or any variant) has issues with raw idents
|
||||
let ty = self.cx.tcx.type_of(self_id);
|
||||
let name = match ty.kind() {
|
||||
TyKind::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()),
|
||||
ty::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()),
|
||||
other if other.is_primitive() => Some(ty.to_string()),
|
||||
_ => None,
|
||||
};
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
fn main() {
|
||||
let mut i = 0;
|
||||
loop { //~ ERROR denote infinite loops with `loop
|
||||
'a: loop { //~ ERROR denote infinite loops with `loop
|
||||
i += 1;
|
||||
if i == 5 { break; }
|
||||
if i == 5 { break 'a; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
fn main() {
|
||||
let mut i = 0;
|
||||
while true { //~ ERROR denote infinite loops with `loop
|
||||
'a: while true { //~ ERROR denote infinite loops with `loop
|
||||
i += 1;
|
||||
if i == 5 { break; }
|
||||
if i == 5 { break 'a; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/issue-1962.rs:6:5
|
||||
|
|
||||
LL | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
LL | 'a: while true {
|
||||
| ^^^^^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
= note: requested on the command line with `-D while-true`
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ warning: denote infinite loops with `loop { ... }`
|
|||
LL | / 'b:
|
||||
LL | |
|
||||
LL | | while true { break }; // but here we cite the whole loop
|
||||
| |____________________________^ help: use `loop`
|
||||
| |__________________^ help: use `loop`
|
||||
|
|
||||
= note: `#[warn(while_true)]` on by default
|
||||
|
||||
|
|
|
@ -1,18 +1,62 @@
|
|||
#![warn(unused_labels)]
|
||||
|
||||
fn main() {
|
||||
'LOOP: loop {
|
||||
LOOP;
|
||||
//~^ ERROR cannot find value `LOOP` in this scope
|
||||
};
|
||||
'while_loop: while true { //~ WARN denote infinite loops with
|
||||
//~^ WARN unused label
|
||||
while_loop;
|
||||
//~^ ERROR cannot find value `while_loop` in this scope
|
||||
};
|
||||
'while_let: while let Some(_) = Some(()) {
|
||||
//~^ WARN unused label
|
||||
while_let;
|
||||
//~^ ERROR cannot find value `while_let` in this scope
|
||||
}
|
||||
'for_loop: for _ in 0..3 {
|
||||
//~^ WARN unused label
|
||||
for_loop;
|
||||
//~^ ERROR cannot find value `for_loop` in this scope
|
||||
};
|
||||
'LOOP: loop {
|
||||
//~^ WARN unused label
|
||||
LOOP;
|
||||
//~^ ERROR cannot find value `LOOP` in this scope
|
||||
};
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
'LOOP: loop {
|
||||
break LOOP;
|
||||
//~^ ERROR cannot find value `LOOP` in this scope
|
||||
};
|
||||
'while_loop: while true { //~ WARN denote infinite loops with
|
||||
break while_loop;
|
||||
//~^ ERROR cannot find value `while_loop` in this scope
|
||||
};
|
||||
'while_let: while let Some(_) = Some(()) {
|
||||
break while_let;
|
||||
//~^ ERROR cannot find value `while_let` in this scope
|
||||
}
|
||||
'for_loop: for _ in 0..3 {
|
||||
break for_loop;
|
||||
//~^ ERROR cannot find value `for_loop` in this scope
|
||||
};
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let foo = ();
|
||||
'while_loop: while true { //~ WARN denote infinite loops with
|
||||
//~^ WARN unused label
|
||||
break foo;
|
||||
//~^ ERROR `break` with value from a `while` loop
|
||||
};
|
||||
'while_let: while let Some(_) = Some(()) {
|
||||
//~^ WARN unused label
|
||||
break foo;
|
||||
//~^ ERROR `break` with value from a `while` loop
|
||||
}
|
||||
'for_loop: for _ in 0..3 {
|
||||
//~^ WARN unused label
|
||||
break foo;
|
||||
//~^ ERROR `break` with value from a `for` loop
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,47 +1,206 @@
|
|||
error[E0425]: cannot find value `LOOP` in this scope
|
||||
--> $DIR/label_misspelled.rs:3:9
|
||||
|
|
||||
LL | LOOP;
|
||||
| ^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: a label with a similar name exists: `'LOOP`
|
||||
|
||||
error[E0425]: cannot find value `while_loop` in this scope
|
||||
--> $DIR/label_misspelled.rs:7:9
|
||||
--> $DIR/label_misspelled.rs:6:9
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ----------- a label with a similar name exists
|
||||
LL |
|
||||
LL | while_loop;
|
||||
| ^^^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: a label with a similar name exists: `'while_loop`
|
||||
| ^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `while_let` in this scope
|
||||
--> $DIR/label_misspelled.rs:11:9
|
||||
|
|
||||
LL | 'while_let: while let Some(_) = Some(()) {
|
||||
| ---------- a label with a similar name exists
|
||||
LL |
|
||||
LL | while_let;
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: a label with a similar name exists: `'while_let`
|
||||
| ^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `for_loop` in this scope
|
||||
--> $DIR/label_misspelled.rs:15:9
|
||||
--> $DIR/label_misspelled.rs:16:9
|
||||
|
|
||||
LL | 'for_loop: for _ in 0..3 {
|
||||
| --------- a label with a similar name exists
|
||||
LL |
|
||||
LL | for_loop;
|
||||
| ^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: a label with a similar name exists: `'for_loop`
|
||||
| ^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `LOOP` in this scope
|
||||
--> $DIR/label_misspelled.rs:21:9
|
||||
|
|
||||
LL | 'LOOP: loop {
|
||||
| ----- a label with a similar name exists
|
||||
LL |
|
||||
LL | LOOP;
|
||||
| ^^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `LOOP` in this scope
|
||||
--> $DIR/label_misspelled.rs:28:15
|
||||
|
|
||||
LL | 'LOOP: loop {
|
||||
| ----- a label with a similar name exists
|
||||
LL | break LOOP;
|
||||
| ^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: use the similarly named label: `'LOOP`
|
||||
|
||||
error[E0425]: cannot find value `while_loop` in this scope
|
||||
--> $DIR/label_misspelled.rs:32:15
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ----------- a label with a similar name exists
|
||||
LL | break while_loop;
|
||||
| ^^^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: use the similarly named label: `'while_loop`
|
||||
|
||||
error[E0425]: cannot find value `while_let` in this scope
|
||||
--> $DIR/label_misspelled.rs:36:15
|
||||
|
|
||||
LL | 'while_let: while let Some(_) = Some(()) {
|
||||
| ---------- a label with a similar name exists
|
||||
LL | break while_let;
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: use the similarly named label: `'while_let`
|
||||
|
||||
error[E0425]: cannot find value `for_loop` in this scope
|
||||
--> $DIR/label_misspelled.rs:40:15
|
||||
|
|
||||
LL | 'for_loop: for _ in 0..3 {
|
||||
| --------- a label with a similar name exists
|
||||
LL | break for_loop;
|
||||
| ^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: use the similarly named label: `'for_loop`
|
||||
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:4:5
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/label_misspelled.rs:1:9
|
||||
|
|
||||
LL | #![warn(unused_labels)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/label_misspelled.rs:6:5
|
||||
--> $DIR/label_misspelled.rs:4:5
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
= note: `#[warn(while_true)]` on by default
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:9:5
|
||||
|
|
||||
LL | 'while_let: while let Some(_) = Some(()) {
|
||||
| ^^^^^^^^^^
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:14:5
|
||||
|
|
||||
LL | 'for_loop: for _ in 0..3 {
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:19:5
|
||||
|
|
||||
LL | 'LOOP: loop {
|
||||
| ^^^^^
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/label_misspelled.rs:31:5
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
||||
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:47:5
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/label_misspelled.rs:47:5
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
||||
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:52:5
|
||||
|
|
||||
LL | 'while_let: while let Some(_) = Some(()) {
|
||||
| ^^^^^^^^^^
|
||||
|
||||
warning: unused label
|
||||
--> $DIR/label_misspelled.rs:57:5
|
||||
|
|
||||
LL | 'for_loop: for _ in 0..3 {
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/label_misspelled.rs:49:9
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ----------------------- you can't `break` with a value in a `while` loop
|
||||
LL |
|
||||
LL | break foo;
|
||||
| ^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
help: alternatively, you might have meant to use the available loop label
|
||||
|
|
||||
LL | break 'while_loop;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/label_misspelled.rs:54:9
|
||||
|
|
||||
LL | 'while_let: while let Some(_) = Some(()) {
|
||||
| ---------------------------------------- you can't `break` with a value in a `while` loop
|
||||
LL |
|
||||
LL | break foo;
|
||||
| ^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
help: alternatively, you might have meant to use the available loop label
|
||||
|
|
||||
LL | break 'while_let;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `for` loop
|
||||
--> $DIR/label_misspelled.rs:59:9
|
||||
|
|
||||
LL | 'for_loop: for _ in 0..3 {
|
||||
| ------------------------ you can't `break` with a value in a `for` loop
|
||||
LL |
|
||||
LL | break foo;
|
||||
| ^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: use `break` on its own without a value inside this `for` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
help: alternatively, you might have meant to use the available loop label
|
||||
|
|
||||
LL | break 'for_loop;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 11 previous errors; 10 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0425, E0571.
|
||||
For more information about an error, try `rustc --explain E0425`.
|
||||
|
|
16
src/test/ui/label/label_misspelled_2.rs
Normal file
16
src/test/ui/label/label_misspelled_2.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
#![warn(unused_labels)]
|
||||
|
||||
fn main() {
|
||||
'a: for _ in 0..1 {
|
||||
break 'a;
|
||||
}
|
||||
'b: for _ in 0..1 {
|
||||
break b; //~ ERROR cannot find value `b` in this scope
|
||||
}
|
||||
c: for _ in 0..1 { //~ ERROR malformed loop label
|
||||
break 'c;
|
||||
}
|
||||
d: for _ in 0..1 { //~ ERROR malformed loop label
|
||||
break d; //~ ERROR cannot find value `d` in this scope
|
||||
}
|
||||
}
|
37
src/test/ui/label/label_misspelled_2.stderr
Normal file
37
src/test/ui/label/label_misspelled_2.stderr
Normal file
|
@ -0,0 +1,37 @@
|
|||
error: malformed loop label
|
||||
--> $DIR/label_misspelled_2.rs:10:5
|
||||
|
|
||||
LL | c: for _ in 0..1 {
|
||||
| ^ help: use the correct loop label format: `'c`
|
||||
|
||||
error: malformed loop label
|
||||
--> $DIR/label_misspelled_2.rs:13:5
|
||||
|
|
||||
LL | d: for _ in 0..1 {
|
||||
| ^ help: use the correct loop label format: `'d`
|
||||
|
||||
error[E0425]: cannot find value `b` in this scope
|
||||
--> $DIR/label_misspelled_2.rs:8:15
|
||||
|
|
||||
LL | 'b: for _ in 0..1 {
|
||||
| -- a label with a similar name exists
|
||||
LL | break b;
|
||||
| ^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: use the similarly named label: `'b`
|
||||
|
||||
error[E0425]: cannot find value `d` in this scope
|
||||
--> $DIR/label_misspelled_2.rs:14:15
|
||||
|
|
||||
LL | d: for _ in 0..1 {
|
||||
| - a label with a similar name exists
|
||||
LL | break d;
|
||||
| ^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: use the similarly named label: `'d`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
|
@ -1,10 +1,12 @@
|
|||
error[E0571]: `break` with value from a `for` loop
|
||||
--> $DIR/loop-break-value-no-repeat.rs:12:9
|
||||
|
|
||||
LL | for _ in &[1,2,3] {
|
||||
| ----------------- you can't `break` with a value in a `for` loop
|
||||
LL | break 22
|
||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `for` loop
|
||||
help: use `break` on its own without a value inside this `for` loop
|
||||
|
|
||||
LL | break
|
||||
| ^^^^^
|
||||
|
|
|
@ -94,6 +94,5 @@ fn main() {
|
|||
'LOOP: for _ in 0 .. 9 {
|
||||
break LOOP;
|
||||
//~^ ERROR cannot find value `LOOP` in this scope
|
||||
//~| ERROR `break` with value from a `for` loop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
error[E0425]: cannot find value `LOOP` in this scope
|
||||
--> $DIR/loop-break-value.rs:95:15
|
||||
|
|
||||
LL | 'LOOP: for _ in 0 .. 9 {
|
||||
| ----- a label with a similar name exists
|
||||
LL | break LOOP;
|
||||
| ^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| help: a label with a similar name exists: `'LOOP`
|
||||
| help: use the similarly named label: `'LOOP`
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/loop-break-value.rs:26:5
|
||||
|
@ -18,32 +20,44 @@ LL | 'while_loop: while true {
|
|||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/loop-break-value.rs:28:9
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ----------------------- you can't `break` with a value in a `while` loop
|
||||
LL | break;
|
||||
LL | break ();
|
||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `while` loop
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
help: alternatively, you might have meant to use the available loop label
|
||||
|
|
||||
LL | break 'while_loop;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/loop-break-value.rs:30:13
|
||||
|
|
||||
LL | 'while_loop: while true {
|
||||
| ----------------------- you can't `break` with a value in a `while` loop
|
||||
...
|
||||
LL | break 'while_loop 123;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `while` loop
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
LL | break 'while_loop;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/loop-break-value.rs:38:12
|
||||
|
|
||||
LL | while let Some(_) = Some(()) {
|
||||
| ---------------------------- you can't `break` with a value in a `while` loop
|
||||
LL | if break () {
|
||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `while` loop
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | if break {
|
||||
| ^^^^^
|
||||
|
@ -51,10 +65,12 @@ LL | if break {
|
|||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/loop-break-value.rs:43:9
|
||||
|
|
||||
LL | while let Some(_) = Some(()) {
|
||||
| ---------------------------- you can't `break` with a value in a `while` loop
|
||||
LL | break None;
|
||||
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `while` loop
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
|
@ -62,21 +78,26 @@ LL | break;
|
|||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/loop-break-value.rs:49:13
|
||||
|
|
||||
LL | 'while_let_loop: while let Some(_) = Some(()) {
|
||||
| --------------------------------------------- you can't `break` with a value in a `while` loop
|
||||
LL | loop {
|
||||
LL | break 'while_let_loop "nope";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `while` loop
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
LL | break 'while_let_loop;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `for` loop
|
||||
--> $DIR/loop-break-value.rs:56:9
|
||||
|
|
||||
LL | for _ in &[1,2,3] {
|
||||
| ----------------- you can't `break` with a value in a `for` loop
|
||||
LL | break ();
|
||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `for` loop
|
||||
help: use `break` on its own without a value inside this `for` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
|
@ -84,10 +105,13 @@ LL | break;
|
|||
error[E0571]: `break` with value from a `for` loop
|
||||
--> $DIR/loop-break-value.rs:57:9
|
||||
|
|
||||
LL | for _ in &[1,2,3] {
|
||||
| ----------------- you can't `break` with a value in a `for` loop
|
||||
LL | break ();
|
||||
LL | break [()];
|
||||
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `for` loop
|
||||
help: use `break` on its own without a value inside this `for` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
|
@ -95,24 +119,16 @@ LL | break;
|
|||
error[E0571]: `break` with value from a `for` loop
|
||||
--> $DIR/loop-break-value.rs:64:13
|
||||
|
|
||||
LL | 'for_loop: for _ in &[1,2,3] {
|
||||
| ---------------------------- you can't `break` with a value in a `for` loop
|
||||
...
|
||||
LL | break 'for_loop Some(17);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `for` loop
|
||||
help: use `break` on its own without a value inside this `for` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
|
||||
error[E0571]: `break` with value from a `for` loop
|
||||
--> $DIR/loop-break-value.rs:95:9
|
||||
|
|
||||
LL | break LOOP;
|
||||
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: instead, use `break` on its own without a value inside this `for` loop
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
LL | break 'for_loop;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:4:31
|
||||
|
@ -171,7 +187,7 @@ LL | break;
|
|||
| expected integer, found `()`
|
||||
| help: give it a value of the expected type: `break value`
|
||||
|
||||
error: aborting due to 18 previous errors; 1 warning emitted
|
||||
error: aborting due to 17 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0308, E0425, E0571.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
|
|
@ -533,7 +533,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
}
|
||||
|
||||
// check for never_loop
|
||||
if let ExprKind::Loop(ref block, _, _) = expr.kind {
|
||||
if let ExprKind::Loop(ref block, _, _, _) = expr.kind {
|
||||
match never_loop_block(block, expr.hir_id) {
|
||||
NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
|
||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
||||
|
@ -543,7 +543,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
// check for `loop { if let {} else break }` that could be `while let`
|
||||
// (also matches an explicit "match" instead of "if let")
|
||||
// (even if the "match" or "if let" is used for declaration)
|
||||
if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
|
||||
if let ExprKind::Loop(ref block, _, LoopSource::Loop, _) = expr.kind {
|
||||
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
|
||||
if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
|
||||
let msg = "empty `loop {}` wastes CPU cycles";
|
||||
|
@ -738,7 +738,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
|||
| ExprKind::Assign(ref e1, ref e2, _)
|
||||
| ExprKind::AssignOp(_, ref e1, ref e2)
|
||||
| ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
|
||||
ExprKind::Loop(ref b, _, _) => {
|
||||
ExprKind::Loop(ref b, _, _, _) => {
|
||||
// Break can come from the inner loop so remove them.
|
||||
absorb_break(&never_loop_block(b, main_loop_id))
|
||||
},
|
||||
|
@ -1314,7 +1314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
|
|||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
match &expr.kind {
|
||||
// Non-determinism may occur ... don't give a lint
|
||||
ExprKind::Loop(_, _, _) | ExprKind::Match(_, _, _) => self.should_lint = false,
|
||||
ExprKind::Loop(..) | ExprKind::Match(..) => self.should_lint = false,
|
||||
ExprKind::Block(block, _) => self.visit_block(block),
|
||||
_ => {},
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ where
|
|||
{
|
||||
if let ast::ExprKind::While(_, loop_block, label)
|
||||
| ast::ExprKind::ForLoop(_, _, loop_block, label)
|
||||
| ast::ExprKind::Loop(loop_block, label) = &expr.kind
|
||||
| ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
|
||||
{
|
||||
func(loop_block, label.as_ref());
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
|
|||
| ExprKind::Field(ref e, _)
|
||||
| ExprKind::AddrOf(_, _, ref e)
|
||||
| ExprKind::Box(ref e) => check_expr(cx, e, bindings),
|
||||
ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, _, _) => check_block(cx, block, bindings),
|
||||
ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => check_block(cx, block, bindings),
|
||||
// ExprKind::Call
|
||||
// ExprKind::MethodCall
|
||||
ExprKind::Array(v) | ExprKind::Tup(v) => {
|
||||
|
|
|
@ -317,7 +317,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
|
|||
self.current = cast_pat;
|
||||
self.visit_expr(expr);
|
||||
},
|
||||
ExprKind::Loop(ref body, _, desugaring) => {
|
||||
ExprKind::Loop(ref body, _, desugaring, _) => {
|
||||
let body_pat = self.next("body");
|
||||
let des = loop_desugaring_name(desugaring);
|
||||
let label_pat = self.next("label");
|
||||
|
|
|
@ -142,7 +142,7 @@ pub fn for_loop<'tcx>(
|
|||
if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
|
||||
if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
|
||||
if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
|
||||
if let hir::ExprKind::Loop(ref block, _, _) = arms[0].body.kind;
|
||||
if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
|
||||
if block.expr.is_none();
|
||||
if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
|
||||
if let hir::StmtKind::Local(ref local) = let_stmt.kind;
|
||||
|
@ -158,7 +158,7 @@ pub fn for_loop<'tcx>(
|
|||
/// `while cond { body }` becomes `(cond, body)`.
|
||||
pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Loop(block, _, hir::LoopSource::While) = &expr.kind;
|
||||
if let hir::ExprKind::Loop(block, _, hir::LoopSource::While, _) = &expr.kind;
|
||||
if let hir::Block { expr: Some(expr), .. } = &**block;
|
||||
if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
|
||||
if let hir::ExprKind::DropTemps(cond) = &cond.kind;
|
||||
|
|
|
@ -123,7 +123,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
|||
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
|
||||
},
|
||||
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
|
||||
(&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => {
|
||||
(&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
|
||||
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
|
||||
},
|
||||
(&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
|
||||
|
@ -560,7 +560,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
ExprKind::Lit(ref l) => {
|
||||
l.node.hash(&mut self.s);
|
||||
},
|
||||
ExprKind::Loop(ref b, ref i, _) => {
|
||||
ExprKind::Loop(ref b, ref i, ..) => {
|
||||
self.hash_block(b);
|
||||
if let Some(i) = *i {
|
||||
self.hash_name(i.ident.name);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue