Skip to content

Commit b814b63

Browse files
committed
Auto merge of rust-lang#81271 - m-ou-se:rollup-xv7gq3w, r=m-ou-se
Rollup of 10 pull requests Successful merges: - rust-lang#80573 (Deny rustc::internal lints for rustdoc and clippy) - rust-lang#81173 (Expand docs on Iterator::intersperse) - rust-lang#81194 (Stabilize std::panic::panic_any.) - rust-lang#81202 (Don't prefix 0x for each segments in `dbg!(Ipv6)`) - rust-lang#81225 (Make 'docs' nullable in rustdoc-json output) - rust-lang#81227 (Remove doctree::StructType) - rust-lang#81233 (Document why not use concat! in dbg! macro) - rust-lang#81236 (Gracefully handle loop labels missing leading `'` in different positions) - rust-lang#81241 (Turn alloc's force_expr macro into a regular macro_rules.) - rust-lang#81242 (Enforce statically that `MIN_NON_ZERO_CAP` is calculated at compile time) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents f2de221 + 9c2a577 commit b814b63

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+681
-266
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use rustc_errors::struct_span_err;
1010
use rustc_hir as hir;
1111
use rustc_hir::def::Res;
1212
use rustc_session::parse::feature_err;
13-
use rustc_span::hygiene::ForLoopLoc;
1413
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
1514
use rustc_span::symbol::{sym, Ident, Symbol};
15+
use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
1616
use rustc_target::asm;
1717
use std::collections::hash_map::Entry;
1818
use std::fmt::Write;
@@ -102,6 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
102102
this.lower_block(body, false),
103103
opt_label,
104104
hir::LoopSource::Loop,
105+
DUMMY_SP,
105106
)
106107
}),
107108
ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
@@ -453,7 +454,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
453454
self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
454455

455456
// `[opt_ident]: loop { ... }`
456-
hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source)
457+
hir::ExprKind::Loop(
458+
self.block_expr(self.arena.alloc(match_expr)),
459+
opt_label,
460+
source,
461+
span.with_hi(cond.span.hi()),
462+
)
457463
}
458464

459465
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
@@ -748,7 +754,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
748754
// loop { .. }
749755
let loop_expr = self.arena.alloc(hir::Expr {
750756
hir_id: loop_hir_id,
751-
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop),
757+
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span),
752758
span,
753759
attrs: ThinVec::new(),
754760
});
@@ -1709,7 +1715,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
17091715
);
17101716

