未验证 提交 63ea42fd 编写于 作者: K kennytm

Rollup merge of #50793 - jrlusby:master, r=petrochenkov

tidy: Add a check for empty UI test files

Check for empty `.stderr` and `.stdout` files in UI test directories.
Empty files could  still pass testing for `compile-pass` tests with no output
so they can get into the repo accidentally, but they are not necessary and can
be removed.

This is very much an in progress pull request. I'm having an issue with rustfmt. It wanted to reformat the entire file for almost every file by default. And when I run tidy it just errors out because it catches the empty files that are already in the repo.

My next step is goin got be to remove those empty file and see if running tidy again will actually reformat things outside of the context of `cargo fmt`

Fixes https://github.com/rust-lang/rust/issues/50785
......@@ -179,7 +179,7 @@ fn pats_all<'b, I: Iterator<Item=&'b P<hir::Pat>>>(&mut self,
fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
match expr.node {
hir::ExprBlock(ref blk) => {
hir::ExprBlock(ref blk, _) => {
let blk_exit = self.block(&blk, pred);
self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
}
......
......@@ -1015,7 +1015,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
expression.span,
expression.id)
}
ExprBlock(ref block) => visitor.visit_block(block),
ExprBlock(ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
}
ExprAssign(ref left_hand_expression, ref right_hand_expression) => {
visitor.visit_expr(right_hand_expression);
visitor.visit_expr(left_hand_expression)
......
......@@ -3048,7 +3048,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
);
block.expr = Some(this.wrap_in_try_constructor(
"from_ok", tail, unstable_span));
hir::ExprBlock(P(block))
hir::ExprBlock(P(block), None)
})
}
ExprKind::Match(ref expr, ref arms) => hir::ExprMatch(
......@@ -3100,7 +3100,11 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
})
})
}
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)),
ExprKind::Block(ref blk, opt_label) => {
hir::ExprBlock(self.lower_block(blk,
opt_label.is_some()),
self.lower_label(opt_label))
}
ExprKind::Assign(ref el, ref er) => {
hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
......@@ -3843,7 +3847,7 @@ fn expr_match(
}
fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
self.expr(b.span, hir::ExprBlock(b), attrs)
self.expr(b.span, hir::ExprBlock(b, None), attrs)
}
fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
......
......@@ -778,9 +778,8 @@ pub struct Block {
pub rules: BlockCheckMode,
pub span: Span,
/// If true, then there may exist `break 'a` values that aim to
/// break out of this block early. As of this writing, this is not
/// currently permitted in Rust itself, but it is generated as
/// part of `catch` statements.
/// break out of this block early.
/// Used by `'label: {}` blocks and by `catch` statements.
pub targeted_by_break: bool,
/// If true, don't emit return value type errors as the parser had
/// to recover from a parse error so this block will not have an
......@@ -1381,8 +1380,8 @@ pub enum Expr_ {
/// This may also be a generator literal, indicated by the final boolean,
/// in that case there is an GeneratorClause.
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
/// A block (`{ ... }`)
ExprBlock(P<Block>),
/// A block (`'label: { ... }`)
ExprBlock(P<Block>, Option<Label>),
/// An assignment (`a = foo()`)
ExprAssign(P<Expr>, P<Expr>),
......
......@@ -1047,7 +1047,7 @@ fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> {
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
hir::ExprBlock(ref b) => {
hir::ExprBlock(ref b, _) => {
self.cbox(indent_unit - 1)?;
self.ibox(0)?;
self.s.word(" else ")?;
......@@ -1377,7 +1377,11 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
// empty box to satisfy the close.
self.ibox(0)?;
}
hir::ExprBlock(ref blk) => {
hir::ExprBlock(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_name(label.name)?;
self.word_space(":")?;
}
// containing cbox, will be closed by print-block at }
self.cbox(indent_unit)?;
// head-box, will be closed by print-block after {
......@@ -1893,7 +1897,11 @@ fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
self.word_space("=>")?;
match arm.body.node {
hir::ExprBlock(ref blk) => {
hir::ExprBlock(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_name(label.name)?;
self.word_space(":")?;
}
// the block will close the pattern's ibox
self.print_block_unclosed_indent(&blk, indent_unit)?;
......@@ -2299,7 +2307,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
match e.node {
hir::ExprIf(..) |
hir::ExprMatch(..) |
hir::ExprBlock(_) |
hir::ExprBlock(..) |
hir::ExprWhile(..) |
hir::ExprLoop(..) => false,
_ => true,
......
......@@ -589,7 +589,7 @@ fn hash_stable<W: StableHasherResult>(&self,
ExprLoop(body, label, loop_src),
ExprMatch(matchee, arms, match_src),
ExprClosure(capture_clause, decl, body_id, span, gen),
ExprBlock(blk),
ExprBlock(blk, label),
ExprAssign(lhs, rhs),
ExprAssignOp(op, lhs, rhs),
ExprField(owner, field_name),
......
......@@ -499,7 +499,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
self.consume_expr(&rhs);
}
hir::ExprBlock(ref blk) => {
hir::ExprBlock(ref blk, _) => {
self.walk_block(&blk);
}
......
......@@ -1187,7 +1187,9 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
succ
}
hir::ExprBlock(ref blk) => {
// Note that labels have been resolved, so we don't need to look
// at the label ident
hir::ExprBlock(ref blk, _) => {
self.propagate_through_block(&blk, succ)
}
}
......
......@@ -1247,7 +1247,7 @@ fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
hir::ExprCast(ref subexpr, _) => {
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id)
}
hir::ExprBlock(ref block) => {
hir::ExprBlock(ref block, _) => {
if let Some(ref subexpr) = block.expr {
record_rvalue_scope_if_borrow_expr(
visitor, &subexpr, blk_id);
......
......@@ -228,7 +228,7 @@ fn report_unsafe(&self, cx: &LateContext, span: Span, desc: &'static str) {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
if let hir::ExprBlock(ref blk) = e.node {
if let hir::ExprBlock(ref blk, _) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) {
self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
......
......@@ -36,7 +36,7 @@ pub fn ast_block(&mut self,
self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
if targeted_by_break {
// This is a `break`-able block (currently only `catch { ... }`)
// This is a `break`-able block
let exit_block = this.cfg.start_new_block();
let block_exit = this.in_breakable_scope(
None, exit_block, destination.clone(), |this| {
......
......@@ -292,7 +292,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
}
hir::ExprBlock(ref blk) => ExprKind::Block { body: &blk },
hir::ExprBlock(ref blk, _) => ExprKind::Block { body: &blk },
hir::ExprAssign(ref lhs, ref rhs) => {
ExprKind::Assign {
......
......@@ -141,7 +141,7 @@ fn fn_is_closure<'a>(fn_like: FnLikeNode<'a>) -> bool {
}
// Check if this is an unsafe block, or an item
match node {
Node::NodeExpr(&hir::Expr { node: hir::ExprBlock(ref block), ..}) => {
Node::NodeExpr(&hir::Expr { node: hir::ExprBlock(ref block, _), ..}) => {
if block_is_unsafe(&*block) {
// Found an unsafe block, we can bail out here.
return true;
......
......@@ -259,6 +259,44 @@ fn foo() {}
i += 1;
};
```
"##,
E0695: r##"
A `break` statement without a label appeared inside a labeled block.
Example of erroneous code:
```compile_fail,E0695
# #![feature(label_break_value)]
loop {
'a: {
break;
}
}
```
Make sure to always label the `break`:
```
# #![feature(label_break_value)]
'l: loop {
'a: {
break 'l;
}
}
```
Or if you want to `break` the labeled block:
```
# #![feature(label_break_value)]
loop {
'a: {
break 'a;
}
break;
}
```
"##
}
......@@ -271,4 +309,5 @@ fn foo() {}
E0642, // patterns aren't allowed in methods without bodies
E0666, // nested `impl Trait` is illegal
E0667, // `impl Trait` in projections
E0696, // `continue` pointing to a labeled block
}
......@@ -13,7 +13,7 @@
use rustc::hir::map::Map;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir;
use rustc::hir::{self, Destination};
use syntax::ast;
use syntax_pos::Span;
......@@ -39,6 +39,7 @@ enum Context {
Normal,
Loop(LoopKind),
Closure,
LabeledBlock,
}
#[derive(Copy, Clone)]
......@@ -84,7 +85,16 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
hir::ExprClosure(.., b, _, _) => {
self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBlock(ref b, Some(_label)) => {
self.with_context(LabeledBlock, |v| v.visit_block(&b));
}
hir::ExprBreak(label, ref opt_expr) => {
if self.require_label_in_labeled_block(e.span, &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.into() {
Ok(loop_id) => loop_id,
Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
......@@ -94,6 +104,7 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
},
Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
};
if loop_id != ast::DUMMY_NODE_ID {
match self.hir_map.find(loop_id).unwrap() {
hir::map::NodeBlock(_) => return,
......@@ -113,13 +124,15 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
})
};
match loop_kind {
None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
None |
Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
Some(kind) => {
struct_span_err!(self.sess, e.span, E0571,
"`break` with value from a `{}` loop",
kind.name())
.span_label(e.span,
"can only break with a value inside `loop`")
"can only break with a value inside \
`loop` or breakable block")
.span_suggestion(e.span,
&format!("instead, use `break` on its own \
without a value inside this `{}` loop",
......@@ -130,13 +143,29 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
}
}
self.require_loop("break", e.span);
self.require_break_cx("break", e.span);
}
hir::ExprAgain(label) => {
if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.target_id {
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
self.require_label_in_labeled_block(e.span, &label, "continue");
match label.target_id {
Ok(loop_id) => {
if let hir::map::NodeBlock(block) = self.hir_map.find(loop_id).unwrap() {
struct_span_err!(self.sess, e.span, E0696,
"`continue` pointing to a labeled block")
.span_label(e.span,
"labeled blocks cannot be `continue`'d")
.span_note(block.span,
"labeled block the continue points to")
.emit();
}
}
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
}
_ => {}
}
self.require_loop("continue", e.span)
self.require_break_cx("continue", e.span)
},
_ => intravisit::walk_expr(self, e),
}
......@@ -153,8 +182,9 @@ fn with_context<F>(&mut self, cx: Context, f: F)
self.cx = old_cx;
}
fn require_loop(&self, name: &str, span: Span) {
fn require_break_cx(&self, name: &str, span: Span) {
match self.cx {
LabeledBlock |
Loop(_) => {}
Closure => {
struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
......@@ -169,6 +199,22 @@ fn require_loop(&self, name: &str, span: Span) {
}
}
fn require_label_in_labeled_block(&mut self, span: Span, label: &Destination, cf_type: &str)
-> bool
{
if self.cx == LabeledBlock {
if label.label.is_none() {
struct_span_err!(self.sess, span, E0695,
"unlabeled `{}` inside of a labeled block", cf_type)
.span_label(span,
format!("`{}` statements that would diverge to or through \
a labeled block need to bear a label", cf_type))
.emit();
return true;
}
}
return false;
}
fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
struct_span_err!(self.sess, span, E0590,
"`break` or `continue` with no label in the condition of a `while` loop")
......
......@@ -342,7 +342,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
let mut callee = &**callee;
loop {
callee = match callee.node {
hir::ExprBlock(ref block) => match block.expr {
hir::ExprBlock(ref block, _) => match block.expr {
Some(ref tail) => &tail,
None => break
},
......@@ -404,7 +404,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
}
}
hir::ExprBlock(_) |
hir::ExprBlock(..) |
hir::ExprIndex(..) |
hir::ExprField(..) |
hir::ExprArray(_) |
......
......@@ -3753,6 +3753,8 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
self.ribs[ValueNS].pop();
}
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
// Equivalent to `visit::walk_expr` + passing some context to children.
ExprKind::Field(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
......
......@@ -3536,7 +3536,7 @@ fn check_expr_with_expectation_and_needs(&self,
// Warn for non-block expressions with diverging children.
match expr.node {
hir::ExprBlock(_) |
hir::ExprBlock(..) |
hir::ExprLoop(..) | hir::ExprWhile(..) |
hir::ExprIf(..) | hir::ExprMatch(..) => {}
......@@ -3912,7 +3912,7 @@ fn check_expr_kind(&self,
hir::ExprClosure(capture, ref decl, body_id, _, gen) => {
self.check_expr_closure(expr, capture, &decl, body_id, gen, expected)
}
hir::ExprBlock(ref body) => {
hir::ExprBlock(ref body, _) => {
self.check_block_with_expected(&body, expected)
}
hir::ExprCall(ref callee, ref args) => {
......@@ -4326,8 +4326,8 @@ fn check_block_with_expected(&self,
};
// In some cases, blocks have just one exit, but other blocks
// can be targeted by multiple breaks. This cannot happen in
// normal Rust syntax today, but it can happen when we desugar
// can be targeted by multiple breaks. This can happen both
// with labeled blocks as well as when we desugar
// a `do catch { ... }` expression.
//
// Example 1:
......
......@@ -934,7 +934,7 @@ impl Expr {
/// Whether this expression would be valid somewhere that expects a value, for example, an `if`
/// condition.
pub fn returns(&self) -> bool {
if let ExprKind::Block(ref block) = self.node {
if let ExprKind::Block(ref block, _) = self.node {
match block.stmts.last().map(|last_stmt| &last_stmt.node) {
// implicit return
Some(&StmtKind::Expr(_)) => true,
......@@ -1121,8 +1121,8 @@ pub enum ExprKind {
///
/// The final span is the span of the argument block `|...|`
Closure(CaptureBy, Movability, P<FnDecl>, P<Expr>, Span),
/// A block (`{ ... }`)
Block(P<Block>),
/// A block (`'label: { ... }`)
Block(P<Block>, Option<Label>),
/// A catch block (`catch { ... }`)
Catch(P<Block>),
......
......@@ -668,7 +668,7 @@ fn expr_method_call(&self, span: Span,
self.expr(span, ast::ExprKind::MethodCall(segment, args))
}
fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
self.expr(b.span, ast::ExprKind::Block(b))
self.expr(b.span, ast::ExprKind::Block(b, None))
}
fn field_imm(&self, span: Span, ident: Ident, e: P<ast::Expr>) -> ast::Field {
ast::Field {
......
......@@ -466,6 +466,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
// inconsistent bounds in where clauses
(active, trivial_bounds, "1.28.0", Some(48214), None),
// 'a: { break 'a; }
(active, label_break_value, "1.28.0", Some(48594), None),
);
declare_features! (
......@@ -1696,6 +1699,12 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
"multiple patterns in `if let` and `while let` are unstable");
}
}
ast::ExprKind::Block(_, opt_label) => {
if let Some(label) = opt_label {
gate_feature_post!(&self, label_break_value, label.ident.span,
"labels on blocks are unstable");
}
}
_ => {}
}
visit::walk_expr(self, e);
......
......@@ -1256,7 +1256,10 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
folder.fold_expr(body),
folder.new_span(span))
}
ExprKind::Block(blk) => ExprKind::Block(folder.fold_block(blk)),
ExprKind::Block(blk, opt_label) => {
ExprKind::Block(folder.fold_block(blk),
opt_label.map(|label| folder.fold_label(label)))
}
ExprKind::Assign(el, er) => {
ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er))
}
......
......@@ -26,7 +26,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
ast::ExprKind::If(..) |
ast::ExprKind::IfLet(..) |
ast::ExprKind::Match(..) |
ast::ExprKind::Block(_) |
ast::ExprKind::Block(..) |
ast::ExprKind::While(..) |
ast::ExprKind::WhileLet(..) |
ast::ExprKind::Loop(..) |
......
......@@ -128,7 +128,7 @@ pub enum BlockMode {
token::NtBlock(ref block) => {
$p.bump();
let span = $p.span;
let kind = ExprKind::Block((*block).clone());
let kind = ExprKind::Block((*block).clone(), None);
return Ok($p.mk_expr(span, kind, ThinVec::new()));
}
_ => {},
......@@ -2244,7 +2244,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
};
}
token::OpenDelim(token::Brace) => {
return self.parse_block_expr(lo, BlockCheckMode::Default, attrs);
return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs);
}
token::BinOp(token::Or) | token::OrOr => {
return self.parse_lambda_expr(attrs);
......@@ -2318,7 +2318,13 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(Some(label), lo, attrs)
}
let msg = "expected `while`, `for`, or `loop` after a label";
if self.token == token::OpenDelim(token::Brace) {
return self.parse_block_expr(Some(label),
lo,
BlockCheckMode::Default,
attrs);
}
let msg = "expected `while`, `for`, `loop` or `{` after a label";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
return Err(err);
......@@ -2338,6 +2344,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
}
if self.eat_keyword(keywords::Unsafe) {
return self.parse_block_expr(
None,
lo,
BlockCheckMode::Unsafe(ast::UserProvided),
attrs);
......@@ -2502,7 +2509,8 @@ fn parse_or_use_outer_attributes(&mut self,
}
/// Parse a block or unsafe block
pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode,
pub fn parse_block_expr(&mut self, opt_label: Option<Label>,
lo: Span, blk_mode: BlockCheckMode,
outer_attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>> {
self.expect(&token::OpenDelim(token::Brace))?;
......@@ -2511,7 +2519,7 @@ pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode,
attrs.extend(self.parse_inner_attributes()?);
let blk = self.parse_block_tail(lo, blk_mode)?;
return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs));
return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs));
}
/// parse a.b or a(13) or a[4] or just a
......@@ -3261,7 +3269,7 @@ pub fn parse_lambda_expr(&mut self,
// If an explicit return type is given, require a
// block to appear (RFC 968).
let body_lo = self.span;
self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())?
self.parse_block_expr(None, body_lo, BlockCheckMode::Default, ThinVec::new())?
}
};
......@@ -3277,7 +3285,7 @@ pub fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
return self.parse_if_expr(ThinVec::new());
} else {
let blk = self.parse_block()?;
return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new()));
return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), ThinVec::new()));
}
}
......
......@@ -1792,7 +1792,7 @@ fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
ast::ExprKind::Block(ref b) => {
ast::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1)?;
self.ibox(0)?;
self.s.word(" else ")?;
......@@ -2182,7 +2182,11 @@ fn print_expr_outer_attr_style(&mut self,
// empty box to satisfy the close.
self.ibox(0)?;
}
ast::ExprKind::Block(ref blk) => {
ast::ExprKind::Block(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
self.word_space(":")?;
}
// containing cbox, will be closed by print-block at }
self.cbox(INDENT_UNIT)?;
// head-box, will be closed by print-block after {
......@@ -2695,7 +2699,12 @@ fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
self.word_space("=>")?;
match arm.body.node {
ast::ExprKind::Block(ref blk) => {
ast::ExprKind::Block(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
self.word_space(":")?;
}
// the block will close the pattern's ibox
self.print_block_unclosed_indent(blk, INDENT_UNIT)?;
......
......@@ -736,7 +736,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
expression.span,
expression.id)
}
ExprKind::Block(ref block) => visitor.visit_block(block),
ExprKind::Block(ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
}
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
visitor.visit_expr(left_hand_expression);
visitor.visit_expr(right_hand_expression);
......
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(label_break_value)]
// Test control flow to follow label_break_value semantics
fn label_break(a: bool, b: bool) -> u32 {
let mut v = 0;
'b: {
v = 1;
if a {
break 'b;
}
v = 2;
if b {
break 'b;
}
v = 3;
}
return v;
}
// Test that values can be returned
fn break_value(a: bool, b: bool) -> u32 {
let result = 'block: {
if a { break 'block 1; }
if b { break 'block 2; }
3
};
result
}
// Test nesting of labeled blocks
// here we only check that it compiles
fn label_break_nested() {
'b: {
println!("hi");
if false {
break 'b;
}
'c: {
if false {
break 'b;
}
break 'c;
}
println!("hello");
if true {
break 'b;
}
}
}
// Tests for mixing labeled blocks with loop constructs
// This function should be the identity function
fn label_break_mixed(v: u32) -> u32 {
let mut r = 0;
'b: {
// Unlabeled break still works
// (only crossing boundaries is an error)
loop {
break;
}
if v == 0 {
break 'b;
}
// Labeled breaking an inner loop still works
'c: loop {
if r == 1 {
break 'c;
}
r += 1;
}
assert_eq!(r, 1);
if v == 1 {
break 'b;
}
// Labeled breaking an outer loop still works
'd: loop {
'e: {
if v == r {
break 'b;
}
if r == 5 {
break 'd;
}
r += 1;
}
}
assert_eq!(r, 5);
assert!(v > r);
// Here we test return from inside a labeled block
return v;
}
r
}
pub fn main() {
assert_eq!(label_break(true, false), 1);
assert_eq!(label_break(false, true), 2);
assert_eq!(label_break(false, false), 3);
assert_eq!(break_value(true, false), 1);
assert_eq!(break_value(false, true), 2);
assert_eq!(break_value(false, false), 3);
assert_eq!(label_break_mixed(0), 0);
assert_eq!(label_break_mixed(1), 1);
assert_eq!(label_break_mixed(2), 2);
assert_eq!(label_break_mixed(3), 3);
assert_eq!(label_break_mixed(4), 4);
assert_eq!(label_break_mixed(5), 5);
assert_eq!(label_break_mixed(6), 6);
// FIXME: ensure that labeled blocks work if produced by macros and in match arms
}
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn main() {
'a: { //~ ERROR labels on blocks are unstable
break 'a;
}
}
error[E0658]: labels on blocks are unstable (see issue #48594)
--> $DIR/feature-gate-label_break_value.rs:12:5
|
LL | 'a: { //~ ERROR labels on blocks are unstable
| ^^
|
= help: add #![feature(label_break_value)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(label_break_value)]
// Simple continue pointing to an unlabeled break should yield in an error
fn continue_simple() {
'b: {
continue; //~ ERROR unlabeled `continue` inside of a labeled block
}
}
// Labeled continue pointing to an unlabeled break should yield in an error
fn continue_labeled() {
'b: {
continue 'b; //~ ERROR `continue` pointing to a labeled block
}
}
// Simple continue that would cross a labeled block should yield in an error
fn continue_crossing() {
loop {
'b: {
continue; //~ ERROR unlabeled `continue` inside of a labeled block
}
}
}
pub fn main() {}
error[E0695]: unlabeled `continue` inside of a labeled block
--> $DIR/label_break_value_continue.rs:16:9
|
LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block
| ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
error[E0696]: `continue` pointing to a labeled block
--> $DIR/label_break_value_continue.rs:23:9
|
LL | continue 'b; //~ ERROR `continue` pointing to a labeled block
| ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
|
note: labeled block the continue points to
--> $DIR/label_break_value_continue.rs:22:5
|
LL | / 'b: {
LL | | continue 'b; //~ ERROR `continue` pointing to a labeled block
LL | | }
| |_____^
error[E0695]: unlabeled `continue` inside of a labeled block
--> $DIR/label_break_value_continue.rs:31:13
|
LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block
| ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
error: aborting due to 3 previous errors
Some errors occurred: E0695, E0696.
For more information about an error, try `rustc --explain E0695`.
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(label_break_value)]
// These are forbidden occurences of label-break-value
fn labeled_unsafe() {
unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{`
}
fn labeled_if() {
if true 'b: {} //~ ERROR expected `{`, found `'b`
}
fn labeled_else() {
if true {} else 'b: {} //~ ERROR expected `{`, found `'b`
}
fn labeled_match() {
match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
}
pub fn main() {}
error: expected one of `extern`, `fn`, or `{`, found `'b`
--> $DIR/label_break_value_illegal_uses.rs:16:12
|
LL | unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{`
| ^^ expected one of `extern`, `fn`, or `{` here
error: expected `{`, found `'b`
--> $DIR/label_break_value_illegal_uses.rs:20:13
|
LL | if true 'b: {} //~ ERROR expected `{`, found `'b`
| -- ^^----
| | |
| | help: try placing this code inside a block: `{ 'b: { } }`
| this `if` statement has a condition, but no block
error: expected `{`, found `'b`
--> $DIR/label_break_value_illegal_uses.rs:24:21
|
LL | if true {} else 'b: {} //~ ERROR expected `{`, found `'b`
| ^^----
| |
| help: try placing this code inside a block: `{ 'b: { } }`
error: expected one of `.`, `?`, `{`, or an operator, found `'b`
--> $DIR/label_break_value_illegal_uses.rs:28:17
|
LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
| ^^ expected one of `.`, `?`, `{`, or an operator here
error: aborting due to 4 previous errors
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(label_break_value)]
// Simple unlabeled break should yield in an error
fn unlabeled_break_simple() {
'b: {
break; //~ ERROR unlabeled `break` inside of a labeled block
}
}
// Unlabeled break that would cross a labeled block should yield in an error
fn unlabeled_break_crossing() {
loop {
'b: {
break; //~ ERROR unlabeled `break` inside of a labeled block
}
}
}
pub fn main() {}
error[E0695]: unlabeled `break` inside of a labeled block
--> $DIR/label_break_value_unlabeled_break.rs:16:9
|
LL | break; //~ ERROR unlabeled `break` inside of a labeled block
| ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
error[E0695]: unlabeled `break` inside of a labeled block
--> $DIR/label_break_value_unlabeled_break.rs:24:13
|
LL | break; //~ ERROR unlabeled `break` inside of a labeled block
| ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0695`.
......@@ -2,7 +2,7 @@ error[E0571]: `break` with value from a `for` loop
--> $DIR/loop-break-value-no-repeat.rs:22:9
|
LL | break 22 //~ ERROR `break` with value from a `for` loop
| ^^^^^^^^ can only break with a value inside `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 //~ ERROR `break` with value from a `for` loop
......
......@@ -10,32 +10,49 @@
//! Tidy check to ensure that there are no stray `.stderr` files in UI test directories.
use std::fs;
use std::path::Path;
pub fn check(path: &Path, bad: &mut bool) {
super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
&mut |_| false,
&mut |file_path| {
if let Some(ext) = file_path.extension() {
if ext == "stderr" || ext == "stdout" {
// Test output filenames have the format:
// $testname.stderr
// $testname.$mode.stderr
// $testname.$revision.stderr
// $testname.$revision.$mode.stderr
//
// For now, just make sure that there is a corresponding
// $testname.rs file.
let testname = file_path.file_name().unwrap()
.to_str().unwrap()
.splitn(2, '.').next().unwrap();
if !file_path.with_file_name(testname)
.with_extension("rs")
.exists() {
println!("Stray file with UI testing output: {:?}", file_path);
*bad = true;
super::walk_many(
&[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
&mut |_| false,
&mut |file_path| {
if let Some(ext) = file_path.extension() {
if ext == "stderr" || ext == "stdout" {
// Test output filenames have the format:
// $testname.stderr
// $testname.$mode.stderr
// $testname.$revision.stderr
// $testname.$revision.$mode.stderr
//
// For now, just make sure that there is a corresponding
// $testname.rs file.
let testname = file_path
.file_name()
.unwrap()
.to_str()
.unwrap()
.splitn(2, '.')
.next()
.unwrap();
if !file_path
.with_file_name(testname)
.with_extension("rs")
.exists()
{
println!("Stray file with UI testing output: {:?}", file_path);
*bad = true;
}
if let Ok(metadata) = fs::metadata(file_path) {
if metadata.len() == 0 {
println!("Empty file with UI testing output: {:?}", file_path);
*bad = true;
}
}
}
}
}
});
},
);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册