Auto merge of #62075 - Centril:guardless-match-arms, r=petrochenkov
Remove `ast::Guard`
With the introduction of `ast::ExprKind::Let` in https://github.com/rust-lang/rust/pull/60861, the `ast::Guard` structure is now redundant in terms of representing [`if let` guards](https://github.com/rust-lang/rust/issues/51114) in AST since it can be represented by `ExprKind::Let` syntactically. Therefore, we remove `ast::Guard` here.
However, we keep `hir::Guard` because the semantic representation is a different matter and this story is more unclear right now (might involve `goto 'arm` in HIR or something...).
r? @petrochenkov
diff --git a/Cargo.lock b/Cargo.lock
index 40b8cf5..657831b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3801,9 +3801,11 @@
name = "tidy"
version = "0.1.0"
dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 74caaae..2f9bd06 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -709,8 +709,8 @@
if !builder.config.vendor {
cmd.arg("--no-vendor");
}
- if !builder.config.verbose_tests {
- cmd.arg("--quiet");
+ if builder.is_verbose() {
+ cmd.arg("--verbose");
}
let _folder = builder.fold_output(|| "tidy");
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 3947327..e1d0d5a 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -4344,53 +4344,147 @@
let ohs = P(self.lower_expr(ohs));
hir::ExprKind::AddrOf(m, ohs)
}
- // More complicated than you might expect because the else branch
- // might be `if let`.
- ExprKind::If(ref cond, ref then, ref else_opt) => {
- // `true => then`:
- let then_pat = self.pat_bool(e.span, true);
- let then_blk = self.lower_block(then, false);
- let then_expr = self.expr_block(then_blk, ThinVec::new());
- let then_arm = self.arm(hir_vec![then_pat], P(then_expr));
+ ExprKind::Let(ref pats, ref scrutinee) => {
+ // If we got here, the `let` expression is not allowed.
+ self.sess
+ .struct_span_err(e.span, "`let` expressions are not supported here")
+ .note("only supported directly in conditions of `if`- and `while`-expressions")
+ .note("as well as when nested within `&&` and parenthesis in those conditions")
+ .emit();
+ // For better recovery, we emit:
+ // ```
+ // match scrutinee { pats => true, _ => false }
+ // ```
+ // While this doesn't fully match the user's intent, it has key advantages:
+ // 1. We can avoid using `abort_if_errors`.
+ // 2. We can typeck both `pats` and `scrutinee`.
+ // 3. `pats` is allowed to be refutable.
+ // 4. The return type of the block is `bool` which seems like what the user wanted.
+ let scrutinee = self.lower_expr(scrutinee);
+ let then_arm = {
+ let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ let expr = self.expr_bool(e.span, true);
+ self.arm(pats, P(expr))
+ };
+ let else_arm = {
+ let pats = hir_vec![self.pat_wild(e.span)];
+ let expr = self.expr_bool(e.span, false);
+ self.arm(pats, P(expr))
+ };
+ hir::ExprKind::Match(
+ P(scrutinee),
+ vec![then_arm, else_arm].into(),
+ hir::MatchSource::Normal,
+ )
+ }
+ // FIXME(#53667): handle lowering of && and parens.
+ ExprKind::If(ref cond, ref then, ref else_opt) => {
// `_ => else_block` where `else_block` is `{}` if there's `None`:
let else_pat = self.pat_wild(e.span);
- let else_expr = match else_opt {
- None => self.expr_block_empty(e.span),
- Some(els) => match els.node {
- ExprKind::IfLet(..) => {
- // Wrap the `if let` expr in a block.
- let els = self.lower_expr(els);
- let blk = self.block_all(els.span, hir_vec![], Some(P(els)));
- self.expr_block(P(blk), ThinVec::new())
- }
- _ => self.lower_expr(els),
- }
+ let (else_expr, contains_else_clause) = match else_opt {
+ None => (self.expr_block_empty(e.span), false),
+ Some(els) => (self.lower_expr(els), true),
};
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
- // Lower condition:
- let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
- let cond = self.lower_expr(cond);
- // Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
- // semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
- let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
+ // Handle then + scrutinee:
+ let then_blk = self.lower_block(then, false);
+ let then_expr = self.expr_block(then_blk, ThinVec::new());
+ let (then_pats, scrutinee, desugar) = match cond.node {
+ // `<pat> => <then>`
+ ExprKind::Let(ref pats, ref scrutinee) => {
+ let scrutinee = self.lower_expr(scrutinee);
+ let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
+ (pats, scrutinee, desugar)
+ }
+ // `true => then`:
+ _ => {
+ // Lower condition:
+ let cond = self.lower_expr(cond);
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
+ // to preserve drop semantics since `if cond { ... }`
+ // don't let temporaries live outside of `cond`.
+ let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
+ // to preserve drop semantics since `if cond { ... }` does not
+ // let temporaries live outside of `cond`.
+ let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
- hir::ExprKind::Match(
- P(cond),
- vec![then_arm, else_arm].into(),
- hir::MatchSource::IfDesugar {
- contains_else_clause: else_opt.is_some()
- },
- )
+ let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
+ let pats = hir_vec![self.pat_bool(e.span, true)];
+ (pats, cond, desugar)
+ }
+ };
+ let then_arm = self.arm(then_pats, P(then_expr));
+
+ hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
}
- ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
- hir::ExprKind::While(
- this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
- this.lower_block(body, false),
- this.lower_label(opt_label),
- )
- }),
+ // FIXME(#53667): handle lowering of && and parens.
+ ExprKind::While(ref cond, ref body, opt_label) => {
+ // Desugar `ExprWhileLet`
+ // from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
+ if let ExprKind::Let(ref pats, ref sub_expr) = cond.node {
+ // to:
+ //
+ // [opt_ident]: loop {
+ // match <sub_expr> {
+ // <pat> => <body>,
+ // _ => break
+ // }
+ // }
+
+ // Note that the block AND the condition are evaluated in the loop scope.
+ // This is done to allow `break` from inside the condition of the loop.
+ let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
+ (
+ this.lower_block(body, false),
+ this.expr_break(e.span, ThinVec::new()),
+ this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
+ )
+ });
+
+ // `<pat> => <body>`
+ let pat_arm = {
+ let body_expr = P(self.expr_block(body, ThinVec::new()));
+ let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ self.arm(pats, body_expr)
+ };
+
+ // `_ => break`
+ let break_arm = {
+ let pat_under = self.pat_wild(e.span);
+ self.arm(hir_vec![pat_under], break_expr)
+ };
+
+ // `match <sub_expr> { ... }`
+ let arms = hir_vec![pat_arm, break_arm];
+ let match_expr = self.expr(
+ sub_expr.span,
+ hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
+ ThinVec::new(),
+ );
+
+ // `[opt_ident]: loop { ... }`
+ let loop_block = P(self.block_expr(P(match_expr)));
+ let loop_expr = hir::ExprKind::Loop(
+ loop_block,
+ self.lower_label(opt_label),
+ hir::LoopSource::WhileLet,
+ );
+ // Add attributes to the outer returned expr node.
+ loop_expr
+ } else {
+ self.with_loop_scope(e.id, |this| {
+ hir::ExprKind::While(
+ this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
+ this.lower_block(body, false),
+ this.lower_label(opt_label),
+ )
+ })
+ }
+ }
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::Loop(
this.lower_block(body, false),
@@ -4703,105 +4797,6 @@
ExprKind::Err => hir::ExprKind::Err,
- // Desugar `ExprIfLet`
- // from: `if let <pat> = <sub_expr> <body> [<else_opt>]`
- ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
- // to:
- //
- // match <sub_expr> {
- // <pat> => <body>,
- // _ => [<else_opt> | ()]
- // }
-
- let mut arms = vec![];
-
- // `<pat> => <body>`
- {
- let body = self.lower_block(body, false);
- let body_expr = P(self.expr_block(body, ThinVec::new()));
- let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
- arms.push(self.arm(pats, body_expr));
- }
-
- // _ => [<else_opt>|{}]
- {
- let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
- let wildcard_pattern = self.pat_wild(e.span);
- let body = if let Some(else_expr) = wildcard_arm {
- self.lower_expr(else_expr)
- } else {
- self.expr_block_empty(e.span)
- };
- arms.push(self.arm(hir_vec![wildcard_pattern], P(body)));
- }
-
- let contains_else_clause = else_opt.is_some();
-
- let sub_expr = P(self.lower_expr(sub_expr));
-
- hir::ExprKind::Match(
- sub_expr,
- arms.into(),
- hir::MatchSource::IfLetDesugar {
- contains_else_clause,
- },
- )
- }
-
- // Desugar `ExprWhileLet`
- // from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
- ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
- // to:
- //
- // [opt_ident]: loop {
- // match <sub_expr> {
- // <pat> => <body>,
- // _ => break
- // }
- // }
-
- // Note that the block AND the condition are evaluated in the loop scope.
- // This is done to allow `break` from inside the condition of the loop.
- let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
- (
- this.lower_block(body, false),
- this.expr_break(e.span, ThinVec::new()),
- this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
- )
- });
-
- // `<pat> => <body>`
- let pat_arm = {
- let body_expr = P(self.expr_block(body, ThinVec::new()));
- let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
- self.arm(pats, body_expr)
- };
-
- // `_ => break`
- let break_arm = {
- let pat_under = self.pat_wild(e.span);
- self.arm(hir_vec![pat_under], break_expr)
- };
-
- // `match <sub_expr> { ... }`
- let arms = hir_vec![pat_arm, break_arm];
- let match_expr = self.expr(
- sub_expr.span,
- hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
- ThinVec::new(),
- );
-
- // `[opt_ident]: loop { ... }`
- let loop_block = P(self.block_expr(P(match_expr)));
- let loop_expr = hir::ExprKind::Loop(
- loop_block,
- self.lower_label(opt_label),
- hir::LoopSource::WhileLet,
- );
- // Add attributes to the outer returned expr node.
- loop_expr
- }
-
// Desugar `ExprForLoop`
// from: `[opt_ident]: for <pat> in <head> <body>`
ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
@@ -5463,10 +5458,15 @@
)
}
+ /// Constructs a `true` or `false` literal expression.
+ fn expr_bool(&mut self, span: Span, val: bool) -> hir::Expr {
+ let lit = Spanned { span, node: LitKind::Bool(val) };
+ self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new())
+ }
+
/// Constructs a `true` or `false` literal pattern.
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
- let lit = Spanned { span, node: LitKind::Bool(val) };
- let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new());
+ let expr = self.expr_bool(span, val);
self.pat(span, hir::PatKind::Lit(P(expr)))
}
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index f84ce2f..b5c5fc0 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -324,20 +324,28 @@
value: &ast::Expr,
msg: &str,
followed_by_block: bool) {
- if let ast::ExprKind::Paren(ref inner) = value.node {
- let necessary = followed_by_block && match inner.node {
- ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
- _ => parser::contains_exterior_struct_lit(&inner),
- };
- if !necessary {
- let expr_text = if let Ok(snippet) = cx.sess().source_map()
- .span_to_snippet(value.span) {
- snippet
- } else {
- pprust::expr_to_string(value)
- };
- Self::remove_outer_parens(cx, value.span, &expr_text, msg);
+ match value.node {
+ ast::ExprKind::Paren(ref inner) => {
+ let necessary = followed_by_block && match inner.node {
+ ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
+ _ => parser::contains_exterior_struct_lit(&inner),
+ };
+ if !necessary {
+ let expr_text = if let Ok(snippet) = cx.sess().source_map()
+ .span_to_snippet(value.span) {
+ snippet
+ } else {
+ pprust::expr_to_string(value)
+ };
+ Self::remove_outer_parens(cx, value.span, &expr_text, msg);
+ }
}
+ ast::ExprKind::Let(_, ref expr) => {
+ // FIXME(#60336): Properly handle `let true = (false && true)`
+ // actually needing the parenthesis.
+ self.check_unused_parens_expr(cx, expr, "`let` head expression", followed_by_block);
+ }
+ _ => {}
}
}
@@ -399,8 +407,6 @@
let (value, msg, followed_by_block) = match e.node {
If(ref cond, ..) => (cond, "`if` condition", true),
While(ref cond, ..) => (cond, "`while` condition", true),
- IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
- WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
Match(ref head, _) => (head, "`match` head expression", true),
Ret(Some(ref value)) => (value, "`return` value", false),
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 00b6db0..2da9c5a 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -17,13 +17,11 @@
use syntax::feature_gate::is_builtin_attr;
use syntax::source_map::Spanned;
use syntax::symbol::{kw, sym};
-use syntax::ptr::P;
use syntax::visit::{self, Visitor};
use syntax::{span_err, struct_span_err, walk_list};
use syntax_ext::proc_macro_decls::is_proc_macro_attr;
use syntax_pos::{Span, MultiSpan};
use errors::{Applicability, FatalError};
-use log::debug;
#[derive(Copy, Clone, Debug)]
struct OuterImplTrait {
@@ -319,54 +317,6 @@
}
}
- /// With eRFC 2497, we need to check whether an expression is ambiguous and warn or error
- /// depending on the edition, this function handles that.
- fn while_if_let_ambiguity(&self, expr: &P<Expr>) {
- if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) {
- let mut err = self.err_handler().struct_span_err(
- span, &format!("ambiguous use of `{}`", op_kind.to_string())
- );
-
- err.note(
- "this will be a error until the `let_chains` feature is stabilized"
- );
- err.note(
- "see rust-lang/rust#53668 for more information"
- );
-
- if let Ok(snippet) = self.session.source_map().span_to_snippet(span) {
- err.span_suggestion(
- span, "consider adding parentheses", format!("({})", snippet),
- Applicability::MachineApplicable,
- );
- }
-
- err.emit();
- }
- }
-
- /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of
- /// `&&` and `||` in a if-let statement be unambiguous. This function returns a span and
- /// a `BinOpKind` (either `&&` or `||` depending on what was ambiguous) if it is determined
- /// that the current expression parsed is ambiguous and will break in future.
- fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> {
- debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node);
- match &expr.node {
- ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => {
- Some((expr.span, op.node))
- },
- ExprKind::Range(ref lhs, ref rhs, _) => {
- let lhs_ambiguous = lhs.as_ref()
- .and_then(|lhs| self.while_if_let_expr_ambiguity(lhs));
- let rhs_ambiguous = rhs.as_ref()
- .and_then(|rhs| self.while_if_let_expr_ambiguity(rhs));
-
- lhs_ambiguous.or(rhs_ambiguous)
- }
- _ => None,
- }
- }
-
fn check_fn_decl(&self, fn_decl: &FnDecl) {
fn_decl
.inputs
@@ -493,19 +443,17 @@
impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_expr(&mut self, expr: &'a Expr) {
- match expr.node {
- ExprKind::Closure(_, _, _, ref fn_decl, _, _) => {
+ match &expr.node {
+ ExprKind::Closure(_, _, _, fn_decl, _, _) => {
self.check_fn_decl(fn_decl);
}
- ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) =>
- self.while_if_let_ambiguity(&expr),
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
}
_ => {}
}
- visit::walk_expr(self, expr)
+ visit::walk_expr(self, expr);
}
fn visit_ty(&mut self, ty: &'a Ty) {
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index bf2f763..5f3d715 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -8,6 +8,7 @@
#![feature(in_band_lifetimes)]
#![feature(nll)]
+#![feature(bind_by_move_pattern_guards)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0b27bfd..3b418d0 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -485,8 +485,6 @@
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum PatternSource {
Match,
- IfLet,
- WhileLet,
Let,
For,
FnParam,
@@ -496,8 +494,6 @@
fn descr(self) -> &'static str {
match self {
PatternSource::Match => "match binding",
- PatternSource::IfLet => "if let binding",
- PatternSource::WhileLet => "while let binding",
PatternSource::Let => "let binding",
PatternSource::For => "for binding",
PatternSource::FnParam => "function parameter",
@@ -3057,13 +3053,7 @@
fn resolve_arm(&mut self, arm: &Arm) {
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
- let mut bindings_list = FxHashMap::default();
- for pattern in &arm.pats {
- self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
- }
-
- // This has to happen *after* we determine which pat_idents are variants.
- self.check_consistent_bindings(&arm.pats);
+ self.resolve_pats(&arm.pats, PatternSource::Match);
if let Some(ref expr) = arm.guard {
self.visit_expr(expr)
@@ -3073,6 +3063,16 @@
self.ribs[ValueNS].pop();
}
+ /// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
+ fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) {
+ let mut bindings_list = FxHashMap::default();
+ for pat in pats {
+ self.resolve_pattern(pat, source, &mut bindings_list);
+ }
+ // This has to happen *after* we determine which pat_idents are variants
+ self.check_consistent_bindings(pats);
+ }
+
fn resolve_block(&mut self, block: &Block) {
debug!("(resolving block) entering block");
// Move down in the graph, if there's an anonymous module rooted here.
@@ -3151,8 +3151,7 @@
);
}
Some(..) if pat_src == PatternSource::Match ||
- pat_src == PatternSource::IfLet ||
- pat_src == PatternSource::WhileLet => {
+ pat_src == PatternSource::Let => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident];
@@ -4345,41 +4344,26 @@
visit::walk_expr(self, expr);
}
- ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
- self.visit_expr(subexpression);
+ ExprKind::Let(ref pats, ref scrutinee) => {
+ self.visit_expr(scrutinee);
+ self.resolve_pats(pats, PatternSource::Let);
+ }
+ ExprKind::If(ref cond, ref then, ref opt_else) => {
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
- let mut bindings_list = FxHashMap::default();
- for pat in pats {
- self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list);
- }
- // This has to happen *after* we determine which pat_idents are variants
- self.check_consistent_bindings(pats);
- self.visit_block(if_block);
+ self.visit_expr(cond);
+ self.visit_block(then);
self.ribs[ValueNS].pop();
- optional_else.as_ref().map(|expr| self.visit_expr(expr));
+ opt_else.as_ref().map(|expr| self.visit_expr(expr));
}
ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
ExprKind::While(ref subexpression, ref block, label) => {
self.with_resolved_label(label, expr.id, |this| {
- this.visit_expr(subexpression);
- this.visit_block(block);
- });
- }
-
- ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => {
- self.with_resolved_label(label, expr.id, |this| {
- this.visit_expr(subexpression);
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
- let mut bindings_list = FxHashMap::default();
- for pat in pats {
- this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list);
- }
- // This has to happen *after* we determine which pat_idents are variants.
- this.check_consistent_bindings(pats);
+ this.visit_expr(subexpression);
this.visit_block(block);
this.ribs[ValueNS].pop();
});
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index fd746ef..beef9f1 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1580,17 +1580,9 @@
self.visit_expr(subexpression);
visit::walk_block(self, block);
}
- ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
+ ast::ExprKind::Let(ref pats, ref scrutinee) => {
self.process_var_decl_multi(pats);
- debug!("for loop, walk sub-expr: {:?}", subexpression.node);
- self.visit_expr(subexpression);
- visit::walk_block(self, block);
- }
- ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
- self.process_var_decl_multi(pats);
- self.visit_expr(subexpression);
- visit::walk_block(self, block);
- opt_else.as_ref().map(|el| self.visit_expr(el));
+ self.visit_expr(scrutinee);
}
ast::ExprKind::Repeat(ref element, ref count) => {
self.visit_expr(element);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 8a2b36e..f2fac16 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1027,10 +1027,9 @@
ExprKind::Unary(..) => ExprPrecedence::Unary,
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
+ ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::If(..) => ExprPrecedence::If,
- ExprKind::IfLet(..) => ExprPrecedence::IfLet,
ExprKind::While(..) => ExprPrecedence::While,
- ExprKind::WhileLet(..) => ExprPrecedence::WhileLet,
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
@@ -1111,26 +1110,20 @@
Cast(P<Expr>, P<Ty>),
/// A type ascription (e.g., `42: usize`).
Type(P<Expr>, P<Ty>),
+ /// A `let pats = expr` expression that is only semantically allowed in the condition
+ /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
+ ///
+ /// The `Vec<P<Pat>>` is for or-patterns at the top level.
+ /// FIXME(54883): Change this to just `P<Pat>`.
+ Let(Vec<P<Pat>>, P<Expr>),
/// An `if` block, with an optional `else` block.
///
/// `if expr { block } else { expr }`
If(P<Expr>, P<Block>, Option<P<Expr>>),
- /// An `if let` expression with an optional else block
- ///
- /// `if let pat = expr { block } else { expr }`
- ///
- /// This is desugared to a `match` expression.
- IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>),
- /// A while loop, with an optional label
+ /// A while loop, with an optional label.
///
/// `'label: while expr { block }`
While(P<Expr>, P<Block>, Option<Label>),
- /// A `while let` loop, with an optional label.
- ///
- /// `'label: while let pat = expr { block }`
- ///
- /// This is desugared to a combination of `loop` and `match` expressions.
- WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>),
/// A `for` loop, with an optional label.
///
/// `'label: for pat in expr { block }`
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index d5da4c9..92ce377 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -825,7 +825,9 @@
}
match name {
- sym::expr => token.can_begin_expr(),
+ sym::expr => token.can_begin_expr()
+ // This exception is here for backwards compatibility.
+ && !token.is_keyword(kw::Let),
sym::ty => token.can_begin_type(),
sym::ident => get_macro_name(token).is_some(),
sym::literal => token.can_begin_literal_or_bool(),
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 7f051c2..1a448cb 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -1,37 +1,37 @@
-use crate::{ast, attr};
use crate::edition::Edition;
-use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
+use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use crate::ext::expand::{AstFragment, AstFragmentKind};
use crate::ext::hygiene::Transparency;
-use crate::ext::tt::macro_parser::{Success, Error, Failure};
-use crate::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use crate::ext::tt::macro_parser::{parse, parse_failure_msg};
+use crate::ext::tt::macro_parser::{Error, Failure, Success};
+use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq};
use crate::ext::tt::quoted;
use crate::ext::tt::transcribe::transcribe;
use crate::feature_gate::Features;
-use crate::parse::{Directory, ParseSess};
use crate::parse::parser::Parser;
-use crate::parse::token::{self, Token, NtTT};
use crate::parse::token::TokenKind::*;
-use crate::symbol::{Symbol, kw, sym};
+use crate::parse::token::{self, NtTT, Token};
+use crate::parse::{Directory, ParseSess};
+use crate::symbol::{kw, sym, Symbol};
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use crate::{ast, attr};
use errors::FatalError;
-use syntax_pos::{Span, symbol::Ident};
use log::debug;
+use syntax_pos::{symbol::Ident, Span};
-use rustc_data_structures::fx::{FxHashMap};
+use rustc_data_structures::fx::FxHashMap;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::slice;
-use rustc_data_structures::sync::Lrc;
use errors::Applicability;
+use rustc_data_structures::sync::Lrc;
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
- `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, \
- `path`, `meta`, `tt`, `item` and `vis`";
+ `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
+ `literal`, `path`, `meta`, `tt`, `item` and `vis`";
pub struct ParserAnyMacro<'a> {
parser: Parser<'a>,
@@ -48,7 +48,8 @@
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
- if !e.span.is_dummy() { // early end of macro arm (#52866)
+ if !e.span.is_dummy() {
+ // early end of macro arm (#52866)
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
}
let msg = &e.message[0];
@@ -60,7 +61,8 @@
msg.1,
);
}
- if e.span.is_dummy() { // Get around lack of span in error (#30128)
+ if e.span.is_dummy() {
+ // Get around lack of span in error (#30128)
e.replace_span_with(site_span);
if parser.sess.source_map().span_to_filename(arm_span).is_real() {
e.span_label(arm_span, "in this macro arm");
@@ -99,17 +101,11 @@
sp: Span,
input: TokenStream,
def_span: Option<Span>,
- ) -> Box<dyn MacResult+'cx> {
+ ) -> Box<dyn MacResult + 'cx> {
if !self.valid {
return DummyResult::any(sp);
}
- generic_extension(cx,
- sp,
- def_span,
- self.name,
- input,
- &self.lhses,
- &self.rhses)
+ generic_extension(cx, sp, def_span, self.name, input, &self.lhses, &self.rhses)
}
}
@@ -119,14 +115,15 @@
}
/// Given `lhses` and `rhses`, this is the new macro we create
-fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
- sp: Span,
- def_span: Option<Span>,
- name: ast::Ident,
- arg: TokenStream,
- lhses: &[quoted::TokenTree],
- rhses: &[quoted::TokenTree])
- -> Box<dyn MacResult+'cx> {
+fn generic_extension<'cx>(
+ cx: &'cx mut ExtCtxt<'_>,
+ sp: Span,
+ def_span: Option<Span>,
+ name: ast::Ident,
+ arg: TokenStream,
+ lhses: &[quoted::TokenTree],
+ rhses: &[quoted::TokenTree],
+) -> Box<dyn MacResult + 'cx> {
if cx.trace_macros() {
trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg));
}
@@ -134,10 +131,11 @@
// Which arm's failure should we report? (the one furthest along)
let mut best_failure: Option<(Token, &str)> = None;
- for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
+ for (i, lhs) in lhses.iter().enumerate() {
+ // try each arm's matchers
let lhs_tt = match *lhs {
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
- _ => cx.span_bug(sp, "malformed macro lhs")
+ _ => cx.span_bug(sp, "malformed macro lhs"),
};
match TokenTree::parse(cx, lhs_tt, arg.clone()) {
@@ -173,8 +171,8 @@
ownership: cx.current_expansion.directory_ownership,
};
let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None);
- p.root_module_name = cx.current_expansion.module.mod_path.last()
- .map(|id| id.as_str().to_string());
+ p.root_module_name =
+ cx.current_expansion.module.mod_path.last().map(|id| id.as_str().to_string());
p.process_potential_macro_variable();
// Let the context choose how to interpret the result.
@@ -188,15 +186,13 @@
site_span: sp,
macro_ident: name,
arm_span,
- })
+ });
}
Failure(token, msg) => match best_failure {
Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {}
- _ => best_failure = Some((token, msg))
- }
- Error(err_sp, ref msg) => {
- cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..])
- }
+ _ => best_failure = Some((token, msg)),
+ },
+ Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]),
}
}
@@ -212,7 +208,8 @@
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
if let Some((arg, comma_span)) = arg.add_comma() {
- for lhs in lhses { // try each arm's matchers
+ for lhs in lhses {
+ // try each arm's matchers
let lhs_tt = match *lhs {
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
_ => continue,
@@ -249,7 +246,7 @@
sess: &ParseSess,
features: &Features,
def: &ast::Item,
- edition: Edition
+ edition: Edition,
) -> SyntaxExtension {
let lhs_nm = ast::Ident::new(sym::lhs, def.span);
let rhs_nm = ast::Ident::new(sym::rhs, def.span);
@@ -267,25 +264,32 @@
// ...quasiquoting this would be nice.
// These spans won't matter, anyways
let argument_gram = vec![
- quoted::TokenTree::Sequence(DelimSpan::dummy(), Lrc::new(quoted::SequenceRepetition {
- tts: vec![
- quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
- quoted::TokenTree::token(token::FatArrow, def.span),
- quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
- ],
- separator: Some(Token::new(
- if body.legacy { token::Semi } else { token::Comma }, def.span
- )),
- op: quoted::KleeneOp::OneOrMore,
- num_captures: 2,
- })),
+ quoted::TokenTree::Sequence(
+ DelimSpan::dummy(),
+ Lrc::new(quoted::SequenceRepetition {
+ tts: vec![
+ quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
+ quoted::TokenTree::token(token::FatArrow, def.span),
+ quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
+ ],
+ separator: Some(Token::new(
+ if body.legacy { token::Semi } else { token::Comma },
+ def.span,
+ )),
+ op: quoted::KleeneOp::OneOrMore,
+ num_captures: 2,
+ }),
+ ),
// to phase into semicolon-termination instead of semicolon-separation
- quoted::TokenTree::Sequence(DelimSpan::dummy(), Lrc::new(quoted::SequenceRepetition {
- tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
- separator: None,
- op: quoted::KleeneOp::ZeroOrMore,
- num_captures: 0
- })),
+ quoted::TokenTree::Sequence(
+ DelimSpan::dummy(),
+ Lrc::new(quoted::SequenceRepetition {
+ tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
+ separator: None,
+ op: quoted::KleeneOp::ZeroOrMore,
+ num_captures: 0,
+ }),
+ ),
];
let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) {
@@ -307,8 +311,9 @@
// Extract the arguments:
let lhses = match *argument_map[&lhs_nm] {
- MatchedSeq(ref s, _) => {
- s.iter().map(|m| {
+ MatchedSeq(ref s, _) => s
+ .iter()
+ .map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
let tt = quoted::parse(
@@ -327,14 +332,15 @@
}
}
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
- }).collect::<Vec<quoted::TokenTree>>()
- }
- _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+ })
+ .collect::<Vec<quoted::TokenTree>>(),
+ _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
};
let rhses = match *argument_map[&rhs_nm] {
- MatchedSeq(ref s, _) => {
- s.iter().map(|m| {
+ MatchedSeq(ref s, _) => s
+ .iter()
+ .map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
return quoted::parse(
@@ -345,14 +351,15 @@
&def.attrs,
edition,
def.id,
- ).pop()
- .unwrap();
+ )
+ .pop()
+ .unwrap();
}
}
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
- }).collect::<Vec<quoted::TokenTree>>()
- }
- _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
+ })
+ .collect::<Vec<quoted::TokenTree>>(),
+ _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
};
for rhs in &rhses {
@@ -366,16 +373,12 @@
sess,
slice::from_ref(lhs),
&mut FxHashMap::default(),
- def.id
+ def.id,
);
}
- let expander: Box<_> = Box::new(MacroRulesMacroExpander {
- name: def.ident,
- lhses,
- rhses,
- valid,
- });
+ let expander: Box<_> =
+ Box::new(MacroRulesMacroExpander { name: def.ident, lhses, rhses, valid });
let default_transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
Transparency::Transparent
@@ -385,29 +388,34 @@
Transparency::Opaque
};
- let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
- .map(|attr| attr
- .meta_item_list()
- .map(|list| list.iter()
- .filter_map(|it| {
- let name = it.ident().map(|ident| ident.name);
- if name.is_none() {
- sess.span_diagnostic.span_err(it.span(),
- "allow internal unstable expects feature names")
- }
- name
+ let allow_internal_unstable =
+ attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| {
+ attr.meta_item_list()
+ .map(|list| {
+ list.iter()
+ .filter_map(|it| {
+ let name = it.ident().map(|ident| ident.name);
+ if name.is_none() {
+ sess.span_diagnostic.span_err(
+ it.span(),
+ "allow internal unstable expects feature names",
+ )
+ }
+ name
+ })
+ .collect::<Vec<Symbol>>()
+ .into()
})
- .collect::<Vec<Symbol>>().into()
- )
- .unwrap_or_else(|| {
- sess.span_diagnostic.span_warn(
- attr.span, "allow_internal_unstable expects list of feature names. In the \
- future this will become a hard error. Please use `allow_internal_unstable(\
- foo, bar)` to only allow the `foo` and `bar` features",
- );
- vec![sym::allow_internal_unstable_backcompat_hack].into()
- })
- );
+ .unwrap_or_else(|| {
+ sess.span_diagnostic.span_warn(
+ attr.span,
+ "allow_internal_unstable expects list of feature names. In the \
+ future this will become a hard error. Please use `allow_internal_unstable(\
+ foo, bar)` to only allow the `foo` and `bar` features",
+ );
+ vec![sym::allow_internal_unstable_backcompat_hack].into()
+ })
+ });
let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
@@ -418,14 +426,14 @@
}
}
- let unstable_feature = attr::find_stability(&sess,
- &def.attrs, def.span).and_then(|stability| {
- if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
- Some((stability.feature, issue))
- } else {
- None
- }
- });
+ let unstable_feature =
+ attr::find_stability(&sess, &def.attrs, def.span).and_then(|stability| {
+ if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
+ Some((stability.feature, issue))
+ } else {
+ None
+ }
+ });
SyntaxExtension {
kind: SyntaxExtensionKind::LegacyBang(expander),
@@ -440,10 +448,12 @@
}
}
-fn check_lhs_nt_follows(sess: &ParseSess,
- features: &Features,
- attrs: &[ast::Attribute],
- lhs: "ed::TokenTree) -> bool {
+fn check_lhs_nt_follows(
+ sess: &ParseSess,
+ features: &Features,
+ attrs: &[ast::Attribute],
+ lhs: "ed::TokenTree,
+) -> bool {
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
if let quoted::TokenTree::Delimited(_, ref tts) = *lhs {
@@ -464,19 +474,22 @@
for tt in tts {
match *tt {
TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
- TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) {
- return false;
- },
+ TokenTree::Delimited(_, ref del) => {
+ if !check_lhs_no_empty_seq(sess, &del.tts) {
+ return false;
+ }
+ }
TokenTree::Sequence(span, ref seq) => {
- if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| {
- match *seq_tt {
+ if seq.separator.is_none()
+ && seq.tts.iter().all(|seq_tt| match *seq_tt {
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
- TokenTree::Sequence(_, ref sub_seq) =>
+ TokenTree::Sequence(_, ref sub_seq) => {
sub_seq.op == quoted::KleeneOp::ZeroOrMore
- || sub_seq.op == quoted::KleeneOp::ZeroOrOne,
+ || sub_seq.op == quoted::KleeneOp::ZeroOrOne
+ }
_ => false,
- }
- }) {
+ })
+ {
let sp = span.entire();
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
return false;
@@ -517,7 +530,7 @@
if !check_lhs_duplicate_matcher_bindings(sess, &del.tts, metavar_names, node_id) {
return false;
}
- },
+ }
TokenTree::Sequence(_, ref seq) => {
if !check_lhs_duplicate_matcher_bindings(sess, &seq.tts, metavar_names, node_id) {
return false;
@@ -533,15 +546,17 @@
fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool {
match *rhs {
quoted::TokenTree::Delimited(..) => return true,
- _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited")
+ _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"),
}
false
}
-fn check_matcher(sess: &ParseSess,
- features: &Features,
- attrs: &[ast::Attribute],
- matcher: &[quoted::TokenTree]) -> bool {
+fn check_matcher(
+ sess: &ParseSess,
+ features: &Features,
+ attrs: &[ast::Attribute],
+ matcher: &[quoted::TokenTree],
+) -> bool {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
let err = sess.span_diagnostic.err_count();
@@ -620,8 +635,8 @@
// Reverse scan: Sequence comes before `first`.
if subfirst.maybe_empty
- || seq_rep.op == quoted::KleeneOp::ZeroOrMore
- || seq_rep.op == quoted::KleeneOp::ZeroOrOne
+ || seq_rep.op == quoted::KleeneOp::ZeroOrMore
+ || seq_rep.op == quoted::KleeneOp::ZeroOrOne
{
// If sequence is potentially empty, then
// union them (preserving first emptiness).
@@ -659,7 +674,6 @@
TokenTree::Sequence(sp, ref seq_rep) => {
match self.first.get(&sp.entire()) {
Some(&Some(ref subfirst)) => {
-
// If the sequence contents can be empty, then the first
// token could be the separator token itself.
@@ -670,8 +684,8 @@
assert!(first.maybe_empty);
first.add_all(subfirst);
if subfirst.maybe_empty
- || seq_rep.op == quoted::KleeneOp::ZeroOrMore
- || seq_rep.op == quoted::KleeneOp::ZeroOrOne
+ || seq_rep.op == quoted::KleeneOp::ZeroOrMore
+ || seq_rep.op == quoted::KleeneOp::ZeroOrOne
{
// continue scanning for more first
// tokens, but also make sure we
@@ -720,7 +734,9 @@
impl TokenSet {
// Returns a set for the empty sequence.
- fn empty() -> Self { TokenSet { tokens: Vec::new(), maybe_empty: true } }
+ fn empty() -> Self {
+ TokenSet { tokens: Vec::new(), maybe_empty: true }
+ }
// Returns the set `{ tok }` for the single-token (and thus
// non-empty) sequence [tok].
@@ -789,12 +805,14 @@
//
// Requires that `first_sets` is pre-computed for `matcher`;
// see `FirstSets::new`.
-fn check_matcher_core(sess: &ParseSess,
- features: &Features,
- attrs: &[ast::Attribute],
- first_sets: &FirstSets,
- matcher: &[quoted::TokenTree],
- follow: &TokenSet) -> TokenSet {
+fn check_matcher_core(
+ sess: &ParseSess,
+ features: &Features,
+ attrs: &[ast::Attribute],
+ first_sets: &FirstSets,
+ matcher: &[quoted::TokenTree],
+ follow: &TokenSet,
+) -> TokenSet {
use quoted::TokenTree;
let mut last = TokenSet::empty();
@@ -804,11 +822,13 @@
// then ensure T can also be followed by any element of FOLLOW.
'each_token: for i in 0..matcher.len() {
let token = &matcher[i];
- let suffix = &matcher[i+1..];
+ let suffix = &matcher[i + 1..];
let build_suffix_first = || {
let mut s = first_sets.first(suffix);
- if s.maybe_empty { s.add_all(follow); }
+ if s.maybe_empty {
+ s.add_all(follow);
+ }
s
};
@@ -824,7 +844,8 @@
let can_be_followed_by_any;
if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) {
let msg = format!("invalid fragment specifier `{}`", bad_frag);
- sess.span_diagnostic.struct_span_err(token.span(), &msg)
+ sess.span_diagnostic
+ .struct_span_err(token.span(), &msg)
.help(VALID_FRAGMENT_NAMES_MSG)
.emit();
// (This eliminates false positives and duplicates
@@ -879,12 +900,8 @@
// At this point, `suffix_first` is built, and
// `my_suffix` is some TokenSet that we can use
// for checking the interior of `seq_rep`.
- let next = check_matcher_core(sess,
- features,
- attrs,
- first_sets,
- &seq_rep.tts,
- my_suffix);
+ let next =
+ check_matcher_core(sess, features, attrs, first_sets, &seq_rep.tts, my_suffix);
if next.maybe_empty {
last.add_all(&next);
} else {
@@ -906,16 +923,17 @@
for next_token in &suffix_first.tokens {
match is_in_follow(next_token, &frag_spec.as_str()) {
IsInFollow::Invalid(msg, help) => {
- sess.span_diagnostic.struct_span_err(next_token.span(), &msg)
- .help(help).emit();
+ sess.span_diagnostic
+ .struct_span_err(next_token.span(), &msg)
+ .help(help)
+ .emit();
// don't bother reporting every source of
// conflict for a particular element of `last`.
continue 'each_last;
}
IsInFollow::Yes => {}
IsInFollow::No(possible) => {
- let may_be = if last.tokens.len() == 1 &&
- suffix_first.tokens.len() == 1
+ let may_be = if last.tokens.len() == 1 && suffix_first.tokens.len() == 1
{
"is"
} else {
@@ -925,12 +943,14 @@
let sp = next_token.span();
let mut err = sess.span_diagnostic.struct_span_err(
sp,
- &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
- is not allowed for `{frag}` fragments",
- name=name,
- frag=frag_spec,
- next=quoted_tt_to_string(next_token),
- may_be=may_be),
+ &format!(
+ "`${name}:{frag}` {may_be} followed by `{next}`, which \
+ is not allowed for `{frag}` fragments",
+ name = name,
+ frag = frag_spec,
+ next = quoted_tt_to_string(next_token),
+ may_be = may_be
+ ),
);
err.span_label(
sp,
@@ -942,16 +962,18 @@
&[t] => {
err.note(&format!(
"only {} is allowed after `{}` fragments",
- t,
- frag_spec,
+ t, frag_spec,
));
}
ts => {
err.note(&format!(
"{}{} or {}",
msg,
- ts[..ts.len() - 1].iter().map(|s| *s)
- .collect::<Vec<_>>().join(", "),
+ ts[..ts.len() - 1]
+ .iter()
+ .map(|s| *s)
+ .collect::<Vec<_>>()
+ .join(", "),
ts[ts.len() - 1],
));
}
@@ -1026,13 +1048,13 @@
// since items *must* be followed by either a `;` or a `}`, we can
// accept anything after them
IsInFollow::Yes
- },
+ }
"block" => {
// anything can follow block, the braces provide an easy boundary to
// maintain
IsInFollow::Yes
- },
- "stmt" | "expr" => {
+ }
+ "stmt" | "expr" => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
match tok {
TokenTree::Token(token) => match token.kind {
@@ -1041,7 +1063,7 @@
},
_ => IsInFollow::No(TOKENS),
}
- },
+ }
"pat" => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
match tok {
@@ -1052,40 +1074,48 @@
},
_ => IsInFollow::No(TOKENS),
}
- },
+ }
"path" | "ty" => {
const TOKENS: &[&str] = &[
- "`{`", "`[`", "`=>`", "`,`", "`>`","`=`", "`:`", "`;`", "`|`", "`as`",
+ "`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`",
"`where`",
];
match tok {
TokenTree::Token(token) => match token.kind {
- OpenDelim(token::DelimToken::Brace) |
- OpenDelim(token::DelimToken::Bracket) |
- Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi |
- BinOp(token::Or) => IsInFollow::Yes,
- Ident(name, false) if name == kw::As ||
- name == kw::Where => IsInFollow::Yes,
+ OpenDelim(token::DelimToken::Brace)
+ | OpenDelim(token::DelimToken::Bracket)
+ | Comma
+ | FatArrow
+ | Colon
+ | Eq
+ | Gt
+ | BinOp(token::Shr)
+ | Semi
+ | BinOp(token::Or) => IsInFollow::Yes,
+ Ident(name, false) if name == kw::As || name == kw::Where => {
+ IsInFollow::Yes
+ }
_ => IsInFollow::No(TOKENS),
},
- TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block =>
- IsInFollow::Yes,
+ TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block => {
+ IsInFollow::Yes
+ }
_ => IsInFollow::No(TOKENS),
}
- },
+ }
"ident" | "lifetime" => {
// being a single token, idents and lifetimes are harmless
IsInFollow::Yes
- },
+ }
"literal" => {
// literals may be of a single token, or two tokens (negative numbers)
IsInFollow::Yes
- },
+ }
"meta" | "tt" => {
// being either a single token or a delimited sequence, tt is
// harmless
IsInFollow::Yes
- },
+ }
"vis" => {
// Explicitly disallow `priv`, on the off chance it comes back.
const TOKENS: &[&str] = &["`,`", "an ident", "a type"];
@@ -1093,30 +1123,39 @@
TokenTree::Token(token) => match token.kind {
Comma => IsInFollow::Yes,
Ident(name, is_raw) if is_raw || name != kw::Priv => IsInFollow::Yes,
- _ => if token.can_begin_type() {
- IsInFollow::Yes
- } else {
- IsInFollow::No(TOKENS)
+ _ => {
+ if token.can_begin_type() {
+ IsInFollow::Yes
+ } else {
+ IsInFollow::No(TOKENS)
+ }
}
},
- TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::ident
- || frag.name == sym::ty
- || frag.name == sym::path =>
- IsInFollow::Yes,
+ TokenTree::MetaVarDecl(_, _, frag)
+ if frag.name == sym::ident
+ || frag.name == sym::ty
+ || frag.name == sym::path =>
+ {
+ IsInFollow::Yes
+ }
_ => IsInFollow::No(TOKENS),
}
- },
+ }
"" => IsInFollow::Yes, // kw::Invalid
- _ => IsInFollow::Invalid(format!("invalid fragment specifier `{}`", frag),
- VALID_FRAGMENT_NAMES_MSG),
+ _ => IsInFollow::Invalid(
+ format!("invalid fragment specifier `{}`", frag),
+ VALID_FRAGMENT_NAMES_MSG,
+ ),
}
}
}
-fn has_legal_fragment_specifier(sess: &ParseSess,
- features: &Features,
- attrs: &[ast::Attribute],
- tok: "ed::TokenTree) -> Result<(), String> {
+fn has_legal_fragment_specifier(
+ sess: &ParseSess,
+ features: &Features,
+ attrs: &[ast::Attribute],
+ tok: "ed::TokenTree,
+) -> Result<(), String> {
debug!("has_legal_fragment_specifier({:?})", tok);
if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
let frag_span = tok.span();
@@ -1127,11 +1166,13 @@
Ok(())
}
-fn is_legal_fragment_specifier(_sess: &ParseSess,
- _features: &Features,
- _attrs: &[ast::Attribute],
- frag_name: Symbol,
- _frag_span: Span) -> bool {
+fn is_legal_fragment_specifier(
+ _sess: &ParseSess,
+ _features: &Features,
+ _attrs: &[ast::Attribute],
+ frag_name: Symbol,
+ _frag_span: Span,
+) -> bool {
/*
* If new fragment specifiers are invented in nightly, `_sess`,
* `_features`, `_attrs`, and `_frag_span` will be useful here
@@ -1139,9 +1180,20 @@
* this function.
*/
match frag_name {
- sym::item | sym::block | sym::stmt | sym::expr | sym::pat |
- sym::lifetime | sym::path | sym::ty | sym::ident | sym::meta | sym::tt |
- sym::vis | sym::literal | kw::Invalid => true,
+ sym::item
+ | sym::block
+ | sym::stmt
+ | sym::expr
+ | sym::pat
+ | sym::lifetime
+ | sym::path
+ | sym::ty
+ | sym::ident
+ | sym::meta
+ | sym::tt
+ | sym::vis
+ | sym::literal
+ | kw::Invalid => true,
_ => false,
}
}
@@ -1151,7 +1203,9 @@
quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
quoted::TokenTree::MetaVar(_, name) => format!("${}", name),
quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
- _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} \
- in follow set checker"),
+ _ => panic!(
+ "unexpected quoted::TokenTree::{{Sequence or Delimited}} \
+ in follow set checker"
+ ),
}
}
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index b52e3b7..6f5ce89 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -1,12 +1,12 @@
+use crate::ast;
use crate::ast::NodeId;
use crate::ext::tt::macro_parser;
use crate::feature_gate::Features;
use crate::parse::token::{self, Token, TokenKind};
use crate::parse::ParseSess;
use crate::print::pprust;
-use crate::tokenstream::{self, DelimSpan};
-use crate::ast;
use crate::symbol::kw;
+use crate::tokenstream::{self, DelimSpan};
use syntax_pos::{edition::Edition, BytePos, Span};
@@ -137,8 +137,7 @@
TokenTree::Token(Token { span, .. })
| TokenTree::MetaVar(span, _)
| TokenTree::MetaVarDecl(span, _, _) => span,
- TokenTree::Delimited(span, _)
- | TokenTree::Sequence(span, _) => span.entire(),
+ TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
}
}
@@ -199,7 +198,7 @@
match tree {
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
let span = match trees.next() {
- Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) =>
+ Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
match trees.next() {
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
Some((kind, _)) => {
@@ -209,22 +208,13 @@
}
_ => token.span,
},
- tree => tree
- .as_ref()
- .map(tokenstream::TokenTree::span)
- .unwrap_or(span),
- },
- tree => tree
- .as_ref()
- .map(tokenstream::TokenTree::span)
- .unwrap_or(start_sp),
+ tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+ }
+ }
+ tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
};
sess.missing_fragment_specifiers.borrow_mut().insert(span);
- result.push(TokenTree::MetaVarDecl(
- span,
- ident,
- ast::Ident::invalid(),
- ));
+ result.push(TokenTree::MetaVarDecl(span, ident, ast::Ident::invalid()));
}
// Not a metavar or no matchers allowed, so just return the tree
@@ -311,10 +301,8 @@
// `tree` is followed by a random token. This is an error.
Some(tokenstream::TokenTree::Token(token)) => {
- let msg = format!(
- "expected identifier, found `{}`",
- pprust::token_to_string(&token),
- );
+ let msg =
+ format!("expected identifier, found `{}`", pprust::token_to_string(&token),);
sess.span_diagnostic.span_err(token.span, &msg);
TokenTree::MetaVar(token.span, ast::Ident::invalid())
}
@@ -371,10 +359,7 @@
Some(op) => Ok(Ok((op, token.span))),
None => Ok(Err(token)),
},
- tree => Err(tree
- .as_ref()
- .map(tokenstream::TokenTree::span)
- .unwrap_or(span)),
+ tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)),
}
}
@@ -426,8 +411,7 @@
};
// If we ever get to this point, we have experienced an "unexpected token" error
- sess.span_diagnostic
- .span_err(span, "expected one of: `*`, `+`, or `?`");
+ sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
// Return a dummy
(None, KleeneOp::ZeroOrMore)
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 7f80e20..8ec07de 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -560,6 +560,9 @@
// Allows calling constructor functions in `const fn`.
(active, const_constructor, "1.37.0", Some(61456), None),
+ // Allows `if/while p && let q = r && ...` chains.
+ (active, let_chains, "1.37.0", Some(53667), None),
+
// #[repr(transparent)] on enums.
(active, transparent_enums, "1.37.0", Some(60405), None),
@@ -577,7 +580,8 @@
const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::impl_trait_in_bindings,
sym::generic_associated_types,
- sym::const_generics
+ sym::const_generics,
+ sym::let_chains,
];
declare_features! (
@@ -2517,6 +2521,17 @@
"attributes on function parameters are unstable"
));
+ sess
+ .let_chains_spans
+ .borrow()
+ .iter()
+ .for_each(|span| gate_feature!(
+ &ctx,
+ let_chains,
+ *span,
+ "`let` expressions in this position are experimental"
+ ));
+
let visitor = &mut PostExpansionVisitor {
context: &ctx,
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 076557a..e23bc02 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -1100,28 +1100,20 @@
vis.visit_ty(ty);
}
ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs),
+ ExprKind::Let(pats, scrutinee) => {
+ visit_vec(pats, |pat| vis.visit_pat(pat));
+ vis.visit_expr(scrutinee);
+ }
ExprKind::If(cond, tr, fl) => {
vis.visit_expr(cond);
vis.visit_block(tr);
visit_opt(fl, |fl| vis.visit_expr(fl));
}
- ExprKind::IfLet(pats, expr, tr, fl) => {
- visit_vec(pats, |pat| vis.visit_pat(pat));
- vis.visit_expr(expr);
- vis.visit_block(tr);
- visit_opt(fl, |fl| vis.visit_expr(fl));
- }
ExprKind::While(cond, body, label) => {
vis.visit_expr(cond);
vis.visit_block(body);
visit_opt(label, |label| vis.visit_label(label));
}
- ExprKind::WhileLet(pats, expr, body, label) => {
- visit_vec(pats, |pat| vis.visit_pat(pat));
- vis.visit_expr(expr);
- vis.visit_block(body);
- visit_opt(label, |label| vis.visit_label(label));
- }
ExprKind::ForLoop(pat, iter, body, label) => {
vis.visit_pat(pat);
vis.visit_expr(iter);
diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs
index dfd6f45..6ebfab3 100644
--- a/src/libsyntax/parse/classify.rs
+++ b/src/libsyntax/parse/classify.rs
@@ -14,11 +14,9 @@
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
match e.node {
ast::ExprKind::If(..) |
- ast::ExprKind::IfLet(..) |
ast::ExprKind::Match(..) |
ast::ExprKind::Block(..) |
ast::ExprKind::While(..) |
- ast::ExprKind::WhileLet(..) |
ast::ExprKind::Loop(..) |
ast::ExprKind::ForLoop(..) |
ast::ExprKind::TryBlock(..) => false,
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 1c44155..ead5d54 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1491,6 +1491,7 @@
edition: Edition::from_session(),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
+ let_chains_spans: Lock::new(Vec::new()),
}
}
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index ba5d1d0..e19eab3 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -54,7 +54,9 @@
/// operation token that followed it, but that the parser cannot identify without further
/// analysis.
pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
- pub param_attr_spans: Lock<Vec<Span>>
+ pub param_attr_spans: Lock<Vec<Span>>,
+ // Places where `let` exprs were used and should be feature gated according to `let_chains`.
+ pub let_chains_spans: Lock<Vec<Span>>,
}
impl ParseSess {
@@ -81,6 +83,7 @@
edition: Edition::from_session(),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
+ let_chains_spans: Lock::new(Vec::new()),
}
}
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 7b91ad4..f3ace84 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -41,7 +41,7 @@
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use crate::parse::token::{Token, TokenKind, DelimToken};
use crate::parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
-use crate::util::parser::{AssocOp, Fixity};
+use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
use crate::print::pprust;
use crate::ptr::P;
use crate::parse::PResult;
@@ -2215,13 +2215,8 @@
} else {
ex = ExprKind::Yield(None);
}
- } else if self.token.is_keyword(kw::Let) {
- // Catch this syntax error here, instead of in `parse_ident`, so
- // that we can explicitly mention that let is not to be used as an expression
- let mut db = self.fatal("expected expression, found statement (`let`)");
- db.span_label(self.token.span, "expected expression");
- db.note("variable declaration using `let` is a statement");
- return Err(db);
+ } else if self.eat_keyword(kw::Let) {
+ return self.parse_let_expr(attrs);
} else if is_span_rust_2018 && self.eat_keyword(kw::Await) {
let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
hi = await_hi;
@@ -2483,15 +2478,13 @@
attrs.extend::<Vec<_>>(expr.attrs.into());
expr.attrs = attrs;
match expr.node {
- ExprKind::If(..) | ExprKind::IfLet(..) => {
- if !expr.attrs.is_empty() {
- // Just point to the first attribute in there...
- let span = expr.attrs[0].span;
+ ExprKind::If(..) if !expr.attrs.is_empty() => {
+ // Just point to the first attribute in there...
+ let span = expr.attrs[0].span;
- self.span_err(span,
- "attributes are not yet allowed on `if` \
- expressions");
- }
+ self.span_err(span,
+ "attributes are not yet allowed on `if` \
+ expressions");
}
_ => {}
}
@@ -3161,13 +3154,10 @@
}
}
- /// Parses an `if` or `if let` expression (`if` token already eaten).
+ /// Parses an `if` expression (`if` token already eaten).
fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
- if self.check_keyword(kw::Let) {
- return self.parse_if_let_expr(attrs);
- }
let lo = self.prev_span;
- let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
+ let cond = self.parse_cond_expr()?;
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
@@ -3197,22 +3187,32 @@
Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
}
- /// Parses an `if let` expression (`if` token already eaten).
- fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
- -> PResult<'a, P<Expr>> {
+ /// Parse the condition of a `if`- or `while`-expression
+ fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
+ let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
+
+ if let ExprKind::Let(..) = cond.node {
+ // Remove the last feature gating of a `let` expression since it's stable.
+ let last = self.sess.let_chains_spans.borrow_mut().pop();
+ debug_assert_eq!(cond.span, last.unwrap());
+ }
+
+ Ok(cond)
+ }
+
+ /// Parses a `let $pats = $expr` pseudo-expression.
+ /// The `let` token has already been eaten.
+ fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let lo = self.prev_span;
- self.expect_keyword(kw::Let)?;
let pats = self.parse_pats()?;
self.expect(&token::Eq)?;
- let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
- let thn = self.parse_block()?;
- let (hi, els) = if self.eat_keyword(kw::Else) {
- let expr = self.parse_else_expr()?;
- (expr.span, Some(expr))
- } else {
- (thn.span, None)
- };
- Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
+ let expr = self.with_res(
+ Restrictions::NO_STRUCT_LITERAL,
+ |this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
+ )?;
+ let span = lo.to(expr.span);
+ self.sess.let_chains_spans.borrow_mut().push(span);
+ Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs))
}
/// Parses `move |args| expr`.
@@ -3299,28 +3299,11 @@
fn parse_while_expr(&mut self, opt_label: Option<Label>,
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
- if self.token.is_keyword(kw::Let) {
- return self.parse_while_let_expr(opt_label, span_lo, attrs);
- }
- let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
+ let cond = self.parse_cond_expr()?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let span = span_lo.to(body.span);
- return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs));
- }
-
- /// Parses a `while let` expression (`while` token already eaten).
- fn parse_while_let_expr(&mut self, opt_label: Option<Label>,
- span_lo: Span,
- mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
- self.expect_keyword(kw::Let)?;
- let pats = self.parse_pats()?;
- self.expect(&token::Eq)?;
- let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
- let (iattrs, body) = self.parse_inner_attrs_and_block()?;
- attrs.extend(iattrs);
- let span = span_lo.to(body.span);
- return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
+ Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs))
}
// parse `loop {...}`, `loop` token already eaten
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index cc34883..ebd0dec 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -135,6 +135,7 @@
kw::False,
kw::For,
kw::If,
+ kw::Let,
kw::Loop,
kw::Match,
kw::Move,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 9edd095..3f05992 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1715,6 +1715,21 @@
self.ann.post(self, AnnNode::Block(blk))
}
+ /// Print a `let pats = scrutinee` expression.
+ pub fn print_let(&mut self, pats: &[P<ast::Pat>], scrutinee: &ast::Expr) -> io::Result<()> {
+ self.s.word("let ")?;
+
+ self.print_pats(pats)?;
+ self.s.space()?;
+
+ self.word_space("=")?;
+ self.print_expr_cond_paren(
+ scrutinee,
+ Self::cond_needs_par(scrutinee)
+ || parser::needs_par_as_let_scrutinee(scrutinee.precedence().order())
+ )
+ }
+
fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
match els {
Some(_else) => {
@@ -1729,19 +1744,6 @@
self.print_block(then)?;
self.print_else(e.as_ref().map(|e| &**e))
}
- // Another `else if let` block.
- ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
- self.cbox(INDENT_UNIT - 1)?;
- self.ibox(0)?;
- self.s.word(" else if let ")?;
- self.print_pats(pats)?;
- self.s.space()?;
- self.word_space("=")?;
- self.print_expr_as_cond(expr)?;
- self.s.space()?;
- self.print_block(then)?;
- self.print_else(e.as_ref().map(|e| &**e))
- }
// Final `else` block.
ast::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1)?;
@@ -1762,20 +1764,10 @@
pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
elseopt: Option<&ast::Expr>) -> io::Result<()> {
self.head("if")?;
+
self.print_expr_as_cond(test)?;
self.s.space()?;
- self.print_block(blk)?;
- self.print_else(elseopt)
- }
- pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
- elseopt: Option<&ast::Expr>) -> io::Result<()> {
- self.head("if let")?;
- self.print_pats(pats)?;
- self.s.space()?;
- self.word_space("=")?;
- self.print_expr_as_cond(expr)?;
- self.s.space()?;
self.print_block(blk)?;
self.print_else(elseopt)
}
@@ -1807,21 +1799,18 @@
}
pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) -> io::Result<()> {
- let needs_par = expr.precedence().order() < prec;
- if needs_par {
- self.popen()?;
- }
- self.print_expr(expr)?;
- if needs_par {
- self.pclose()?;
- }
- Ok(())
+ self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
}
/// Print an expr using syntax that's acceptable in a condition position, such as the `cond` in
/// `if cond { ... }`.
pub fn print_expr_as_cond(&mut self, expr: &ast::Expr) -> io::Result<()> {
- let needs_par = match expr.node {
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+ }
+
+ /// Does `expr` need parenthesis when printed in a condition position?
+ fn cond_needs_par(expr: &ast::Expr) -> bool {
+ match expr.node {
// These cases need parens due to the parse error observed in #26461: `if return {}`
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
ast::ExprKind::Closure(..) |
@@ -1829,8 +1818,11 @@
ast::ExprKind::Break(..) => true,
_ => parser::contains_exterior_struct_lit(expr),
- };
+ }
+ }
+ /// Print `expr` or `(expr)` when `needs_par` holds.
+ fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) -> io::Result<()> {
if needs_par {
self.popen()?;
}
@@ -1962,6 +1954,17 @@
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt) |
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Shl) => parser::PREC_FORCE_PAREN,
+ // We are given `(let _ = a) OP b`.
+ //
+ // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
+ // as the parser will interpret this as `(let _ = a) OP b`.
+ //
+ // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
+ // parens are required since the parser would interpret `let a = b < c` as
+ // `let a = (b < c)`. To achieve this, we force parens.
+ (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+ parser::PREC_FORCE_PAREN
+ }
_ => left_prec,
};
@@ -2052,12 +2055,12 @@
self.word_space(":")?;
self.print_type(ty)?;
}
+ ast::ExprKind::Let(ref pats, ref scrutinee) => {
+ self.print_let(pats, scrutinee)?;
+ }
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
}
- ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => {
- self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?;
- }
ast::ExprKind::While(ref test, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
@@ -2068,19 +2071,6 @@
self.s.space()?;
self.print_block_with_attrs(blk, attrs)?;
}
- ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident)?;
- self.word_space(":")?;
- }
- self.head("while let")?;
- self.print_pats(pats)?;
- self.s.space()?;
- self.word_space("=")?;
- self.print_expr_as_cond(expr)?;
- self.s.space()?;
- self.print_block_with_attrs(blk, attrs)?;
- }
ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident)?;
diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs
index fcecee8..1e52186 100644
--- a/src/libsyntax/util/parser.rs
+++ b/src/libsyntax/util/parser.rs
@@ -260,6 +260,7 @@
Box,
AddrOf,
+ Let,
Unary,
Call,
@@ -277,9 +278,7 @@
Path,
Paren,
If,
- IfLet,
While,
- WhileLet,
ForLoop,
Loop,
Match,
@@ -318,6 +317,11 @@
// Unary, prefix
ExprPrecedence::Box |
ExprPrecedence::AddrOf |
+ // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
+ // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
+ // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
+ // but we need to print `(let _ = a) < b` as-is with parens.
+ ExprPrecedence::Let |
ExprPrecedence::Unary => PREC_PREFIX,
// Unary, postfix
@@ -338,9 +342,7 @@
ExprPrecedence::Path |
ExprPrecedence::Paren |
ExprPrecedence::If |
- ExprPrecedence::IfLet |
ExprPrecedence::While |
- ExprPrecedence::WhileLet |
ExprPrecedence::ForLoop |
ExprPrecedence::Loop |
ExprPrecedence::Match |
@@ -353,6 +355,19 @@
}
}
+/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
+crate fn prec_let_scrutinee_needs_par() -> usize {
+ AssocOp::LAnd.precedence()
+}
+
+/// Suppose we have `let _ = e` and the `order` of `e`.
+/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
+///
+/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
+/// Can we print this as `let _ = a OP b`?
+crate fn needs_par_as_let_scrutinee(order: i8) -> bool {
+ order <= prec_let_scrutinee_needs_par() as i8
+}
/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index e2489c1..9ec9550 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -719,6 +719,10 @@
visitor.visit_expr(subexpression);
visitor.visit_ty(typ)
}
+ ExprKind::Let(ref pats, ref scrutinee) => {
+ walk_list!(visitor, visit_pat, pats);
+ visitor.visit_expr(scrutinee);
+ }
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
visitor.visit_expr(head_expression);
visitor.visit_block(if_block);
@@ -729,18 +733,6 @@
visitor.visit_expr(subexpression);
visitor.visit_block(block);
}
- ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
- walk_list!(visitor, visit_pat, pats);
- visitor.visit_expr(subexpression);
- visitor.visit_block(if_block);
- walk_list!(visitor, visit_expr, optional_else);
- }
- ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => {
- walk_list!(visitor, visit_label, opt_label);
- walk_list!(visitor, visit_pat, pats);
- visitor.visit_expr(subexpression);
- visitor.visit_block(block);
- }
ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_pat(pattern);
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index c25e65e..756bc8c 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -354,6 +354,7 @@
label_break_value,
lang,
lang_items,
+ let_chains,
lhs,
lib,
lifetime,
diff --git a/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs b/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs
index 3d16a15..afc0862 100644
--- a/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs
+++ b/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs
@@ -2,7 +2,7 @@
// rustc_on_unimplemented, but with this bug we are seeing it fire (on
// subsequent runs) if incremental compilation is enabled.
-// revisions: rpass1 rpass2
+// revisions: cfail1 cfail2
// compile-pass
#![feature(on_unimplemented)]
diff --git a/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs b/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs
index e4802cb..37bd8d0 100644
--- a/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs
+++ b/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs
@@ -3,7 +3,7 @@
// seeing it fire (on subsequent runs) if incremental compilation is
// enabled.
-// revisions: rpass1 rpass2
+// revisions: cfail1 cfail2
// compile-pass
#![feature(rustc_attrs)]
diff --git a/src/test/incremental/no_mangle.rs b/src/test/incremental/no_mangle.rs
index 1b17886..b1c9b2b 100644
--- a/src/test/incremental/no_mangle.rs
+++ b/src/test/incremental/no_mangle.rs
@@ -1,6 +1,6 @@
-// revisions:rpass1 rpass2
+// revisions:cfail1 cfail2
+// check-pass
// compile-flags: --crate-type cdylib
-// skip-codegen
#![deny(unused_attributes)]
diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs
index 5f76caa..796729a 100644
--- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs
+++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs
@@ -1,4 +1,4 @@
-// compile-pass
+// error-pattern:returned Box<dyn Error> from main()
// failure-status: 1
use std::error::Error;
diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
index bd47a97..2f3a73a 100644
--- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
+++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
@@ -1,4 +1,4 @@
-// compile-pass
+// error-pattern:returned Box<Error> from main()
// failure-status: 1
use std::io::{Error, ErrorKind};
diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
index 7e819e2..5716e6d 100644
--- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
@@ -68,7 +68,7 @@
let mut g = |e| f(expr(e));
- for kind in 0 .. 16 {
+ for kind in 0..=19 {
match kind {
0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))),
1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
@@ -79,25 +79,26 @@
iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
seg.clone(), vec![make_x(), e])));
},
- 3 => {
- let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add };
+ 3..=8 => {
+ let op = Spanned {
+ span: DUMMY_SP,
+ node: match kind {
+ 3 => BinOpKind::Add,
+ 4 => BinOpKind::Mul,
+ 5 => BinOpKind::Shl,
+ 6 => BinOpKind::And,
+ 7 => BinOpKind::Or,
+ 8 => BinOpKind::Lt,
+ _ => unreachable!(),
+ }
+ };
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
},
- 4 => {
- let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul };
- iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
- iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
- },
- 5 => {
- let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl };
- iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
- iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
- },
- 6 => {
+ 9 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
},
- 7 => {
+ 10 => {
let block = P(Block {
stmts: Vec::new(),
id: DUMMY_NODE_ID,
@@ -106,7 +107,7 @@
});
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
},
- 8 => {
+ 11 => {
let decl = P(FnDecl {
inputs: vec![],
output: FunctionRetTy::Default(DUMMY_SP),
@@ -120,33 +121,41 @@
e,
DUMMY_SP)));
},
- 9 => {
+ 12 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e)));
},
- 10 => {
+ 13 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
},
- 11 => {
+ 14 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Some(e), Some(make_x()), RangeLimits::HalfOpen)));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Some(make_x()), Some(e), RangeLimits::HalfOpen)));
},
- 12 => {
+ 15 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e)));
},
- 13 => {
+ 16 => {
g(ExprKind::Ret(None));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
},
- 14 => {
+ 17 => {
let path = Path::from_ident(Ident::from_str("S"));
g(ExprKind::Struct(path, vec![], Some(make_x())));
},
- 15 => {
+ 18 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
},
+ 19 => {
+ let ps = vec![P(Pat {
+ id: DUMMY_NODE_ID,
+ node: PatKind::Wild,
+ span: DUMMY_SP,
+ })];
+ iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(ps.clone(), e)))
+ },
_ => panic!("bad counter value in iter_exprs"),
}
}
diff --git a/src/test/run-pass/compiletest-skip-codegen.rs b/src/test/run-pass/compiletest-skip-codegen.rs
deleted file mode 100644
index 3c0e226..0000000
--- a/src/test/run-pass/compiletest-skip-codegen.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// Test that with the `skip-codegen` option the test isn't executed.
-
-// skip-codegen
-
-fn main() {
- unreachable!();
-}
diff --git a/src/test/ui/asm/asm-misplaced-option.rs b/src/test/ui/asm/asm-misplaced-option.rs
index 5c202a1..14ff4c2 100644
--- a/src/test/ui/asm/asm-misplaced-option.rs
+++ b/src/test/ui/asm/asm-misplaced-option.rs
@@ -1,3 +1,4 @@
+// check-pass
// ignore-android
// ignore-arm
// ignore-aarch64
@@ -11,14 +12,11 @@
// ignore-mips
// ignore-mips64
-// compile-pass
-// skip-codegen
#![feature(asm)]
-#![allow(dead_code, non_upper_case_globals)]
#[cfg(any(target_arch = "x86",
target_arch = "x86_64"))]
-pub fn main() {
+fn main() {
// assignment not dead
let mut x: isize = 0;
unsafe {
diff --git a/src/test/ui/asm/asm-misplaced-option.stderr b/src/test/ui/asm/asm-misplaced-option.stderr
index 39d88e3..3d4b28c 100644
--- a/src/test/ui/asm/asm-misplaced-option.stderr
+++ b/src/test/ui/asm/asm-misplaced-option.stderr
@@ -1,11 +1,11 @@
warning: unrecognized option
- --> $DIR/asm-misplaced-option.rs:26:64
+ --> $DIR/asm-misplaced-option.rs:24:64
|
LL | asm!("mov $1, $0" : "=r"(x) : "r"(5_usize), "0"(x) : : "cc");
| ^^^^
warning: expected a clobber, found an option
- --> $DIR/asm-misplaced-option.rs:33:80
+ --> $DIR/asm-misplaced-option.rs:31:80
|
LL | asm!("add $2, $1; mov $1, $0" : "=r"(x) : "r"(x), "r"(8_usize) : "cc", "volatile");
| ^^^^^^^^^^
diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs
index 00d47c9..8ddd347 100644
--- a/src/test/ui/associated-types/cache/chrono-scan.rs
+++ b/src/test/ui/associated-types/cache/chrono-scan.rs
@@ -1,10 +1,10 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
+
pub type ParseResult<T> = Result<T, ()>;
-pub enum Item<'a> { Literal(&'a str),
- }
+pub enum Item<'a> {
+ Literal(&'a str)
+}
pub fn colon_or_space(s: &str) -> ParseResult<&str> {
unimplemented!()
@@ -20,10 +20,9 @@
macro_rules! try_consume {
($e:expr) => ({ let (s_, v) = try!($e); s = s_; v })
}
- let offset = try_consume!(timezone_offset_zulu(s.trim_left(), colon_or_space));
- let offset = try_consume!(timezone_offset_zulu(s.trim_left(), colon_or_space));
+ let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
+ let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
Ok(())
}
-
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/associated-types/cache/elision.rs b/src/test/ui/associated-types/cache/elision.rs
index 2b49cd3..b3e1ec8 100644
--- a/src/test/ui/associated-types/cache/elision.rs
+++ b/src/test/ui/associated-types/cache/elision.rs
@@ -1,10 +1,9 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
// Check that you are allowed to implement using elision but write
// trait without elision (a bug in this cropped up during
// bootstrapping, so this is a regression test).
+// check-pass
+
pub struct SplitWhitespace<'a> {
x: &'a u8
}
diff --git a/src/test/ui/bad/bad-lint-cap3.rs b/src/test/ui/bad/bad-lint-cap3.rs
index 4cfa0b2..c381058 100644
--- a/src/test/ui/bad/bad-lint-cap3.rs
+++ b/src/test/ui/bad/bad-lint-cap3.rs
@@ -1,10 +1,9 @@
+// check-pass
// compile-flags: --cap-lints warn
#![warn(unused)]
#![deny(warnings)]
-// compile-pass
-// skip-codegen
-use std::option; //~ WARN
+use std::option; //~ WARN
fn main() {}
diff --git a/src/test/ui/bad/bad-lint-cap3.stderr b/src/test/ui/bad/bad-lint-cap3.stderr
index a1ea3f7..b898d79 100644
--- a/src/test/ui/bad/bad-lint-cap3.stderr
+++ b/src/test/ui/bad/bad-lint-cap3.stderr
@@ -5,7 +5,7 @@
| ^^^^^^^^^^^
|
note: lint level defined here
- --> $DIR/bad-lint-cap3.rs:4:9
+ --> $DIR/bad-lint-cap3.rs:5:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
diff --git a/src/test/ui/coherence/coherence-projection-ok-orphan.rs b/src/test/ui/coherence/coherence-projection-ok-orphan.rs
index 652b438..b34c31d 100644
--- a/src/test/ui/coherence/coherence-projection-ok-orphan.rs
+++ b/src/test/ui/coherence/coherence-projection-ok-orphan.rs
@@ -1,11 +1,10 @@
-// compile-pass
-// skip-codegen
+// Here we do not get a coherence conflict because `Baz: Iterator`
+// does not hold and (due to the orphan rules), we can rely on that.
+
+// check-pass
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
-#![allow(dead_code)]
-// Here we do not get a coherence conflict because `Baz: Iterator`
-// does not hold and (due to the orphan rules), we can rely on that.
pub trait Foo<P> {}
@@ -18,5 +17,4 @@
impl<A:Iterator> Foo<A::Item> for A { }
-
fn main() {}
diff --git a/src/test/ui/coherence/coherence-projection-ok.rs b/src/test/ui/coherence/coherence-projection-ok.rs
index f759a9e..f4f5ca6 100644
--- a/src/test/ui/coherence/coherence-projection-ok.rs
+++ b/src/test/ui/coherence/coherence-projection-ok.rs
@@ -1,8 +1,8 @@
-// compile-pass
-// skip-codegen
+// check-pass
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
+
pub trait Foo<P> {}
pub trait Bar {
@@ -17,5 +17,4 @@
type Output = u32;
}
-
fn main() {}
diff --git a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs
index bd8317e..0d67780 100644
--- a/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs
+++ b/src/test/ui/coherence/coherence_copy_like_err_fundamental_struct_ref.rs
@@ -1,13 +1,11 @@
// Test that we are able to introduce a negative constraint that
// `MyType: !MyTrait` along with other "fundamental" wrappers.
+// check-pass
// aux-build:coherence_copy_like_lib.rs
-// compile-pass
-// skip-codegen
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
-#![allow(dead_code)]
extern crate coherence_copy_like_lib as lib;
@@ -23,5 +21,4 @@
// Huzzah.
impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { }
-
fn main() { }
diff --git a/src/test/ui/coherence/coherence_local.rs b/src/test/ui/coherence/coherence_local.rs
index cac45b0..3eab6e0 100644
--- a/src/test/ui/coherence/coherence_local.rs
+++ b/src/test/ui/coherence/coherence_local.rs
@@ -1,13 +1,11 @@
// Test that we are able to introduce a negative constraint that
// `MyType: !MyTrait` along with other "fundamental" wrappers.
+// check-pass
// aux-build:coherence_copy_like_lib.rs
-// compile-pass
-// skip-codegen
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
-#![allow(dead_code)]
extern crate coherence_copy_like_lib as lib;
@@ -22,5 +20,4 @@
impl lib::MyCopy for lib::MyFundamentalStruct<MyType> { }
impl lib::MyCopy for lib::MyFundamentalStruct<Box<MyType>> { }
-
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/coherence/coherence_local_ref.rs b/src/test/ui/coherence/coherence_local_ref.rs
index a52510b..dff684c 100644
--- a/src/test/ui/coherence/coherence_local_ref.rs
+++ b/src/test/ui/coherence/coherence_local_ref.rs
@@ -1,13 +1,11 @@
// Test that we are able to introduce a negative constraint that
// `MyType: !MyTrait` along with other "fundamental" wrappers.
+// check-pass
// aux-build:coherence_copy_like_lib.rs
-// compile-pass
-// skip-codegen
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
-#![allow(dead_code)]
extern crate coherence_copy_like_lib as lib;
@@ -16,5 +14,4 @@
// naturally, legal
impl lib::MyCopy for MyType { }
-
fn main() { }
diff --git a/src/test/ui/conditional-compilation/cfg_attr_path.rs b/src/test/ui/conditional-compilation/cfg_attr_path.rs
index 9e9ff66..efb718b 100644
--- a/src/test/ui/conditional-compilation/cfg_attr_path.rs
+++ b/src/test/ui/conditional-compilation/cfg_attr_path.rs
@@ -1,13 +1,12 @@
-// compile-pass
-// skip-codegen
-#![allow(dead_code)]
+// check-pass
+
#![deny(unused_attributes)] // c.f #35584
+
mod auxiliary {
#[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums;
#[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file;
}
-
fn main() {
let _ = auxiliary::namespaced_enums::Foo::A;
let _ = auxiliary::nonexistent_file::Foo::A;
diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs
index 4726f9d..0e0e003 100644
--- a/src/test/ui/consts/const-eval/const_transmute.rs
+++ b/src/test/ui/consts/const-eval/const_transmute.rs
@@ -1,4 +1,3 @@
-// compile-pass
// run-pass
#![feature(const_fn_union)]
diff --git a/src/test/ui/consts/const-eval/enum_discr.rs b/src/test/ui/consts/const-eval/enum_discr.rs
index 4851e75..e09258f 100644
--- a/src/test/ui/consts/const-eval/enum_discr.rs
+++ b/src/test/ui/consts/const-eval/enum_discr.rs
@@ -1,4 +1,3 @@
-// compile-pass
// run-pass
enum Foo {
diff --git a/src/test/ui/consts/const-fn-stability-calls-3.rs b/src/test/ui/consts/const-fn-stability-calls-3.rs
index 44bcca8..b831dee 100644
--- a/src/test/ui/consts/const-fn-stability-calls-3.rs
+++ b/src/test/ui/consts/const-fn-stability-calls-3.rs
@@ -1,15 +1,12 @@
// Test use of const fn from another crate without a feature gate.
-// compile-pass
-// skip-codegen
-#![allow(unused_variables)]
+// check-pass
// aux-build:const_fn_lib.rs
extern crate const_fn_lib;
use const_fn_lib::foo;
-
fn main() {
let x = foo(); // use outside a constant is ok
}
diff --git a/src/test/ui/expanded-cfg.rs b/src/test/ui/expanded-cfg.rs
index c98fd7f..baa161a 100644
--- a/src/test/ui/expanded-cfg.rs
+++ b/src/test/ui/expanded-cfg.rs
@@ -1,5 +1,4 @@
-// skip-codegen
-// compile-pass
+// check-pass
macro_rules! mac {
{} => {
@@ -19,5 +18,4 @@
mac! {}
-
fn main() {}
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index ca0a432..3187b4c 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -30,8 +30,9 @@
// inputs are handled by each, and (2.) to ease searching for related
// occurrences in the source text.
+// check-pass
+
#![warn(unused_attributes, unknown_lints)]
-#![allow(stable_features)]
// UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES
@@ -75,7 +76,7 @@
// see issue-43106-gating-of-stable.rs
// see issue-43106-gating-of-unstable.rs
// see issue-43106-gating-of-deprecated.rs
-#![windows_subsystem = "1000"]
+#![windows_subsystem = "windows"]
// UNGATED CRATE-LEVEL BUILT-IN ATTRIBUTES
@@ -539,7 +540,7 @@
#[export_name = "2200"] impl S { }
}
-// Note that this test has a `skip-codegen`, so it
+// Note that this is a `check-pass` test, so it
// will never invoke the linker. These are here nonetheless to point
// out that we allow them at non-crate-level (though I do not know
// whether they have the same effect here as at crate-level).
@@ -611,17 +612,17 @@
#[must_use] impl S { }
}
-#[windows_subsystem = "1000"]
+#[windows_subsystem = "windows"]
mod windows_subsystem {
- mod inner { #![windows_subsystem="1000"] }
+ mod inner { #![windows_subsystem="windows"] }
- #[windows_subsystem = "1000"] fn f() { }
+ #[windows_subsystem = "windows"] fn f() { }
- #[windows_subsystem = "1000"] struct S;
+ #[windows_subsystem = "windows"] struct S;
- #[windows_subsystem = "1000"] type T = S;
+ #[windows_subsystem = "windows"] type T = S;
- #[windows_subsystem = "1000"] impl S { }
+ #[windows_subsystem = "windows"] impl S { }
}
// BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
index c708120..e03b712 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
@@ -1,1182 +1,1186 @@
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:38:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:9
|
LL | #![warn(x5400)]
| ^^^^^
|
note: lint level defined here
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:33:28
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:35:28
|
LL | #![warn(unused_attributes, unknown_lints)]
| ^^^^^^^^^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:10
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:10
|
LL | #![allow(x5300)]
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:11
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:41:11
|
LL | #![forbid(x5200)]
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:41:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:42:9
|
LL | #![deny(x5100)]
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:99:8
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:8
|
LL | #[warn(x5400)]
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:102:25
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:25
|
LL | mod inner { #![warn(x5400)] }
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:12
|
LL | #[warn(x5400)] fn f() { }
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12
|
LL | #[warn(x5400)] struct S;
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12
|
LL | #[warn(x5400)] type T = S;
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:12
|
LL | #[warn(x5400)] impl S { }
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:9
|
LL | #[allow(x5300)]
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:121:26
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:26
|
LL | mod inner { #![allow(x5300)] }
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:13
|
LL | #[allow(x5300)] fn f() { }
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13
|
LL | #[allow(x5300)] struct S;
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13
|
LL | #[allow(x5300)] type T = S;
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:13
|
LL | #[allow(x5300)] impl S { }
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:10
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:10
|
LL | #[forbid(x5200)]
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:140:27
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:27
|
LL | mod inner { #![forbid(x5200)] }
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:14
|
LL | #[forbid(x5200)] fn f() { }
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14
|
LL | #[forbid(x5200)] struct S;
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14
|
LL | #[forbid(x5200)] type T = S;
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:14
|
LL | #[forbid(x5200)] impl S { }
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:8
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:8
|
LL | #[deny(x5100)]
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:159:25
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:25
|
LL | mod inner { #![deny(x5100)] }
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:12
|
LL | #[deny(x5100)] fn f() { }
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12
|
LL | #[deny(x5100)] struct S;
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12
|
LL | #[deny(x5100)] type T = S;
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:12
|
LL | #[deny(x5100)] impl S { }
| ^^^^^
warning: macro_escape is a deprecated synonym for macro_use
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:1
|
LL | #[macro_escape]
| ^^^^^^^^^^^^^^^
warning: macro_escape is a deprecated synonym for macro_use
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:17
|
LL | mod inner { #![macro_escape] }
| ^^^^^^^^^^^^^^^^
|
= help: consider an outer attribute, #[macro_use] mod ...
+warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:89:12
+ |
+LL | #![feature(rust1)]
+ | ^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:5
|
LL | #[macro_use] fn f() { }
| ^^^^^^^^^^^^
|
note: lint level defined here
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:33:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:35:9
|
LL | #![warn(unused_attributes, unknown_lints)]
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5
|
LL | #[macro_use] struct S;
| ^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:186:5
|
LL | #[macro_use] type T = S;
| ^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:5
|
LL | #[macro_use] impl S { }
| ^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:195:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:17
|
LL | mod inner { #![macro_export] }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5
|
LL | #[macro_export] fn f() { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5
|
LL | #[macro_export] struct S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5
|
LL | #[macro_export] type T = S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:208:5
|
LL | #[macro_export] impl S { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:1
|
LL | #[macro_export]
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:214:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:17
|
LL | mod inner { #![plugin_registrar] }
| ^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:220:5
|
LL | #[plugin_registrar] struct S;
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:222:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:223:5
|
LL | #[plugin_registrar] type T = S;
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:225:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:226:5
|
LL | #[plugin_registrar] impl S { }
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:211:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:1
|
LL | #[plugin_registrar]
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:232:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17
|
LL | mod inner { #![main] }
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:237:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:238:5
|
LL | #[main] struct S;
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5
|
LL | #[main] type T = S;
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:243:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:5
|
LL | #[main] impl S { }
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:229:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:1
|
LL | #[main]
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:250:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:17
|
LL | mod inner { #![start] }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5
|
LL | #[start] struct S;
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:259:5
|
LL | #[start] type T = S;
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:5
|
LL | #[start] impl S { }
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:247:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:1
|
LL | #[start]
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:5
|
LL | #[path = "3800"] fn f() { }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:317:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:5
|
LL | #[path = "3800"] struct S;
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:320:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:5
|
LL | #[path = "3800"] type T = S;
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:5
|
LL | #[path = "3800"] impl S { }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:17
|
LL | mod inner { #![automatically_derived] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5
|
LL | #[automatically_derived] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:337:5
|
LL | #[automatically_derived] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:5
|
LL | #[automatically_derived] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:343:5
|
LL | #[automatically_derived] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:327:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:1
|
LL | #[automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:362:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:363:17
|
LL | mod inner { #![no_link] }
| ^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:366:5
|
LL | #[no_link] fn f() { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:369:5
|
LL | #[no_link] struct S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:372:5
|
LL | #[no_link]type T = S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:5
|
LL | #[no_link] impl S { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:359:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:360:1
|
LL | #[no_link]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:381:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:17
|
LL | mod inner { #![should_panic] }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:384:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5
|
LL | #[should_panic] fn f() { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:5
|
LL | #[should_panic] struct S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5
|
LL | #[should_panic] type T = S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:5
|
LL | #[should_panic] impl S { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:378:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:1
|
LL | #[should_panic]
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:17
|
LL | mod inner { #![ignore] }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
|
LL | #[ignore] fn f() { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5
|
LL | #[ignore] struct S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5
|
LL | #[ignore] type T = S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:413:5
|
LL | #[ignore] impl S { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:1
|
LL | #[ignore]
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:419:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:17
|
LL | mod inner { #![no_implicit_prelude] }
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:422:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
|
LL | #[no_implicit_prelude] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5
|
LL | #[no_implicit_prelude] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5
|
LL | #[no_implicit_prelude] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5
|
LL | #[no_implicit_prelude] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:416:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:1
|
LL | #[no_implicit_prelude]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:438:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:17
|
LL | mod inner { #![reexport_test_harness_main="2900"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:441:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5
|
LL | #[reexport_test_harness_main = "2900"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5
|
LL | #[reexport_test_harness_main = "2900"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5
|
LL | #[reexport_test_harness_main = "2900"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5
|
LL | #[reexport_test_harness_main = "2900"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:435:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:1
|
LL | #[reexport_test_harness_main = "2900"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5
|
LL | #[macro_escape] fn f() { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5
|
LL | #[macro_escape] struct S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5
|
LL | #[macro_escape] type T = S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5
|
LL | #[macro_escape] impl S { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:17
|
LL | mod inner { #![no_std] }
| ^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:17
|
LL | mod inner { #![no_std] }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
|
LL | #[no_std] struct S;
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
|
LL | #[no_std] struct S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:490:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5
|
LL | #[no_std] type T = S;
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:490:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5
|
LL | #[no_std] type T = S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5
|
LL | #[no_std] impl S { }
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5
|
LL | #[no_std] impl S { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:1
|
LL | #[no_std]
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:1
|
LL | #[no_std]
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:17
|
LL | mod inner { #![crate_name="0900"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:17
|
LL | mod inner { #![crate_name="0900"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:637:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5
|
LL | #[crate_name = "0900"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:637:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5
|
LL | #[crate_name = "0900"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
|
LL | #[crate_name = "0900"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
|
LL | #[crate_name = "0900"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
|
LL | #[crate_name = "0900"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
|
LL | #[crate_name = "0900"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
|
LL | #[crate_name = "0900"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
|
LL | #[crate_name = "0900"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:1
|
LL | #[crate_name = "0900"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:1
|
LL | #[crate_name = "0900"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:17
|
LL | mod inner { #![crate_type="0800"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:17
|
LL | mod inner { #![crate_type="0800"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
|
LL | #[crate_type = "0800"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
|
LL | #[crate_type = "0800"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
|
LL | #[crate_type = "0800"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
|
LL | #[crate_type = "0800"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
|
LL | #[crate_type = "0800"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
|
LL | #[crate_type = "0800"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
|
LL | #[crate_type = "0800"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
|
LL | #[crate_type = "0800"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:1
|
LL | #[crate_type = "0800"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:1
|
LL | #[crate_type = "0800"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:17
|
LL | mod inner { #![feature(x0600)] }
| ^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:17
|
LL | mod inner { #![feature(x0600)] }
| ^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5
|
LL | #[feature(x0600)] fn f() { }
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5
|
LL | #[feature(x0600)] fn f() { }
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
|
LL | #[feature(x0600)] struct S;
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
|
LL | #[feature(x0600)] struct S;
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
|
LL | #[feature(x0600)] type T = S;
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
|
LL | #[feature(x0600)] type T = S;
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
|
LL | #[feature(x0600)] impl S { }
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
|
LL | #[feature(x0600)] impl S { }
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:1
|
LL | #[feature(x0600)]
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:1
|
LL | #[feature(x0600)]
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:17
|
LL | mod inner { #![no_main] }
| ^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:17
|
LL | mod inner { #![no_main] }
| ^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:5
|
LL | #[no_main] fn f() { }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:5
|
LL | #[no_main] fn f() { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
|
LL | #[no_main] struct S;
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
|
LL | #[no_main] struct S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5
|
LL | #[no_main] type T = S;
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5
|
LL | #[no_main] type T = S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
|
LL | #[no_main] impl S { }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
|
LL | #[no_main] impl S { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1
|
LL | #[no_main]
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1
|
LL | #[no_main]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17
|
LL | mod inner { #![recursion_limit="0200"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17
|
LL | mod inner { #![recursion_limit="0200"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5
|
LL | #[recursion_limit="0200"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5
|
LL | #[recursion_limit="0200"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
|
LL | #[recursion_limit="0200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
|
LL | #[recursion_limit="0200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5
|
LL | #[recursion_limit="0200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5
|
LL | #[recursion_limit="0200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
|
LL | #[recursion_limit="0200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
|
LL | #[recursion_limit="0200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1
|
LL | #[recursion_limit="0200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1
|
LL | #[recursion_limit="0200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:17
|
LL | mod inner { #![type_length_limit="0100"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:17
|
LL | mod inner { #![type_length_limit="0100"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5
|
LL | #[type_length_limit="0100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:5
|
LL | #[type_length_limit="0100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5
|
LL | #[type_length_limit="0100"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5
|
LL | #[type_length_limit="0100"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5
|
LL | #[type_length_limit="0100"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5
|
LL | #[type_length_limit="0100"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
|
LL | #[type_length_limit="0100"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
|
LL | #[type_length_limit="0100"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:1
|
LL | #[type_length_limit="0100"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo]
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:1
|
LL | #[type_length_limit="0100"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:1
|
LL | #![macro_export]
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:1
|
LL | #![plugin_registrar]
| ^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:1
|
LL | #![main]
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1
|
LL | #![start]
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:51:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1
|
LL | #![repr()]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1
|
LL | #![path = "3800"]
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1
|
LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:57:1
|
LL | #![no_link]
| ^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
|
LL | #![should_panic]
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
|
LL | #![ignore]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
|
LL | #![proc_macro_derive()]
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: invalid windows subsystem `1000`, only `windows` and `console` are allowed
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs b/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs
index 360d570..5e1d08d 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.rs
@@ -5,8 +5,7 @@
//
// (For non-crate-level cases, see issue-43106-gating-of-builtin-attrs.rs)
-// compile-pass
-// skip-codegen
+// check-pass
#![deprecated]
diff --git a/src/test/ui/glob-cycles.rs b/src/test/ui/glob-cycles.rs
index 84f9e5d..f354cc8 100644
--- a/src/test/ui/glob-cycles.rs
+++ b/src/test/ui/glob-cycles.rs
@@ -1,5 +1,5 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
mod foo {
pub use bar::*;
pub use main as f;
@@ -15,5 +15,4 @@
pub use super::*;
}
-
pub fn main() {}
diff --git a/src/test/ui/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs
index eb0ca6a..93cf759 100644
--- a/src/test/ui/hygiene/assoc_ty_bindings.rs
+++ b/src/test/ui/hygiene/assoc_ty_bindings.rs
@@ -1,8 +1,8 @@
+// check-pass
// ignore-pretty pretty-printing is unhygienic
#![feature(decl_macro, associated_type_defaults)]
-// compile-pass
-// skip-codegen
+
trait Base {
type AssocTy;
fn f();
@@ -35,5 +35,4 @@
mac!();
-
fn main() {}
diff --git a/src/test/ui/if/if-loop.rs b/src/test/ui/if/if-loop.rs
index c799df2..06d0bdf 100644
--- a/src/test/ui/if/if-loop.rs
+++ b/src/test/ui/if/if-loop.rs
@@ -1,10 +1,8 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
+
// This used to ICE because the "if" being unreachable was not handled correctly
fn err() {
if loop {} {}
}
-
fn main() {}
diff --git a/src/test/ui/imports/import-crate-var.rs b/src/test/ui/imports/import-crate-var.rs
index ab26050..b9d146d 100644
--- a/src/test/ui/imports/import-crate-var.rs
+++ b/src/test/ui/imports/import-crate-var.rs
@@ -1,10 +1,8 @@
+// check-pass
// aux-build:import_crate_var.rs
-// compile-pass
-// skip-codegen
#[macro_use] extern crate import_crate_var;
-
fn main() {
m!();
//~^ WARN `$crate` may not be imported
diff --git a/src/test/ui/imports/import-crate-var.stderr b/src/test/ui/imports/import-crate-var.stderr
index 4c358a8..2f8c845 100644
--- a/src/test/ui/imports/import-crate-var.stderr
+++ b/src/test/ui/imports/import-crate-var.stderr
@@ -1,5 +1,5 @@
warning: `$crate` may not be imported
- --> $DIR/import-crate-var.rs:9:5
+ --> $DIR/import-crate-var.rs:7:5
|
LL | m!();
| ^^^^^
diff --git a/src/test/ui/issues/issue-11740.rs b/src/test/ui/issues/issue-11740.rs
index 47bdf08..dc10a20 100644
--- a/src/test/ui/issues/issue-11740.rs
+++ b/src/test/ui/issues/issue-11740.rs
@@ -1,6 +1,5 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
+
struct Attr {
name: String,
value: String,
@@ -21,7 +20,6 @@
}
}
-
fn main() {
let element = Element { attrs: Vec::new() };
let _ = unsafe { element.get_attr("foo") };
diff --git a/src/test/ui/issues/issue-16994.rs b/src/test/ui/issues/issue-16994.rs
index d5f1b13..8d3074b 100644
--- a/src/test/ui/issues/issue-16994.rs
+++ b/src/test/ui/issues/issue-16994.rs
@@ -1,10 +1,9 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
fn cb<'a,T>(_x: Box<dyn Fn((&'a i32, &'a (Vec<&'static i32>, bool))) -> T>) -> T {
panic!()
}
-
fn main() {
cb(Box::new(|(k, &(ref v, b))| (*k, v.clone(), b)));
}
diff --git a/src/test/ui/issues/issue-19601.rs b/src/test/ui/issues/issue-19601.rs
index faaa2db..176e6ba 100644
--- a/src/test/ui/issues/issue-19601.rs
+++ b/src/test/ui/issues/issue-19601.rs
@@ -1,9 +1,6 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
+
trait A<T> {}
struct B<T> where B<T>: A<B<T>> { t: T }
-
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-22603.rs b/src/test/ui/issues/issue-22603.rs
index e298316..a83e291 100644
--- a/src/test/ui/issues/issue-22603.rs
+++ b/src/test/ui/issues/issue-22603.rs
@@ -1,6 +1,7 @@
-// skip-codegen
-// compile-pass
+// check-pass
+
#![feature(unboxed_closures, fn_traits)]
+
struct Foo;
impl<A> FnOnce<(A,)> for Foo {
diff --git a/src/test/ui/issues/issue-22789.rs b/src/test/ui/issues/issue-22789.rs
index e668012..cef4075 100644
--- a/src/test/ui/issues/issue-22789.rs
+++ b/src/test/ui/issues/issue-22789.rs
@@ -1,6 +1,7 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
#![feature(unboxed_closures, fn_traits)]
+
fn main() {
let k = |x: i32| { x + 1 };
Fn::call(&k, (0,));
diff --git a/src/test/ui/issues/issue-22933-1.rs b/src/test/ui/issues/issue-22933-1.rs
index 1bf8cb0..3c9aa26 100644
--- a/src/test/ui/issues/issue-22933-1.rs
+++ b/src/test/ui/issues/issue-22933-1.rs
@@ -1,6 +1,5 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
+
struct CNFParser {
token: char,
}
@@ -14,12 +13,11 @@
self.consume_while(&(CNFParser::is_whitespace))
}
- fn consume_while(&mut self, p: &Fn(char) -> bool) {
+ fn consume_while(&mut self, p: &dyn Fn(char) -> bool) {
while p(self.token) {
return
}
}
}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-24883.rs b/src/test/ui/issues/issue-24883.rs
index 1aa62d3..819a20d 100644
--- a/src/test/ui/issues/issue-24883.rs
+++ b/src/test/ui/issues/issue-24883.rs
@@ -1,5 +1,5 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
mod a {
pub mod b { pub struct Foo; }
@@ -11,7 +11,6 @@
pub use self::c::*;
}
-
fn main() {
let _ = a::c::Bar(a::b::Foo);
let _ = a::Bar(a::b::Foo);
diff --git a/src/test/ui/issues/issue-26614.rs b/src/test/ui/issues/issue-26614.rs
index 11c2202..b8ebbdc 100644
--- a/src/test/ui/issues/issue-26614.rs
+++ b/src/test/ui/issues/issue-26614.rs
@@ -1,6 +1,5 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
+
trait Mirror {
type It;
}
@@ -9,8 +8,6 @@
type It = Self;
}
-
-
fn main() {
let c: <u32 as Mirror>::It = 5;
const CCCC: <u32 as Mirror>::It = 5;
diff --git a/src/test/ui/issues/issue-26930.rs b/src/test/ui/issues/issue-26930.rs
index abf6b93..707e71b 100644
--- a/src/test/ui/issues/issue-26930.rs
+++ b/src/test/ui/issues/issue-26930.rs
@@ -1,10 +1,8 @@
-// compile-pass
-// skip-codegen
-#![allow(unused)]
+// check-pass
+
extern crate core;
use core as core_export;
use self::x::*;
mod x {}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-29857.rs b/src/test/ui/issues/issue-29857.rs
index 5aff968..6f4c5f4 100644
--- a/src/test/ui/issues/issue-29857.rs
+++ b/src/test/ui/issues/issue-29857.rs
@@ -1,5 +1,4 @@
-// compile-pass
-// skip-codegen
+// check-pass
use std::marker::PhantomData;
@@ -17,5 +16,4 @@
impl<T: 'static, W: Bar<Output = T>> Foo<*mut T> for W {}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-31924-non-snake-ffi.rs b/src/test/ui/issues/issue-31924-non-snake-ffi.rs
index 5e2336c..63e42b48 100644
--- a/src/test/ui/issues/issue-31924-non-snake-ffi.rs
+++ b/src/test/ui/issues/issue-31924-non-snake-ffi.rs
@@ -1,8 +1,8 @@
-// compile-pass
-// skip-codegen
-#![deny(non_snake_case)]
-#[no_mangle]
-pub extern "C" fn SparklingGenerationForeignFunctionInterface() {}
+// check-pass
+#![deny(non_snake_case)]
+
+#[no_mangle]
+pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK
fn main() {}
diff --git a/src/test/ui/issues/issue-32119.rs b/src/test/ui/issues/issue-32119.rs
index ea8824b..36adb52 100644
--- a/src/test/ui/issues/issue-32119.rs
+++ b/src/test/ui/issues/issue-32119.rs
@@ -1,6 +1,5 @@
-// compile-pass
-// skip-codegen
-#![allow(dead_code)]
+// check-pass
+
pub type T = ();
mod foo { pub use super::T; }
mod bar { pub use super::T; }
@@ -15,5 +14,4 @@
pub use self::bar::*;
}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-32222.rs b/src/test/ui/issues/issue-32222.rs
index 91f53ab..4ed06bf 100644
--- a/src/test/ui/issues/issue-32222.rs
+++ b/src/test/ui/issues/issue-32222.rs
@@ -1,6 +1,4 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
mod foo {
pub fn bar() {}
@@ -21,5 +19,4 @@
pub use a::bar;
}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-32797.rs b/src/test/ui/issues/issue-32797.rs
index 5ceb7f4..b12b929 100644
--- a/src/test/ui/issues/issue-32797.rs
+++ b/src/test/ui/issues/issue-32797.rs
@@ -1,5 +1,4 @@
-// compile-pass
-// skip-codegen
+// check-pass
pub use bar::*;
mod bar {
@@ -11,5 +10,4 @@
pub use main as f;
}
-
pub fn main() {}
diff --git a/src/test/ui/issues/issue-32922.rs b/src/test/ui/issues/issue-32922.rs
index b06b63c..54ec44a 100644
--- a/src/test/ui/issues/issue-32922.rs
+++ b/src/test/ui/issues/issue-32922.rs
@@ -1,6 +1,4 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
macro_rules! foo { () => {
let x = 1;
@@ -22,7 +20,6 @@
}
}
-
fn main() {
foo! {};
bar! {};
diff --git a/src/test/ui/issues/issue-33241.rs b/src/test/ui/issues/issue-33241.rs
index 4d6204c..5f9f1e4 100644
--- a/src/test/ui/issues/issue-33241.rs
+++ b/src/test/ui/issues/issue-33241.rs
@@ -1,5 +1,4 @@
-// compile-pass
-// skip-codegen
+// check-pass
use std::fmt;
@@ -7,7 +6,6 @@
// an unsized tuple by transmuting a trait object.
fn any<T>() -> T { unreachable!() }
-
fn main() {
let t: &(u8, dyn fmt::Debug) = any();
println!("{:?}", &t.1);
diff --git a/src/test/ui/issues/issue-34028.rs b/src/test/ui/issues/issue-34028.rs
index 8ebc730..d761c0c 100644
--- a/src/test/ui/issues/issue-34028.rs
+++ b/src/test/ui/issues/issue-34028.rs
@@ -1,5 +1,4 @@
-// compile-pass
-// skip-codegen
+// check-pass
macro_rules! m {
() => { #[cfg(any())] fn f() {} }
@@ -8,5 +7,4 @@
trait T {}
impl T for () { m!(); }
-
fn main() {}
diff --git a/src/test/ui/issues/issue-34171.rs b/src/test/ui/issues/issue-34171.rs
index 25a5f72..157c58c 100644
--- a/src/test/ui/issues/issue-34171.rs
+++ b/src/test/ui/issues/issue-34171.rs
@@ -1,12 +1,10 @@
-// compile-pass
-// skip-codegen
+// check-pass
macro_rules! null { ($i:tt) => {} }
macro_rules! apply_null {
($i:item) => { null! { $i } }
}
-
fn main() {
apply_null!(#[cfg(all())] fn f() {});
}
diff --git a/src/test/ui/issues/issue-34418.rs b/src/test/ui/issues/issue-34418.rs
index 6a86c27..6132f74 100644
--- a/src/test/ui/issues/issue-34418.rs
+++ b/src/test/ui/issues/issue-34418.rs
@@ -1,6 +1,4 @@
-// compile-pass
-// skip-codegen
-#![allow(unused)]
+// check-pass
macro_rules! make_item {
() => { fn f() {} }
@@ -18,5 +16,4 @@
make_stmt! {}
}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-34839.rs b/src/test/ui/issues/issue-34839.rs
index 01669f0..8ffed82 100644
--- a/src/test/ui/issues/issue-34839.rs
+++ b/src/test/ui/issues/issue-34839.rs
@@ -1,6 +1,4 @@
-// compile-pass
-// skip-codegen
-#![allow(dead_code)]
+// check-pass
trait RegularExpression: Sized {
type Text;
@@ -18,5 +16,4 @@
Dynamic(FindCaptures<'t, ExecNoSyncStr<'r>>),
}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-35570.rs b/src/test/ui/issues/issue-35570.rs
index 9bb9db6..fafef79 100644
--- a/src/test/ui/issues/issue-35570.rs
+++ b/src/test/ui/issues/issue-35570.rs
@@ -1,5 +1,4 @@
-// compile-pass
-// skip-codegen
+// check-pass
use std::mem;
@@ -25,7 +24,6 @@
fn takes_lifetime(_f: for<'a> fn(&'a ()) -> <() as Lifetime<'a>>::Out) {
}
-
fn main() {
takes_lifetime(foo);
}
diff --git a/src/test/ui/issues/issue-36116.rs b/src/test/ui/issues/issue-36116.rs
index b4bfba4..c7c70c7 100644
--- a/src/test/ui/issues/issue-36116.rs
+++ b/src/test/ui/issues/issue-36116.rs
@@ -1,8 +1,7 @@
// Unnecessary path disambiguator is ok
-// compile-pass
-// skip-codegen
-#![allow(unused)]
+// check-pass
+
macro_rules! m {
($p: path) => {
let _ = $p(0);
@@ -23,5 +22,4 @@
m!(S::<u8>);
}
-
fn main() {}
diff --git a/src/test/ui/issues/issue-36379.rs b/src/test/ui/issues/issue-36379.rs
index b2da651..3a3e6f4 100644
--- a/src/test/ui/issues/issue-36379.rs
+++ b/src/test/ui/issues/issue-36379.rs
@@ -1,7 +1,5 @@
-// compile-pass
-// skip-codegen
+// check-pass
fn _test() -> impl Default { }
-
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/issues/issue-36839.rs b/src/test/ui/issues/issue-36839.rs
index a660368..ca3d66b 100644
--- a/src/test/ui/issues/issue-36839.rs
+++ b/src/test/ui/issues/issue-36839.rs
@@ -1,5 +1,4 @@
-// compile-pass
-// skip-codegen
+// check-pass
pub trait Foo {
type Bar;
@@ -17,7 +16,6 @@
}
}
-
fn main() {
let _m: &dyn Broken<Assoc=()> = &();
}
diff --git a/src/test/ui/issues/issue-37051.rs b/src/test/ui/issues/issue-37051.rs
index 1ccf5b9..9cae6cf 100644
--- a/src/test/ui/issues/issue-37051.rs
+++ b/src/test/ui/issues/issue-37051.rs
@@ -1,7 +1,7 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
#![feature(associated_type_defaults)]
-#![allow(warnings)]
+
trait State: Sized {
type NextState: State = StateMachineEnded;
fn execute(self) -> Option<Self::NextState>;
@@ -15,6 +15,4 @@
}
}
-
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-37366.rs b/src/test/ui/issues/issue-37366.rs
index 1c27960..6bf3a27 100644
--- a/src/test/ui/issues/issue-37366.rs
+++ b/src/test/ui/issues/issue-37366.rs
@@ -1,6 +1,6 @@
+// check-pass
// ignore-emscripten
-// compile-pass
-// skip-codegen
+
#![feature(asm)]
macro_rules! interrupt_handler {
@@ -12,6 +12,4 @@
}
interrupt_handler!{}
-
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-37510.rs b/src/test/ui/issues/issue-37510.rs
index 465e680..2081c9f 100644
--- a/src/test/ui/issues/issue-37510.rs
+++ b/src/test/ui/issues/issue-37510.rs
@@ -1,9 +1,7 @@
-// compile-pass
-// skip-codegen
+// check-pass
fn foo(_: &mut i32) -> bool { true }
-
fn main() {
let opt = Some(92);
let mut x = 62;
diff --git a/src/test/ui/issues/issue-37515.rs b/src/test/ui/issues/issue-37515.rs
index cc07bd1..caff507 100644
--- a/src/test/ui/issues/issue-37515.rs
+++ b/src/test/ui/issues/issue-37515.rs
@@ -1,10 +1,8 @@
-// skip-codegen
-// compile-pass
+// check-pass
+
#![warn(unused)]
type Z = dyn for<'x> Send;
//~^ WARN type alias is never used
-
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-38160.rs b/src/test/ui/issues/issue-38160.rs
index a454211..0da8b79 100644
--- a/src/test/ui/issues/issue-38160.rs
+++ b/src/test/ui/issues/issue-38160.rs
@@ -1,7 +1,5 @@
-// compile-pass
-// skip-codegen
-#![feature(associated_consts)]
-#![allow(warnings)]
+// check-pass
+
trait MyTrait {
const MY_CONST: &'static str;
}
@@ -18,5 +16,4 @@
my_macro!();
-
fn main() {}
diff --git a/src/test/ui/issues/issue-38381.rs b/src/test/ui/issues/issue-38381.rs
index 1351376..82d4a4e 100644
--- a/src/test/ui/issues/issue-38381.rs
+++ b/src/test/ui/issues/issue-38381.rs
@@ -1,9 +1,7 @@
-// compile-pass
-// skip-codegen
+// check-pass
use std::ops::Deref;
-
fn main() {
let _x: fn(&i32) -> <&i32 as Deref>::Target = unimplemented!();
}
diff --git a/src/test/ui/issues/issue-40350.rs b/src/test/ui/issues/issue-40350.rs
index b2cc004..a39a851 100644
--- a/src/test/ui/issues/issue-40350.rs
+++ b/src/test/ui/issues/issue-40350.rs
@@ -1,6 +1,4 @@
-// compile-pass
-// skip-codegen
-#![allow(warnings)]
+// check-pass
enum E {
A = {
@@ -9,5 +7,4 @@
}
}
-
fn main() {}
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index dc74d69..c361010 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -22,8 +22,8 @@
match (true) { //~ ERROR unnecessary parentheses around `match` head expression
_ => {}
}
- if let 1 = (1) {} //~ ERROR unnecessary parentheses around `if let` head expression
- while let 1 = (2) {} //~ ERROR unnecessary parentheses around `while let` head expression
+ if let 1 = (1) {} //~ ERROR unnecessary parentheses around `let` head expression
+ while let 1 = (2) {} //~ ERROR unnecessary parentheses around `let` head expression
let v = X { y: false };
// struct lits needs parens, so these shouldn't warn.
if (v == X { y: true }) {}
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index fe2ee38..dfbefd7 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -40,13 +40,13 @@
LL | match (true) {
| ^^^^^^ help: remove these parentheses
-error: unnecessary parentheses around `if let` head expression
+error: unnecessary parentheses around `let` head expression
--> $DIR/lint-unnecessary-parens.rs:25:16
|
LL | if let 1 = (1) {}
| ^^^ help: remove these parentheses
-error: unnecessary parentheses around `while let` head expression
+error: unnecessary parentheses around `let` head expression
--> $DIR/lint-unnecessary-parens.rs:26:19
|
LL | while let 1 = (2) {}
diff --git a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
index 5a008ad..a558e8a 100644
--- a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
+++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
@@ -1,12 +1,11 @@
// Basic test for free regions in the NLL code. This test does not
// report an error because of the (implied) bound that `'b: 'a`.
+// check-pass
// compile-flags:-Zborrowck=mir -Zverbose
-// compile-pass
-// skip-codegen
fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 {
&**x
}
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
index 5dbd38e..d1e7c3b 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
@@ -1,5 +1,5 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
#![deny(unreachable_patterns)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
index 74922d4..8973d21 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -1,5 +1,5 @@
-// compile-pass
-// skip-codegen
+// check-pass
+
#![deny(unreachable_patterns)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
new file mode 100644
index 0000000..e66d465
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
@@ -0,0 +1,6 @@
+// compile-pass
+// compile-flags: -Z unpretty=expanded
+
+fn main() {
+ if let 0 = 1 {}
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
new file mode 100644
index 0000000..a6b15f9
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
@@ -0,0 +1,10 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::v1::*;
+#[macro_use]
+extern crate std;
+// compile-pass
+// compile-flags: -Z unpretty=expanded
+
+fn main() { if let 0 = 1 { } }
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
new file mode 100644
index 0000000..7d1e5c3
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -0,0 +1,244 @@
+// Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions.
+//
+// We want to make sure that `let` is banned in situations other than:
+//
+// expr =
+// | ...
+// | "if" expr_with_let block {"else" block}?
+// | {label ":"}? while" expr_with_let block
+// ;
+//
+// expr_with_let =
+// | "let" top_pats "=" expr
+// | expr_with_let "&&" expr_with_let
+// | "(" expr_with_let ")"
+// | expr
+// ;
+//
+// To that end, we check some positions which is not part of the language above.
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
+//~^ WARN the feature `let_chains` is incomplete
+
+#![allow(irrefutable_let_patterns)]
+
+use std::ops::Range;
+
+fn main() {}
+
+fn nested_within_if_expr() {
+ if &let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+
+ if !let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ if *let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR type `bool` cannot be dereferenced
+ if -let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR cannot apply unary operator `-` to type `bool`
+
+ fn _check_try_binds_tighter() -> Result<(), ()> {
+ if let 0 = 0? {}
+ //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+ Ok(())
+ }
+ if (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+ //~| ERROR the `?` operator can only be used in a function that returns `Result`
+
+ if true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ if (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ if true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ if true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+
+ let mut x = true;
+ if x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+
+ if true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+ if ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+ if (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+
+ // Binds as `(let ... = true)..true &&/|| false`.
+ if let Range { start: _, end: _ } = true..true && false {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ if let Range { start: _, end: _ } = true..true || false {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // Binds as `(let Range { start: F, end } = F)..(|| true)`.
+ const F: fn() -> bool = || true;
+ if let Range { start: F, end } = F..|| true {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // Binds as `(let Range { start: true, end } = t)..(&&false)`.
+ let t = &&true;
+ if let Range { start: true, end } = t..&&false {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+
+ if let true = let true = true {} //~ ERROR `let` expressions are not supported here
+}
+
+fn nested_within_while_expr() {
+ while &let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+
+ while !let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ while *let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR type `bool` cannot be dereferenced
+ while -let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR cannot apply unary operator `-` to type `bool`
+
+ fn _check_try_binds_tighter() -> Result<(), ()> {
+ while let 0 = 0? {}
+ //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+ Ok(())
+ }
+ while (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+ //~| ERROR the `?` operator can only be used in a function that returns `Result`
+
+ while true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ while (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ while true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ while true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+
+ let mut x = true;
+ while x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+
+ while true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+ while ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+ while (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here
+ //~^ ERROR mismatched types
+
+ // Binds as `(let ... = true)..true &&/|| false`.
+ while let Range { start: _, end: _ } = true..true && false {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ while let Range { start: _, end: _ } = true..true || false {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // Binds as `(let Range { start: F, end } = F)..(|| true)`.
+ const F: fn() -> bool = || true;
+ while let Range { start: F, end } = F..|| true {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // Binds as `(let Range { start: true, end } = t)..(&&false)`.
+ let t = &&true;
+ while let Range { start: true, end } = t..&&false {}
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+
+ while let true = let true = true {} //~ ERROR `let` expressions are not supported here
+}
+
+fn not_error_because_clarified_intent() {
+ if let Range { start: _, end: _ } = (true..true || false) { }
+
+ if let Range { start: _, end: _ } = (true..true && false) { }
+
+ while let Range { start: _, end: _ } = (true..true || false) { }
+
+ while let Range { start: _, end: _ } = (true..true && false) { }
+}
+
+fn outside_if_and_while_expr() {
+ &let 0 = 0; //~ ERROR `let` expressions are not supported here
+
+ !let 0 = 0; //~ ERROR `let` expressions are not supported here
+ *let 0 = 0; //~ ERROR `let` expressions are not supported here
+ //~^ ERROR type `bool` cannot be dereferenced
+ -let 0 = 0; //~ ERROR `let` expressions are not supported here
+ //~^ ERROR cannot apply unary operator `-` to type `bool`
+
+ fn _check_try_binds_tighter() -> Result<(), ()> {
+ let 0 = 0?;
+ //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+ Ok(())
+ }
+ (let 0 = 0)?; //~ ERROR `let` expressions are not supported here
+ //~^ ERROR the `?` operator can only be used in a function that returns `Result`
+ //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+
+ true || let 0 = 0; //~ ERROR `let` expressions are not supported here
+ (true || let 0 = 0); //~ ERROR `let` expressions are not supported here
+ true && (true || let 0 = 0); //~ ERROR `let` expressions are not supported here
+
+ let mut x = true;
+ x = let 0 = 0; //~ ERROR `let` expressions are not supported here
+
+ true..(let 0 = 0); //~ ERROR `let` expressions are not supported here
+ ..(let 0 = 0); //~ ERROR `let` expressions are not supported here
+ (let 0 = 0)..; //~ ERROR `let` expressions are not supported here
+
+ (let Range { start: _, end: _ } = true..true || false);
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+
+ (let true = let true = true);
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+
+ // Check function tail position.
+ &let 0 = 0
+ //~^ ERROR `let` expressions are not supported here
+ //~| ERROR mismatched types
+}
+
+// Let's make sure that `let` inside const generic arguments are considered.
+fn inside_const_generic_arguments() {
+ struct A<const B: bool>;
+ impl<const B: bool> A<{B}> { const O: u32 = 5; }
+
+ if let A::<{
+ true && let 1 = 1 //~ ERROR `let` expressions are not supported here
+ //~^ ERROR constant contains unimplemented expression type
+ //~| ERROR constant contains unimplemented expression type
+ }>::O = 5 {}
+
+ while let A::<{
+ true && let 1 = 1 //~ ERROR `let` expressions are not supported here
+ //~^ ERROR constant contains unimplemented expression type
+ //~| ERROR constant contains unimplemented expression type
+ }>::O = 5 {}
+
+ if A::<{
+ true && let 1 = 1 //~ ERROR `let` expressions are not supported here
+ //~^ ERROR constant contains unimplemented expression type
+ //~| ERROR constant contains unimplemented expression type
+ }>::O == 5 {}
+
+ // In the cases above we have `ExprKind::Block` to help us out.
+ // Below however, we would not have a block and so an implementation might go
+ // from visiting expressions to types without banning `let` expressions down the tree.
+ // This tests ensures that we are not caught by surprise should the parser
+ // admit non-IDENT expressions in const generic arguments.
+
+ if A::<
+ true && let 1 = 1 //~ ERROR expected one of `,` or `>`, found `&&`
+ >::O == 5 {}
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
new file mode 100644
index 0000000..207d0d6
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -0,0 +1,987 @@
+error: expected one of `,` or `>`, found `&&`
+ --> $DIR/disallowed-positions.rs:242:14
+ |
+LL | true && let 1 = 1
+ | ^^ expected one of `,` or `>` here
+
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/disallowed-positions.rs:20:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
+warning: the feature `let_chains` is incomplete and may cause the compiler to crash
+ --> $DIR/disallowed-positions.rs:22:12
+ |
+LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
+ | ^^^^^^^^^^
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:32:9
+ |
+LL | if &let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:35:9
+ |
+LL | if !let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:36:9
+ |
+LL | if *let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:38:9
+ |
+LL | if -let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:46:9
+ |
+LL | if (let 0 = 0)? {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:50:16
+ |
+LL | if true || let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:51:17
+ |
+LL | if (true || let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:52:25
+ |
+LL | if true && (true || let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:53:25
+ |
+LL | if true || (true && let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:56:12
+ |
+LL | if x = let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:59:15
+ |
+LL | if true..(let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:61:11
+ |
+LL | if ..(let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:63:9
+ |
+LL | if (let 0 = 0).. {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:67:8
+ |
+LL | if let Range { start: _, end: _ } = true..true && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:71:8
+ |
+LL | if let Range { start: _, end: _ } = true..true || false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:78:8
+ |
+LL | if let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:86:8
+ |
+LL | if let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:92:19
+ |
+LL | if let true = let true = true {}
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:96:12
+ |
+LL | while &let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:99:12
+ |
+LL | while !let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:100:12
+ |
+LL | while *let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:102:12
+ |
+LL | while -let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:110:12
+ |
+LL | while (let 0 = 0)? {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:114:19
+ |
+LL | while true || let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:115:20
+ |
+LL | while (true || let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:116:28
+ |
+LL | while true && (true || let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:117:28
+ |
+LL | while true || (true && let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:120:15
+ |
+LL | while x = let 0 = 0 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:123:18
+ |
+LL | while true..(let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:125:14
+ |
+LL | while ..(let 0 = 0) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:127:12
+ |
+LL | while (let 0 = 0).. {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:131:11
+ |
+LL | while let Range { start: _, end: _ } = true..true && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:135:11
+ |
+LL | while let Range { start: _, end: _ } = true..true || false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:142:11
+ |
+LL | while let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:150:11
+ |
+LL | while let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:156:22
+ |
+LL | while let true = let true = true {}
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:170:6
+ |
+LL | &let 0 = 0;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:172:6
+ |
+LL | !let 0 = 0;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:173:6
+ |
+LL | *let 0 = 0;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:175:6
+ |
+LL | -let 0 = 0;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:183:6
+ |
+LL | (let 0 = 0)?;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:187:13
+ |
+LL | true || let 0 = 0;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:188:14
+ |
+LL | (true || let 0 = 0);
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:189:22
+ |
+LL | true && (true || let 0 = 0);
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:192:9
+ |
+LL | x = let 0 = 0;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:194:12
+ |
+LL | true..(let 0 = 0);
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:195:8
+ |
+LL | ..(let 0 = 0);
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:196:6
+ |
+LL | (let 0 = 0)..;
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:198:6
+ |
+LL | (let Range { start: _, end: _ } = true..true || false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:202:6
+ |
+LL | (let true = let true = true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:202:17
+ |
+LL | (let true = let true = true);
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:207:6
+ |
+LL | &let 0 = 0
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:218:17
+ |
+LL | true && let 1 = 1
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:224:17
+ |
+LL | true && let 1 = 1
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/disallowed-positions.rs:230:17
+ |
+LL | true && let 1 = 1
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:32:8
+ |
+LL | if &let 0 = 0 {}
+ | ^^^^^^^^^^ expected bool, found &bool
+ |
+ = note: expected type `bool`
+ found type `&bool`
+
+error[E0614]: type `bool` cannot be dereferenced
+ --> $DIR/disallowed-positions.rs:36:8
+ |
+LL | if *let 0 = 0 {}
+ | ^^^^^^^^^^
+
+error[E0600]: cannot apply unary operator `-` to type `bool`
+ --> $DIR/disallowed-positions.rs:38:8
+ |
+LL | if -let 0 = 0 {}
+ | ^^^^^^^^^^ cannot apply unary operator `-`
+ |
+ = note: an implementation of `std::ops::Neg` might be missing for `bool`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/disallowed-positions.rs:46:8
+ |
+LL | if (let 0 = 0)? {}
+ | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `bool`
+ = note: required by `std::ops::Try::into_result`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/disallowed-positions.rs:46:8
+ |
+LL | if (let 0 = 0)? {}
+ | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `()`
+ = note: required by `std::ops::Try::from_error`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:56:8
+ |
+LL | if x = let 0 = 0 {}
+ | ^^^^^^^^^^^^^
+ | |
+ | expected bool, found ()
+ | help: try comparing for equality: `x == let 0 = 0`
+ |
+ = note: expected type `bool`
+ found type `()`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:59:8
+ |
+LL | if true..(let 0 = 0) {}
+ | ^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:61:8
+ |
+LL | if ..(let 0 = 0) {}
+ | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeTo`
+ |
+ = note: expected type `bool`
+ found type `std::ops::RangeTo<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:63:8
+ |
+LL | if (let 0 = 0).. {}
+ | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeFrom`
+ |
+ = note: expected type `bool`
+ found type `std::ops::RangeFrom<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:67:12
+ |
+LL | if let Range { start: _, end: _ } = true..true && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:67:8
+ |
+LL | if let Range { start: _, end: _ } = true..true && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:71:12
+ |
+LL | if let Range { start: _, end: _ } = true..true || false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:71:8
+ |
+LL | if let Range { start: _, end: _ } = true..true || false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:78:12
+ |
+LL | if let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range`
+ |
+ = note: expected type `fn() -> bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:78:41
+ |
+LL | if let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^ expected bool, found closure
+ |
+ = note: expected type `bool`
+ found type `[closure@$DIR/disallowed-positions.rs:78:41: 78:48]`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:78:8
+ |
+LL | if let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:86:12
+ |
+LL | if let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:86:44
+ |
+LL | if let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^ expected bool, found &&bool
+ |
+ = note: expected type `bool`
+ found type `&&bool`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:86:8
+ |
+LL | if let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/disallowed-positions.rs:42:20
+ |
+LL | if let 0 = 0? {}
+ | ^^ the `?` operator cannot be applied to type `{integer}`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `{integer}`
+ = note: required by `std::ops::Try::into_result`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:96:11
+ |
+LL | while &let 0 = 0 {}
+ | ^^^^^^^^^^ expected bool, found &bool
+ |
+ = note: expected type `bool`
+ found type `&bool`
+
+error[E0614]: type `bool` cannot be dereferenced
+ --> $DIR/disallowed-positions.rs:100:11
+ |
+LL | while *let 0 = 0 {}
+ | ^^^^^^^^^^
+
+error[E0600]: cannot apply unary operator `-` to type `bool`
+ --> $DIR/disallowed-positions.rs:102:11
+ |
+LL | while -let 0 = 0 {}
+ | ^^^^^^^^^^ cannot apply unary operator `-`
+ |
+ = note: an implementation of `std::ops::Neg` might be missing for `bool`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/disallowed-positions.rs:110:11
+ |
+LL | while (let 0 = 0)? {}
+ | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `bool`
+ = note: required by `std::ops::Try::into_result`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/disallowed-positions.rs:110:11
+ |
+LL | while (let 0 = 0)? {}
+ | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `()`
+ = note: required by `std::ops::Try::from_error`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:120:11
+ |
+LL | while x = let 0 = 0 {}
+ | ^^^^^^^^^^^^^
+ | |
+ | expected bool, found ()
+ | help: try comparing for equality: `x == let 0 = 0`
+ |
+ = note: expected type `bool`
+ found type `()`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:123:11
+ |
+LL | while true..(let 0 = 0) {}
+ | ^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:125:11
+ |
+LL | while ..(let 0 = 0) {}
+ | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeTo`
+ |
+ = note: expected type `bool`
+ found type `std::ops::RangeTo<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:127:11
+ |
+LL | while (let 0 = 0).. {}
+ | ^^^^^^^^^^^^^ expected bool, found struct `std::ops::RangeFrom`
+ |
+ = note: expected type `bool`
+ found type `std::ops::RangeFrom<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:131:15
+ |
+LL | while let Range { start: _, end: _ } = true..true && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:131:11
+ |
+LL | while let Range { start: _, end: _ } = true..true && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:135:15
+ |
+LL | while let Range { start: _, end: _ } = true..true || false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:135:11
+ |
+LL | while let Range { start: _, end: _ } = true..true || false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:142:15
+ |
+LL | while let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range`
+ |
+ = note: expected type `fn() -> bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:142:44
+ |
+LL | while let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^ expected bool, found closure
+ |
+ = note: expected type `bool`
+ found type `[closure@$DIR/disallowed-positions.rs:142:44: 142:51]`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:142:11
+ |
+LL | while let Range { start: F, end } = F..|| true {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:150:15
+ |
+LL | while let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:150:47
+ |
+LL | while let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^ expected bool, found &&bool
+ |
+ = note: expected type `bool`
+ found type `&&bool`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:150:11
+ |
+LL | while let Range { start: true, end } = t..&&false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<bool>`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/disallowed-positions.rs:106:23
+ |
+LL | while let 0 = 0? {}
+ | ^^ the `?` operator cannot be applied to type `{integer}`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `{integer}`
+ = note: required by `std::ops::Try::into_result`
+
+error[E0614]: type `bool` cannot be dereferenced
+ --> $DIR/disallowed-positions.rs:173:5
+ |
+LL | *let 0 = 0;
+ | ^^^^^^^^^^
+
+error[E0600]: cannot apply unary operator `-` to type `bool`
+ --> $DIR/disallowed-positions.rs:175:5
+ |
+LL | -let 0 = 0;
+ | ^^^^^^^^^^ cannot apply unary operator `-`
+ |
+ = note: an implementation of `std::ops::Neg` might be missing for `bool`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/disallowed-positions.rs:183:5
+ |
+LL | (let 0 = 0)?;
+ | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `bool`
+ = note: required by `std::ops::Try::into_result`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/disallowed-positions.rs:183:5
+ |
+LL | (let 0 = 0)?;
+ | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `()`
+ = note: required by `std::ops::Try::from_error`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:198:10
+ |
+LL | (let Range { start: _, end: _ } = true..true || false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool`
+ | |
+ | expected bool, found struct `std::ops::Range`
+ |
+ = note: expected type `bool`
+ found type `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+ --> $DIR/disallowed-positions.rs:207:5
+ |
+LL | fn outside_if_and_while_expr() {
+ | - help: try adding a return type: `-> &bool`
+...
+LL | &let 0 = 0
+ | ^^^^^^^^^^ expected (), found &bool
+ |
+ = note: expected type `()`
+ found type `&bool`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/disallowed-positions.rs:179:17
+ |
+LL | let 0 = 0?;
+ | ^^ the `?` operator cannot be applied to type `{integer}`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `{integer}`
+ = note: required by `std::ops::Try::into_result`
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/disallowed-positions.rs:218:25
+ |
+LL | true && let 1 = 1
+ | ^
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/disallowed-positions.rs:218:21
+ |
+LL | true && let 1 = 1
+ | ^
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/disallowed-positions.rs:224:25
+ |
+LL | true && let 1 = 1
+ | ^
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/disallowed-positions.rs:224:21
+ |
+LL | true && let 1 = 1
+ | ^
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/disallowed-positions.rs:230:25
+ |
+LL | true && let 1 = 1
+ | ^
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/disallowed-positions.rs:230:21
+ |
+LL | true && let 1 = 1
+ | ^
+
+error: aborting due to 109 previous errors
+
+Some errors have detailed explanations: E0019, E0277, E0308, E0600, E0614.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
new file mode 100644
index 0000000..6498766
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
@@ -0,0 +1,136 @@
+// gate-test-let_chains
+
+// Here we test feature gating for ´let_chains`.
+// See `disallowed-positions.rs` for the grammar
+// defining the language for gated allowed positions.
+
+#![allow(irrefutable_let_patterns)]
+
+use std::ops::Range;
+
+fn _if() {
+ if let 0 = 1 {} // Stable!
+
+ if (let 0 = 1) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ if (((let 0 = 1))) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ if true && let 0 = 1 {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ if let 0 = 1 && true {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ if (let 0 = 1) && true {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ if true && (let 0 = 1) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ if (let 0 = 1) && (let 0 = 1) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+
+ if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+
+ if let Range { start: _, end: _ } = (true..true) && false {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+}
+
+fn _while() {
+ while let 0 = 1 {} // Stable!
+
+ while (let 0 = 1) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ while (((let 0 = 1))) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ while true && let 0 = 1 {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ while let 0 = 1 && true {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ while (let 0 = 1) && true {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ while true && (let 0 = 1) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+
+ while (let 0 = 1) && (let 0 = 1) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+
+ while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+ //~| ERROR `let` expressions are not supported here
+
+ while let Range { start: _, end: _ } = (true..true) && false {}
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+}
+
+fn _macros() {
+ macro_rules! noop_expr { ($e:expr) => {}; }
+
+ noop_expr!((let 0 = 1));
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+
+ macro_rules! use_expr {
+ ($e:expr) => {
+ if $e {}
+ while $e {}
+ }
+ }
+ use_expr!((let 0 = 1 && 0 == 0));
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+ use_expr!((let 0 = 1));
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ //~| ERROR `let` expressions are not supported here
+ #[cfg(FALSE)] (let 0 = 1);
+ //~^ ERROR `let` expressions in this position are experimental [E0658]
+ use_expr!(let 0 = 1);
+ //~^ ERROR no rules expected the token `let`
+ // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`.
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
new file mode 100644
index 0000000..6167427
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
@@ -0,0 +1,570 @@
+error: no rules expected the token `let`
+ --> $DIR/feature-gate.rs:131:15
+ |
+LL | macro_rules! use_expr {
+ | --------------------- when calling this macro
+...
+LL | use_expr!(let 0 = 1);
+ | ^^^ no rules expected this token in macro call
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:14:9
+ |
+LL | if (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:18:11
+ |
+LL | if (((let 0 = 1))) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:22:16
+ |
+LL | if true && let 0 = 1 {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:26:8
+ |
+LL | if let 0 = 1 && true {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:30:9
+ |
+LL | if (let 0 = 1) && true {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:34:17
+ |
+LL | if true && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:38:9
+ |
+LL | if (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:38:24
+ |
+LL | if (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:44:8
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:44:21
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:44:35
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:44:48
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:44:61
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:56:8
+ |
+LL | if let Range { start: _, end: _ } = (true..true) && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:64:12
+ |
+LL | while (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:68:14
+ |
+LL | while (((let 0 = 1))) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:72:19
+ |
+LL | while true && let 0 = 1 {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:76:11
+ |
+LL | while let 0 = 1 && true {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:80:12
+ |
+LL | while (let 0 = 1) && true {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:84:20
+ |
+LL | while true && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:88:12
+ |
+LL | while (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:88:27
+ |
+LL | while (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:94:11
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:94:24
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:94:38
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:94:51
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:94:64
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:106:11
+ |
+LL | while let Range { start: _, end: _ } = (true..true) && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:129:20
+ |
+LL | #[cfg(FALSE)] (let 0 = 1);
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:114:17
+ |
+LL | noop_expr!((let 0 = 1));
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:123:16
+ |
+LL | use_expr!((let 0 = 1 && 0 == 0));
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are experimental
+ --> $DIR/feature-gate.rs:126:16
+ |
+LL | use_expr!((let 0 = 1));
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/53667
+ = help: add #![feature(let_chains)] to the crate attributes to enable
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:14:9
+ |
+LL | if (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:18:11
+ |
+LL | if (((let 0 = 1))) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:22:16
+ |
+LL | if true && let 0 = 1 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:26:8
+ |
+LL | if let 0 = 1 && true {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:30:9
+ |
+LL | if (let 0 = 1) && true {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:34:17
+ |
+LL | if true && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:38:9
+ |
+LL | if (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:38:24
+ |
+LL | if (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:44:8
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:44:21
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:44:35
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:44:48
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:44:61
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:56:8
+ |
+LL | if let Range { start: _, end: _ } = (true..true) && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:64:12
+ |
+LL | while (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:68:14
+ |
+LL | while (((let 0 = 1))) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:72:19
+ |
+LL | while true && let 0 = 1 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:76:11
+ |
+LL | while let 0 = 1 && true {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:80:12
+ |
+LL | while (let 0 = 1) && true {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:84:20
+ |
+LL | while true && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:88:12
+ |
+LL | while (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:88:27
+ |
+LL | while (let 0 = 1) && (let 0 = 1) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:94:11
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:94:24
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:94:38
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:94:51
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:94:64
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:106:11
+ |
+LL | while let Range { start: _, end: _ } = (true..true) && false {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:123:16
+ |
+LL | use_expr!((let 0 = 1 && 0 == 0));
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+ --> $DIR/feature-gate.rs:126:16
+ |
+LL | use_expr!((let 0 = 1));
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if`- and `while`-expressions
+ = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: aborting due to 63 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
new file mode 100644
index 0000000..1de4e5b
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+#![allow(irrefutable_let_patterns)]
+
+use std::ops::Range;
+
+fn main() {
+ let x: bool;
+ // This should associate as: `(x = (true && false));`.
+ x = true && false;
+ assert!(!x);
+
+ fn _f1() -> bool {
+ // Should associate as `(let _ = (return (true && false)))`.
+ if let _ = return true && false {};
+ }
+ assert!(!_f1());
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs
deleted file mode 100644
index d79798d..0000000
--- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// edition:2015
-
-// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
-// with examples easier.
-
-#[allow(irrefutable_let_patterns)]
-fn main() {
- use std::ops::Range;
-
- if let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambiguous use of `&&`
-
- if let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambiguous use of `||`
-
- while let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambiguous use of `&&`
-
- while let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambiguous use of `||`
-
- if let true = false && false { }
- //~^ ERROR ambiguous use of `&&`
-
- while let true = (1 == 2) && false { }
- //~^ ERROR ambiguous use of `&&`
-
- // The following cases are not an error as parenthesis are used to
- // clarify intent:
-
- if let Range { start: _, end: _ } = true..(true || false) { }
-
- if let Range { start: _, end: _ } = true..(true && false) { }
-
- while let Range { start: _, end: _ } = true..(true || false) { }
-
- while let Range { start: _, end: _ } = true..(true && false) { }
-}
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr
deleted file mode 100644
index 2cd59fe..0000000
--- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr
+++ /dev/null
@@ -1,56 +0,0 @@
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2015.rs:10:47
- |
-LL | if let Range { start: _, end: _ } = true..true && false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `||`
- --> $DIR/syntax-ambiguity-2015.rs:13:47
- |
-LL | if let Range { start: _, end: _ } = true..true || false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2015.rs:16:50
- |
-LL | while let Range { start: _, end: _ } = true..true && false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `||`
- --> $DIR/syntax-ambiguity-2015.rs:19:50
- |
-LL | while let Range { start: _, end: _ } = true..true || false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2015.rs:22:19
- |
-LL | if let true = false && false { }
- | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2015.rs:25:22
- |
-LL | while let true = (1 == 2) && false { }
- | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: aborting due to 6 previous errors
-
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs
deleted file mode 100644
index 687bf65..0000000
--- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// edition:2018
-
-// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
-// with examples easier.
-
-#[allow(irrefutable_let_patterns)]
-fn main() {
- use std::ops::Range;
-
- if let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambiguous use of `&&`
-
- if let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambiguous use of `||`
-
- while let Range { start: _, end: _ } = true..true && false { }
- //~^ ERROR ambiguous use of `&&`
-
- while let Range { start: _, end: _ } = true..true || false { }
- //~^ ERROR ambiguous use of `||`
-
- if let true = false && false { }
- //~^ ERROR ambiguous use of `&&`
-
- while let true = (1 == 2) && false { }
- //~^ ERROR ambiguous use of `&&`
-
- // The following cases are not an error as parenthesis are used to
- // clarify intent:
-
- if let Range { start: _, end: _ } = true..(true || false) { }
-
- if let Range { start: _, end: _ } = true..(true && false) { }
-
- while let Range { start: _, end: _ } = true..(true || false) { }
-
- while let Range { start: _, end: _ } = true..(true && false) { }
-}
diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr
deleted file mode 100644
index cbba2d7..0000000
--- a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr
+++ /dev/null
@@ -1,56 +0,0 @@
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2018.rs:10:47
- |
-LL | if let Range { start: _, end: _ } = true..true && false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `||`
- --> $DIR/syntax-ambiguity-2018.rs:13:47
- |
-LL | if let Range { start: _, end: _ } = true..true || false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2018.rs:16:50
- |
-LL | while let Range { start: _, end: _ } = true..true && false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `||`
- --> $DIR/syntax-ambiguity-2018.rs:19:50
- |
-LL | while let Range { start: _, end: _ } = true..true || false { }
- | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2018.rs:22:19
- |
-LL | if let true = false && false { }
- | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: ambiguous use of `&&`
- --> $DIR/syntax-ambiguity-2018.rs:25:22
- |
-LL | while let true = (1 == 2) && false { }
- | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
- |
- = note: this will be a error until the `let_chains` feature is stabilized
- = note: see rust-lang/rust#53668 for more information
-
-error: aborting due to 6 previous errors
-
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
index 876a0a5..92b25cb 100644
--- a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
@@ -1,20 +1,16 @@
-// compile-pass
-
-#![deny(single_use_lifetimes)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
-
// Test that we DO NOT warn when lifetime name is used only
// once in a fn return type -- using `'_` is not legal there,
// as it must refer back to an argument.
//
// (Normally, using `'static` would be preferred, but there are
// times when that is not what you want.)
-//
-// run-pass
+
+// compile-pass
+
+#![deny(single_use_lifetimes)]
fn b<'a>() -> &'a u32 { // OK: used only in return type
&22
}
-fn main() { }
+fn main() {}
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index ab5594f..6ce7461 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -290,6 +290,13 @@
}
}
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum PassMode {
+ Check,
+ Build,
+ Run,
+}
+
#[derive(Clone, Debug)]
pub struct TestProps {
// Lines that should be expected, in order, on standard out
@@ -349,14 +356,10 @@
// testing harness and used when generating compilation
// arguments. (In particular, it propagates to the aux-builds.)
pub incremental_dir: Option<PathBuf>,
- // Specifies that a test must actually compile without errors.
- pub compile_pass: bool,
+ // How far should the test proceed while still passing.
+ pub pass_mode: Option<PassMode>,
// rustdoc will test the output of the `--test` option
pub check_test_line_numbers_match: bool,
- // The test must be compiled and run successfully. Only used in UI tests for now.
- pub run_pass: bool,
- // Skip any codegen step and running the executable. Only for run-pass.
- pub skip_codegen: bool,
// Do not pass `-Z ui-testing` to UI tests
pub disable_ui_testing_normalization: bool,
// customized normalization rules
@@ -396,10 +399,8 @@
pretty_compare_only: false,
forbid_output: vec![],
incremental_dir: None,
- compile_pass: false,
+ pass_mode: None,
check_test_line_numbers_match: false,
- run_pass: false,
- skip_codegen: false,
disable_ui_testing_normalization: false,
normalize_stdout: vec![],
normalize_stderr: vec![],
@@ -525,18 +526,7 @@
self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln);
}
- if !self.run_pass {
- self.run_pass = config.parse_run_pass(ln);
- }
-
- if !self.compile_pass {
- // run-pass implies compile_pass
- self.compile_pass = config.parse_compile_pass(ln) || self.run_pass;
- }
-
- if !self.skip_codegen {
- self.skip_codegen = config.parse_skip_codegen(ln);
- }
+ self.update_pass_mode(ln, cfg, config);
if !self.disable_ui_testing_normalization {
self.disable_ui_testing_normalization =
@@ -583,6 +573,41 @@
}
}
}
+
+ fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
+ let check_no_run = |s| {
+ if config.mode != Mode::Ui && config.mode != Mode::Incremental {
+ panic!("`{}` header is only supported in UI and incremental tests", s);
+ }
+ if config.mode == Mode::Incremental &&
+ !revision.map_or(false, |r| r.starts_with("cfail")) &&
+ !self.revisions.iter().all(|r| r.starts_with("cfail")) {
+ panic!("`{}` header is only supported in `cfail` incremental tests", s);
+ }
+ };
+ let pass_mode = if config.parse_name_directive(ln, "check-pass") {
+ check_no_run("check-pass");
+ Some(PassMode::Check)
+ } else if config.parse_name_directive(ln, "build-pass") {
+ check_no_run("build-pass");
+ Some(PassMode::Build)
+ } else if config.parse_name_directive(ln, "compile-pass") /* compatibility */ {
+ check_no_run("compile-pass");
+ Some(PassMode::Build)
+ } else if config.parse_name_directive(ln, "run-pass") {
+ if config.mode != Mode::Ui && config.mode != Mode::RunPass /* compatibility */ {
+ panic!("`run-pass` header is only supported in UI tests")
+ }
+ Some(PassMode::Run)
+ } else {
+ None
+ };
+ match (self.pass_mode, pass_mode) {
+ (None, Some(_)) => self.pass_mode = pass_mode,
+ (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"),
+ (_, None) => {}
+ }
+ }
}
fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
@@ -710,10 +735,6 @@
}
}
- fn parse_compile_pass(&self, line: &str) -> bool {
- self.parse_name_directive(line, "compile-pass")
- }
-
fn parse_disable_ui_testing_normalization(&self, line: &str) -> bool {
self.parse_name_directive(line, "disable-ui-testing-normalization")
}
@@ -722,14 +743,6 @@
self.parse_name_directive(line, "check-test-line-numbers-match")
}
- fn parse_run_pass(&self, line: &str) -> bool {
- self.parse_name_directive(line, "run-pass")
- }
-
- fn parse_skip_codegen(&self, line: &str) -> bool {
- self.parse_name_directive(line, "skip-codegen")
- }
-
fn parse_assembly_output(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "assembly-output")
.map(|r| r.trim().to_string())
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index d87bd66..8b52a52 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -10,7 +10,7 @@
use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly};
use diff;
use crate::errors::{self, Error, ErrorKind};
-use crate::header::TestProps;
+use crate::header::{TestProps, PassMode};
use crate::json;
use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
@@ -310,20 +310,19 @@
}
fn should_run_successfully(&self) -> bool {
- let run_pass = match self.config.mode {
+ match self.config.mode {
RunPass => true,
- Ui => self.props.run_pass,
- _ => unimplemented!(),
- };
- return run_pass && !self.props.skip_codegen;
+ Ui => self.props.pass_mode == Some(PassMode::Run),
+ mode => panic!("unimplemented for mode {:?}", mode),
+ }
}
fn should_compile_successfully(&self) -> bool {
match self.config.mode {
- CompileFail => self.props.compile_pass,
+ CompileFail => false,
RunPass => true,
JsDocTest => true,
- Ui => self.props.compile_pass,
+ Ui => self.props.pass_mode.is_some(),
Incremental => {
let revision = self.revision
.expect("incremental tests require a list of revisions");
@@ -331,7 +330,7 @@
true
} else if revision.starts_with("cfail") {
// FIXME: would be nice if incremental revs could start with "cpass"
- self.props.compile_pass
+ self.props.pass_mode.is_some()
} else {
panic!("revision name must begin with rpass, rfail, or cfail");
}
@@ -433,11 +432,9 @@
"run-pass tests with expected warnings should be moved to ui/"
);
- if !self.props.skip_codegen {
- let proc_res = self.exec_compiled_test();
- if !proc_res.status.success() {
- self.fatal_proc_rec("test run failed!", &proc_res);
- }
+ let proc_res = self.exec_compiled_test();
+ if !proc_res.status.success() {
+ self.fatal_proc_rec("test run failed!", &proc_res);
}
}
@@ -1344,7 +1341,7 @@
fn check_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) {
debug!("check_error_patterns");
if self.props.error_patterns.is_empty() {
- if self.props.compile_pass {
+ if self.props.pass_mode.is_some() {
return;
} else {
self.fatal(&format!(
@@ -1971,7 +1968,7 @@
}
}
- if self.props.skip_codegen {
+ if self.props.pass_mode == Some(PassMode::Check) {
assert!(
!self
.props
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index eeac6cf..43cae31 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -8,3 +8,5 @@
regex = "1"
serde = { version = "1.0.8", features = ["derive"] }
serde_json = "1.0.2"
+lazy_static = "1"
+walkdir = "2"
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 610d1d8..680585a 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -25,16 +25,17 @@
}
}
- super::walk(path,
+ super::walk_no_read(path,
&mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
- &mut |file| {
+ &mut |entry| {
+ let file = entry.path();
let filename = file.file_name().unwrap().to_string_lossy();
let extensions = [".py", ".sh"];
if extensions.iter().any(|e| filename.ends_with(e)) {
return;
}
- let metadata = t!(fs::symlink_metadata(&file), &file);
+ let metadata = t!(entry.metadata(), file);
if metadata.mode() & 0o111 != 0 {
let rel_path = file.strip_prefix(path).unwrap();
let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs
index ef1000e..1bc2774 100644
--- a/src/tools/tidy/src/errors.rs
+++ b/src/tools/tidy/src/errors.rs
@@ -4,24 +4,19 @@
//! statistics about the error codes.
use std::collections::HashMap;
-use std::fs::File;
-use std::io::prelude::*;
use std::path::Path;
pub fn check(path: &Path, bad: &mut bool) {
- let mut contents = String::new();
let mut map: HashMap<_, Vec<_>> = HashMap::new();
super::walk(path,
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
- &mut |file| {
+ &mut |entry, contents| {
+ let file = entry.path();
let filename = file.file_name().unwrap().to_string_lossy();
if filename != "error_codes.rs" {
return
}
- contents.truncate(0);
- t!(t!(File::open(file)).read_to_string(&mut contents));
-
// In the `register_long_diagnostics!` macro, entries look like this:
//
// ```
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 637f10c..1841beb 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -11,11 +11,10 @@
use std::collections::HashMap;
use std::fmt;
-use std::fs::{self, File};
-use std::io::prelude::*;
+use std::fs;
use std::path::Path;
-use regex::{Regex, escape};
+use regex::Regex;
mod version;
use version::Version;
@@ -51,20 +50,48 @@
pub type Features = HashMap<String, Feature>;
-pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
+pub struct CollectedFeatures {
+ pub lib: Features,
+ pub lang: Features,
+}
+
+// Currently only used for unstable book generation
+pub fn collect_lib_features(base_src_path: &Path) -> Features {
+ let mut lib_features = Features::new();
+
+ // This library feature is defined in the `compiler_builtins` crate, which
+ // has been moved out-of-tree. Now it can no longer be auto-discovered by
+ // `tidy`, because we need to filter out its (submodule) directory. Manually
+ // add it to the set of known library features so we can still generate docs.
+ lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
+ level: Status::Unstable,
+ since: None,
+ has_gate_test: false,
+ tracking_issue: None,
+ });
+
+ map_lib_features(base_src_path,
+ &mut |res, _, _| {
+ if let Ok((name, feature)) = res {
+ lib_features.insert(name.to_owned(), feature);
+ }
+ });
+ lib_features
+}
+
+pub fn check(path: &Path, bad: &mut bool, verbose: bool) -> CollectedFeatures {
let mut features = collect_lang_features(path, bad);
assert!(!features.is_empty());
let lib_features = get_and_check_lib_features(path, bad, &features);
assert!(!lib_features.is_empty());
- let mut contents = String::new();
-
super::walk_many(&[&path.join("test/ui"),
&path.join("test/ui-fulldeps"),
&path.join("test/compile-fail")],
&mut |path| super::filter_dirs(path),
- &mut |file| {
+ &mut |entry, contents| {
+ let file = entry.path();
let filename = file.file_name().unwrap().to_string_lossy();
if !filename.ends_with(".rs") || filename == "features.rs" ||
filename == "diagnostic_list.rs" {
@@ -74,9 +101,6 @@
let filen_underscore = filename.replace('-',"_").replace(".rs","");
let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);
- contents.truncate(0);
- t!(t!(File::open(&file), &file).read_to_string(&mut contents));
-
for (i, line) in contents.lines().enumerate() {
let mut err = |msg: &str| {
tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
@@ -130,21 +154,23 @@
}
if *bad {
- return;
+ return CollectedFeatures { lib: lib_features, lang: features };
}
- if quiet {
+
+ if verbose {
+ let mut lines = Vec::new();
+ lines.extend(format_features(&features, "lang"));
+ lines.extend(format_features(&lib_features, "lib"));
+
+ lines.sort();
+ for line in lines {
+ println!("* {}", line);
+ }
+ } else {
println!("* {} features", features.len());
- return;
}
- let mut lines = Vec::new();
- lines.extend(format_features(&features, "lang"));
- lines.extend(format_features(&lib_features, "lib"));
-
- lines.sort();
- for line in lines {
- println!("* {}", line);
- }
+ CollectedFeatures { lib: lib_features, lang: features }
}
fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator<Item = String> + 'a {
@@ -159,8 +185,19 @@
}
fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
- let r = Regex::new(&format!(r#"{}\s*=\s*"([^"]*)""#, escape(attr)))
- .expect("malformed regex for find_attr_val");
+ lazy_static::lazy_static! {
+ static ref ISSUE: Regex = Regex::new(r#"issue\s*=\s*"([^"]*)""#).unwrap();
+ static ref FEATURE: Regex = Regex::new(r#"feature\s*=\s*"([^"]*)""#).unwrap();
+ static ref SINCE: Regex = Regex::new(r#"since\s*=\s*"([^"]*)""#).unwrap();
+ }
+
+ let r = match attr {
+ "issue" => &*ISSUE,
+ "feature" => &*FEATURE,
+ "since" => &*SINCE,
+ _ => unimplemented!("{} not handled", attr),
+ };
+
r.captures(line)
.and_then(|c| c.get(1))
.map(|m| m.as_str())
@@ -175,9 +212,11 @@
}
fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
- if filen_underscore.starts_with("feature_gate") {
+ let prefix = "feature_gate_";
+ if filen_underscore.starts_with(prefix) {
for (n, f) in features.iter_mut() {
- if filen_underscore == format!("feature_gate_{}", n) {
+ // Equivalent to filen_underscore == format!("feature_gate_{}", n)
+ if &filen_underscore[prefix.len()..] == n {
f.has_gate_test = true;
return true;
}
@@ -295,32 +334,6 @@
.collect()
}
-pub fn collect_lib_features(base_src_path: &Path) -> Features {
- let mut lib_features = Features::new();
-
- // This library feature is defined in the `compiler_builtins` crate, which
- // has been moved out-of-tree. Now it can no longer be auto-discovered by
- // `tidy`, because we need to filter out its (submodule) directory. Manually
- // add it to the set of known library features so we can still generate docs.
- lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
- level: Status::Unstable,
- since: None,
- has_gate_test: false,
- tracking_issue: None,
- });
-
- map_lib_features(base_src_path,
- &mut |res, _, _| {
- if let Ok((name, feature)) = res {
- if lib_features.contains_key(name) {
- return;
- }
- lib_features.insert(name.to_owned(), feature);
- }
- });
- lib_features
-}
-
fn get_and_check_lib_features(base_src_path: &Path,
bad: &mut bool,
lang_features: &Features) -> Features {
@@ -355,20 +368,25 @@
fn map_lib_features(base_src_path: &Path,
mf: &mut dyn FnMut(Result<(&str, Feature), &str>, &Path, usize)) {
- let mut contents = String::new();
super::walk(base_src_path,
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
- &mut |file| {
+ &mut |entry, contents| {
+ let file = entry.path();
let filename = file.file_name().unwrap().to_string_lossy();
if !filename.ends_with(".rs") || filename == "features.rs" ||
filename == "diagnostic_list.rs" {
return;
}
- contents.truncate(0);
- t!(t!(File::open(&file), &file).read_to_string(&mut contents));
+ // This is an early exit -- all the attributes we're concerned with must contain this:
+ // * rustc_const_unstable(
+ // * unstable(
+ // * stable(
+ if !contents.contains("stable(") {
+ return;
+ }
- let mut becoming_feature: Option<(String, Feature)> = None;
+ let mut becoming_feature: Option<(&str, Feature)> = None;
for (i, line) in contents.lines().enumerate() {
macro_rules! err {
($msg:expr) => {{
@@ -447,7 +465,7 @@
if line.contains(']') {
mf(Ok((feature_name, feature)), file, i + 1);
} else {
- becoming_feature = Some((feature_name.to_owned(), feature));
+ becoming_feature = Some((feature_name, feature));
}
}
});
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index d06c997..a0bf0b0 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -3,7 +3,9 @@
//! This library contains the tidy lints and exposes it
//! to be used by tools.
-use std::fs;
+use walkdir::{DirEntry, WalkDir};
+use std::fs::File;
+use std::io::Read;
use std::path::Path;
@@ -65,25 +67,35 @@
skip.iter().any(|p| path.ends_with(p))
}
-fn walk_many(paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&Path)) {
+
+fn walk_many(
+ paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)
+) {
for path in paths {
walk(path, skip, f);
}
}
-fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&Path)) {
- if let Ok(dir) = fs::read_dir(path) {
- for entry in dir {
- let entry = t!(entry);
- let kind = t!(entry.file_type());
- let path = entry.path();
- if kind.is_dir() {
- if !skip(&path) {
- walk(&path, skip, f);
- }
- } else {
- f(&path);
+fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
+ let mut contents = String::new();
+ walk_no_read(path, skip, &mut |entry| {
+ contents.clear();
+ if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
+ contents.clear();
+ }
+ f(&entry, &contents);
+ });
+}
+
+fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) {
+ let walker = WalkDir::new(path).into_iter()
+ .filter_entry(|e| !skip(e.path()));
+ for entry in walker {
+ if let Ok(entry) = entry {
+ if entry.file_type().is_dir() {
+ continue;
}
+ f(&entry);
}
}
}
diff --git a/src/tools/tidy/src/libcoretest.rs b/src/tools/tidy/src/libcoretest.rs
index b15b9c3..ea92f98 100644
--- a/src/tools/tidy/src/libcoretest.rs
+++ b/src/tools/tidy/src/libcoretest.rs
@@ -4,29 +4,22 @@
//! item. All tests must be written externally in `libcore/tests`.
use std::path::Path;
-use std::fs::read_to_string;
pub fn check(path: &Path, bad: &mut bool) {
let libcore_path = path.join("libcore");
super::walk(
&libcore_path,
&mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
- &mut |subpath| {
+ &mut |entry, contents| {
+ let subpath = entry.path();
if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
- match read_to_string(subpath) {
- Ok(contents) => {
- if contents.contains("#[test]") {
- tidy_error!(
- bad,
- "{} contains #[test]; libcore tests must be placed inside \
- `src/libcore/tests/`",
- subpath.display()
- );
- }
- }
- Err(err) => {
- panic!("failed to read file {:?}: {}", subpath, err);
- }
+ if contents.contains("#[test]") {
+ tidy_error!(
+ bad,
+ "{} contains #[test]; libcore tests must be placed inside \
+ `src/libcore/tests/`",
+ subpath.display()
+ );
}
}
},
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index eef3719..918762e 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -19,14 +19,14 @@
let args: Vec<String> = env::args().skip(1).collect();
let mut bad = false;
- let quiet = args.iter().any(|s| *s == "--quiet");
+ let verbose = args.iter().any(|s| *s == "--verbose");
bins::check(&path, &mut bad);
style::check(&path, &mut bad);
errors::check(&path, &mut bad);
cargo::check(&path, &mut bad);
- features::check(&path, &mut bad, quiet);
+ let collected = features::check(&path, &mut bad, verbose);
pal::check(&path, &mut bad);
- unstable_book::check(&path, &mut bad);
+ unstable_book::check(&path, collected, &mut bad);
libcoretest::check(&path, &mut bad);
if !args.iter().any(|s| *s == "--no-vendor") {
deps::check(&path, &mut bad);
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index d4a6cf7..c6bb163 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -31,8 +31,6 @@
//! platform-specific cfgs are allowed. Not sure yet how to deal with
//! this in the long term.
-use std::fs::File;
-use std::io::Read;
use std::path::Path;
use std::iter::Iterator;
@@ -87,29 +85,26 @@
];
pub fn check(path: &Path, bad: &mut bool) {
- let mut contents = String::new();
// Sanity check that the complex parsing here works.
let mut saw_target_arch = false;
let mut saw_cfg_bang = false;
- super::walk(path, &mut super::filter_dirs, &mut |file| {
+ super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
+ let file = entry.path();
let filestr = file.to_string_lossy().replace("\\", "/");
if !filestr.ends_with(".rs") { return }
let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
if is_exception_path { return }
- check_cfgs(&mut contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
+ check_cfgs(contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
});
assert!(saw_target_arch);
assert!(saw_cfg_bang);
}
-fn check_cfgs(contents: &mut String, file: &Path,
+fn check_cfgs(contents: &str, file: &Path,
bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
- contents.truncate(0);
- t!(t!(File::open(file), file).read_to_string(contents));
-
// For now it's ok to have platform-specific code after 'mod tests'.
let mod_tests_idx = find_test_mod(contents);
let contents = &contents[..mod_tests_idx];
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index e860f2e..4a159d9 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -13,8 +13,6 @@
//! A number of these checks can be opted-out of with various directives of the form:
//! `// ignore-tidy-CHECK-NAME`.
-use std::fs::File;
-use std::io::prelude::*;
use std::path::Path;
const COLS: usize = 100;
@@ -109,7 +107,11 @@
Ignore(bool),
}
-fn contains_ignore_directive(contents: &String, check: &str) -> Directive {
+fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive {
+ if !can_contain {
+ return Directive::Deny;
+ }
+ // Update `can_contain` when changing this
if contents.contains(&format!("// ignore-tidy-{}", check)) ||
contents.contains(&format!("# ignore-tidy-{}", check)) {
Directive::Ignore(false)
@@ -129,8 +131,8 @@
}
pub fn check(path: &Path, bad: &mut bool) {
- let mut contents = String::new();
- super::walk(path, &mut super::filter_dirs, &mut |file| {
+ super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
+ let file = entry.path();
let filename = file.file_name().unwrap().to_string_lossy();
let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"];
if extensions.iter().all(|e| !filename.ends_with(e)) ||
@@ -138,19 +140,19 @@
return
}
- contents.truncate(0);
- t!(t!(File::open(file), file).read_to_string(&mut contents));
-
if contents.is_empty() {
tidy_error!(bad, "{}: empty file", file.display());
}
- let mut skip_cr = contains_ignore_directive(&contents, "cr");
- let mut skip_tab = contains_ignore_directive(&contents, "tab");
- let mut skip_line_length = contains_ignore_directive(&contents, "linelength");
- let mut skip_file_length = contains_ignore_directive(&contents, "filelength");
- let mut skip_end_whitespace = contains_ignore_directive(&contents, "end-whitespace");
- let mut skip_copyright = contains_ignore_directive(&contents, "copyright");
+ let can_contain = contents.contains("// ignore-tidy-") ||
+ contents.contains("# ignore-tidy-");
+ let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
+ let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
+ let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
+ let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
+ let mut skip_end_whitespace =
+ contains_ignore_directive(can_contain, &contents, "end-whitespace");
+ let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
let mut leading_new_lines = false;
let mut trailing_new_lines = 0;
let mut lines = 0;
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index b572b52..2c52cec 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -4,10 +4,9 @@
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| {
+ for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] {
+ super::walk_no_read(path, &mut |_| false, &mut |entry| {
+ let file_path = entry.path();
if let Some(ext) = file_path.extension() {
if ext == "stderr" || ext == "stdout" {
// Test output filenames have one of the formats:
@@ -45,6 +44,6 @@
}
}
}
- },
- );
+ });
+ }
}
diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs
index f7e40ce..fb63520 100644
--- a/src/tools/tidy/src/unstable_book.rs
+++ b/src/tools/tidy/src/unstable_book.rs
@@ -1,7 +1,7 @@
use std::collections::BTreeSet;
use std::fs;
-use std::path;
-use crate::features::{collect_lang_features, collect_lib_features, Features, Status};
+use std::path::{PathBuf, Path};
+use crate::features::{CollectedFeatures, Features, Feature, Status};
pub const PATH_STR: &str = "doc/unstable-book";
@@ -12,19 +12,19 @@
pub const LIB_FEATURES_DIR: &str = "src/library-features";
/// Builds the path to the Unstable Book source directory from the Rust 'src' directory.
-pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf {
+pub fn unstable_book_path(base_src_path: &Path) -> PathBuf {
base_src_path.join(PATH_STR)
}
/// Builds the path to the directory where the features are documented within the Unstable Book
/// source directory.
-pub fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf {
+pub fn unstable_book_lang_features_path(base_src_path: &Path) -> PathBuf {
unstable_book_path(base_src_path).join(LANG_FEATURES_DIR)
}
/// Builds the path to the directory where the features are documented within the Unstable Book
/// source directory.
-pub fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf {
+pub fn unstable_book_lib_features_path(base_src_path: &Path) -> PathBuf {
unstable_book_path(base_src_path).join(LIB_FEATURES_DIR)
}
@@ -45,7 +45,7 @@
.collect()
}
-pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet<String> {
+pub fn collect_unstable_book_section_file_names(dir: &Path) -> BTreeSet<String> {
fs::read_dir(dir)
.expect("could not read directory")
.map(|entry| entry.expect("could not read directory entry"))
@@ -60,7 +60,7 @@
///
/// * hyphens replaced by underscores,
/// * the markdown suffix ('.md') removed.
-fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::Path)
+fn collect_unstable_book_lang_features_section_file_names(base_src_path: &Path)
-> BTreeSet<String> {
collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path))
}
@@ -69,18 +69,26 @@
///
/// * hyphens replaced by underscores,
/// * the markdown suffix ('.md') removed.
-fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path)
- -> BTreeSet<String> {
+fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) -> BTreeSet<String> {
collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path))
}
-pub fn check(path: &path::Path, bad: &mut bool) {
- // Library features
-
- let lang_features = collect_lang_features(path, bad);
- let lib_features = collect_lib_features(path).into_iter().filter(|&(ref name, _)| {
+pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) {
+ let lang_features = features.lang;
+ let mut lib_features = features.lib.into_iter().filter(|&(ref name, _)| {
!lang_features.contains_key(name)
- }).collect();
+ }).collect::<Features>();
+
+ // This library feature is defined in the `compiler_builtins` crate, which
+ // has been moved out-of-tree. Now it can no longer be auto-discovered by
+ // `tidy`, because we need to filter out its (submodule) directory. Manually
+ // add it to the set of known library features so we can still generate docs.
+ lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
+ level: Status::Unstable,
+ since: None,
+ has_gate_test: false,
+ tracking_issue: None,
+ });
// Library features
let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features);