17111717
// `[opt_ident]: loop { ... }`
1712-
let kind = hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::ForLoop);
1718+
let kind = hir::ExprKind::Loop(
1719+
loop_block,
1720+
opt_label,
1721+
hir::LoopSource::ForLoop,
1722+
e.span.with_hi(orig_head_span.hi()),
1723+
);
17131724
let loop_expr = self.arena.alloc(hir::Expr {
17141725
hir_id: self.lower_node_id(e.id),
17151726
kind,

compiler/rustc_hir/src/hir.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1617,7 +1617,9 @@ pub enum ExprKind<'hir> {
16171617
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
16181618
///
16191619
/// I.e., `'label: loop { <block> }`.
1620-
Loop(&'hir Block<'hir>, Option<Label>, LoopSource),
1620+
///
1621+
/// The `Span` is the loop header (`for x in y`/`while let pat = expr`).
1622+
Loop(&'hir Block<'hir>, Option<Label>, LoopSource, Span),
16211623
/// A `match` block, with a source that indicates whether or not it is
16221624
/// the result of a desugaring, and if so, which kind.
16231625
Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),

compiler/rustc_hir/src/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
11511151
visitor.visit_expr(then);
11521152
walk_list!(visitor, visit_expr, else_opt);
11531153
}
1154-
ExprKind::Loop(ref block, ref opt_label, _) => {
1154+
ExprKind::Loop(ref block, ref opt_label, _, _) => {
11551155
walk_list!(visitor, visit_label, opt_label);
11561156
visitor.visit_block(block);
11571157
}

compiler/rustc_hir_pretty/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ impl<'a> State<'a> {
13961396
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
13971397
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
13981398
}
1399-
hir::ExprKind::Loop(ref blk, opt_label, _) => {
1399+
hir::ExprKind::Loop(ref blk, opt_label, _, _) => {
14001400
if let Some(label) = opt_label {
14011401
self.print_ident(label.ident);
14021402
self.word_space(":");

compiler/rustc_lint/src/builtin.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,24 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
9696

9797
impl EarlyLintPass for WhileTrue {
9898
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
99-
if let ast::ExprKind::While(cond, ..) = &e.kind {
99+
if let ast::ExprKind::While(cond, _, label) = &e.kind {
100100
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
101101
if let ast::LitKind::Bool(true) = lit.kind {
102102
if !lit.span.from_expansion() {
103103
let msg = "denote infinite loops with `loop { ... }`";
104-
let condition_span = cx.sess.source_map().guess_head_span(e.span);
104+
let condition_span = e.span.with_hi(cond.span.hi());
105105
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
106106
lint.build(msg)
107107
.span_suggestion_short(
108108
condition_span,
109109
"use `loop`",
110-
"loop".to_owned(),
110+
format!(
111+
"{}loop",
112+
label.map_or_else(String::new, |label| format!(
113+
"{}: ",
114+
label.ident,
115+
))
116+
),
111117
Applicability::MachineApplicable,
112118
)
113119
.emit();

compiler/rustc_mir_build/src/thir/cx/expr.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -546,9 +546,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
546546
scrutinee: discr.to_ref(),
547547
arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
548548
},
549-
hir::ExprKind::Loop(ref body, _, _) => {
550-
ExprKind::Loop { body: block::to_expr_ref(cx, body) }
551-
}
549+
hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) },
552550
hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
553551
lhs: source.to_ref(),
554552
name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),

compiler/rustc_parse/src/parser/expr.rs

+48-6
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ impl<'a> Parser<'a> {
585585
lhs_span: Span,
586586
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
587587
) -> PResult<'a, P<Expr>> {
588-
let mk_expr = |this: &mut Self, rhs: P<Ty>| {
588+
let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
589589
this.mk_expr(
590590
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
591591
expr_kind(lhs, rhs),
@@ -597,13 +597,49 @@ impl<'a> Parser<'a> {
597597
// LessThan comparison after this cast.
598598
let parser_snapshot_before_type = self.clone();
599599
let cast_expr = match self.parse_ty_no_plus() {
600-
Ok(rhs) => mk_expr(self, rhs),
600+
Ok(rhs) => mk_expr(self, lhs, rhs),
601601
Err(mut type_err) => {
602602
// Rewind to before attempting to parse the type with generics, to recover
603603
// from situations like `x as usize < y` in which we first tried to parse
604604
// `usize < y` as a type with generic arguments.
605605
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
606606

607+
// Check for typo of `'a: loop { break 'a }` with a missing `'`.
608+
match (&lhs.kind, &self.token.kind) {
609+
(
610+
// `foo: `
611+
ExprKind::Path(None, ast::Path { segments, .. }),
612+
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
613+
) if segments.len() == 1 => {
614+
let snapshot = self.clone();
615+
let label = Label {
616+
ident: Ident::from_str_and_span(
617+
&format!("'{}", segments[0].ident),
618+
segments[0].ident.span,
619+
),
620+
};
621+
match self.parse_labeled_expr(label, AttrVec::new(), false) {
622+
Ok(expr) => {
623+
type_err.cancel();
624+
self.struct_span_err(label.ident.span, "malformed loop label")
625+
.span_suggestion(
626+
label.ident.span,
627+
"use the correct loop label format",
628+
label.ident.to_string(),
629+
Applicability::MachineApplicable,
630+
)
631+
.emit();
632+
return Ok(expr);
633+
}
634+
Err(mut err) => {
635+
err.cancel();
636+
*self = snapshot;
637+
}
638+
}
639+
}
640+
_ => {}
641+
}
642+
607643
match self.parse_path(PathStyle::Expr) {
608644
Ok(path) => {
609645
let (op_noun, op_verb) = match self.token.kind {
@@ -630,7 +666,8 @@ impl<'a> Parser<'a> {
630666
op_noun,
631667
);
632668
let span_after_type = parser_snapshot_after_type.token.span;
633-
let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
669+
let expr =
670+
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
634671

635672
let expr_str = self
636673
.span_to_snippet(expr.span)
@@ -1067,7 +1104,7 @@ impl<'a> Parser<'a> {
10671104
} else if self.eat_keyword(kw::While) {
10681105
self.parse_while_expr(None, self.prev_token.span, attrs)
10691106
} else if let Some(label) = self.eat_label() {
1070-
self.parse_labeled_expr(label, attrs)
1107+
self.parse_labeled_expr(label, attrs, true)
10711108
} else if self.eat_keyword(kw::Loop) {
10721109
self.parse_loop_expr(None, self.prev_token.span, attrs)
10731110
} else if self.eat_keyword(kw::Continue) {
@@ -1228,7 +1265,12 @@ impl<'a> Parser<'a> {
12281265
}
12291266

12301267
/// Parse `'label: $expr`. The label is already parsed.
1231-
fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
1268+
fn parse_labeled_expr(
1269+
&mut self,
1270+
label: Label,
1271+
attrs: AttrVec,
1272+
consume_colon: bool,
1273+
) -> PResult<'a, P<Expr>> {
12321274
let lo = label.ident.span;
12331275
let label = Some(label);
12341276
let ate_colon = self.eat(&token::Colon);
@@ -1247,7 +1289,7 @@ impl<'a> Parser<'a> {
12471289
self.parse_expr()
12481290
}?;
12491291

1250-
if !ate_colon {
1292+
if !ate_colon && consume_colon {
12511293
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
12521294
}
12531295

compiler/rustc_passes/src/check_const.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
199199
// Skip the following checks if we are not currently in a const context.
200200
_ if self.const_kind.is_none() => {}
201201

202-
hir::ExprKind::Loop(_, _, source) => {
202+
hir::ExprKind::Loop(_, _, source, _) => {
203203
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
204204
}
205205

compiler/rustc_passes/src/liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
844844

845845
// Note that labels have been resolved, so we don't need to look
846846
// at the label ident
847-
hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ),
847+
hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
848848

849849
hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
850850
//

compiler/rustc_passes/src/loops.rs

+67-27
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
5353

5454
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
5555
match e.kind {
56-
hir::ExprKind::Loop(ref b, _, source) => {
56+
hir::ExprKind::Loop(ref b, _, source, _) => {
5757
self.with_context(Loop(source), |v| v.visit_block(&b));
5858
}
5959
hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
@@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
6868
hir::ExprKind::Block(ref b, Some(_label)) => {
6969
self.with_context(LabeledBlock, |v| v.visit_block(&b));
7070
}
71-
hir::ExprKind::Break(label, ref opt_expr) => {
71+
hir::ExprKind::Break(break_label, ref opt_expr) => {
7272
if let Some(e) = opt_expr {
7373
self.visit_expr(e);
7474
}
7575

76-
if self.require_label_in_labeled_block(e.span, &label, "break") {
76+
if self.require_label_in_labeled_block(e.span, &break_label, "break") {
7777
// If we emitted an error about an unlabeled break in a labeled
7878
// block, we don't need any further checking for this break any more
7979
return;
8080
}
8181

82-
let loop_id = match label.target_id {
82+
let loop_id = match break_label.target_id {
8383
Ok(loop_id) => Some(loop_id),
8484
Err(hir::LoopIdError::OutsideLoopScope) => None,
8585
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
@@ -89,49 +89,89 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
8989
Err(hir::LoopIdError::UnresolvedLabel) => None,
9090
};
9191

92-
if let Some(loop_id) = loop_id {
93-
if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
94-
return;
95-
}
92+
if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) {
93+
return;
9694
}
9795

98-
if opt_expr.is_some() {
99-
let loop_kind = if let Some(loop_id) = loop_id {
100-
Some(match self.hir_map.expect_expr(loop_id).kind {
101-
hir::ExprKind::Loop(_, _, source) => source,
96+
if let Some(break_expr) = opt_expr {
97+
let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id {
98+
match self.hir_map.expect_expr(loop_id).kind {
99+
hir::ExprKind::Loop(_, label, source, sp) => {
100+
(Some(sp), label, Some(source))
101+
}
102102
ref r => {
103103
span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
104104
}
105-
})
105+
}
106106
} else {
107-
None
107+
(None, None, None)
108108
};
109109
match loop_kind {
110110
None | Some(hir::LoopSource::Loop) => (),
111111
Some(kind) => {
112-
struct_span_err!(
112+
let mut err = struct_span_err!(
113113
self.sess,
114114
e.span,
115115
E0571,
116116
"`break` with value from a `{}` loop",
117117
kind.name()
118-
)
119-
.span_label(
118+
);
119+
err.span_label(
120120
e.span,
121-
"can only break with a value inside \
122-
`loop` or breakable block",
123-
)
124-
.span_suggestion(
121+
"can only break with a value inside `loop` or breakable block",
122+
);
123+
if let Some(head) = head {
124+
err.span_label(
125+
head,
126+
&format!(
127+
"you can't `break` with a value in a `{}` loop",
128+
kind.name()
129+
),
130+
);
131+
}
132+
err.span_suggestion(
125133
e.span,
126134
&format!(
127-
"instead, use `break` on its own \
128-
without a value inside this `{}` loop",
129-
kind.name()
135+
"use `break` on its own without a value inside this `{}` loop",
136+
kind.name(),
137+
),
138+
format!(
139+
"break{}",
140+
break_label
141+
.label
142+
.map_or_else(String::new, |l| format!(" {}", l.ident))
130143
),
131-
"break".to_string(),
132144
Applicability::MaybeIncorrect,
133-
)
134-
.emit();
145+
);
146+
if let (Some(label), None) = (loop_label, break_label.label) {
147+
match break_expr.kind {
148+
hir::ExprKind::Path(hir::QPath::Resolved(
149+
None,
150+
hir::Path {
151+
segments: [segment],
152+
res: hir::def::Res::Err,
153+
..
154+
},
155+
)) if label.ident.to_string()
156+
== format!("'{}", segment.ident) =>
157+
{
158+
// This error is redundant, we will have already emitted a
159+
// suggestion to use the label when `segment` wasn't found
160+
// (hence the `Res::Err` check).
161+
err.delay_as_bug();
162+
}
163+
_ => {
164+
err.span_suggestion(
165+
break_expr.span,
166+
"alternatively, you might have meant to use the \
167+
available loop label",
168+
label.ident.to_string(),
169+
Applicability::MaybeIncorrect,
170+
);
171+
}
172+
}
173+
}
174+
err.emit();
135175
}
136176
}
137177
}

compiler/rustc_passes/src/region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
252252
terminating(then.hir_id.local_id);
253253
}
254254

255-
hir::ExprKind::Loop(ref body, _, _) => {
255+
hir::ExprKind::Loop(ref body, _, _, _) => {
256256
terminating(body.hir_id.local_id);
257257
}
258258

0 commit comments

Comments
 (0)