diff options
114 files changed, 1499 insertions, 346 deletions
diff --git a/Cargo.lock b/Cargo.lock index 1dfe710ecee..f49c8515fca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2297,9 +2297,9 @@ dependencies = [ [[package]] name = "object" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2766204889d09937d00bfbb7fec56bb2a199e2ade963cab19185d8a6104c7c" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "compiler_builtins", "crc32fast", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e1ea464dedb..0632d937c4c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1005,13 +1005,42 @@ pub struct Local { pub id: NodeId, pub pat: P<Pat>, pub ty: Option<P<Ty>>, - /// Initializer expression to set the value, if any. - pub init: Option<P<Expr>>, + pub kind: LocalKind, pub span: Span, pub attrs: AttrVec, pub tokens: Option<LazyTokenStream>, } +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum LocalKind { + /// Local declaration. + /// Example: `let x;` + Decl, + /// Local declaration with an initializer. + /// Example: `let x = y;` + Init(P<Expr>), + /// Local declaration with an initializer and an `else` clause. + /// Example: `let Some(x) = y else { return };` + InitElse(P<Expr>, P<Block>), +} + +impl LocalKind { + pub fn init(&self) -> Option<&Expr> { + match self { + Self::Decl => None, + Self::Init(i) | Self::InitElse(i, _) => Some(i), + } + } + + pub fn init_else_opt(&self) -> Option<(&Expr, Option<&Block>)> { + match self { + Self::Decl => None, + Self::Init(init) => Some((init, None)), + Self::InitElse(init, els) => Some((init, Some(els))), + } + } +} + /// An arm of a 'match'. /// /// E.g., `0..=10 => { println!("match!") }` as in diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index fb4db6005ac..368a23e3429 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -571,11 +571,20 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>( } pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { - let Local { id, pat, ty, init, span, attrs, tokens } = local.deref_mut(); + let Local { id, pat, ty, kind, span, attrs, tokens } = local.deref_mut(); vis.visit_id(id); vis.visit_pat(pat); visit_opt(ty, |ty| vis.visit_ty(ty)); - visit_opt(init, |init| vis.visit_expr(init)); + match kind { + LocalKind::Decl => {} + LocalKind::Init(init) => { + vis.visit_expr(init); + } + LocalKind::InitElse(init, els) => { + vis.visit_expr(init); + vis.visit_block(els); + } + } vis.visit_span(span); visit_thin_attrs(attrs, vis); visit_lazy_tts(tokens, vis); diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 90786520fe8..6ea3db6d303 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -23,3 +23,30 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { | ast::ExprKind::TryBlock(..) ) } + +/// If an expression ends with `}`, returns the innermost expression ending in the `}` +pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { + use ast::ExprKind::*; + + loop { + match &expr.kind { + AddrOf(_, _, e) + | Assign(_, e, _) + | AssignOp(_, _, e) + | Binary(_, _, e) + | Box(e) + | Break(_, Some(e)) + | Closure(.., e, _) + | Let(_, e, _) + | Range(_, Some(e), _) + | Ret(Some(e)) + | Unary(_, e) + | Yield(Some(e)) => { + expr = e; + } + Async(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..) + | TryBlock(..) | While(..) => break Some(expr), + _ => break None, + } + } +} diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index dd8927496e0..c30f711b397 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -242,7 +242,10 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) { } visitor.visit_pat(&local.pat); walk_list!(visitor, visit_ty, &local.ty); - walk_list!(visitor, visit_expr, &local.init); + if let Some((init, els)) = local.kind.init_else_opt() { + visitor.visit_expr(init); + walk_list!(visitor, visit_block, els); + } } pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, label: &'a Label) { diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs new file mode 100644 index 00000000000..ca804ec6758 --- /dev/null +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -0,0 +1,185 @@ +use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; +use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind}; +use rustc_hir as hir; +use rustc_session::parse::feature_err; +use rustc_span::symbol::Ident; +use rustc_span::{sym, DesugaringKind}; + +use smallvec::SmallVec; + +impl<'a, 'hir> LoweringContext<'a, 'hir> { + pub(super) fn lower_block( + &mut self, + b: &Block, + targeted_by_break: bool, + ) -> &'hir hir::Block<'hir> { + self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break)) + } + + pub(super) fn lower_block_noalloc( + &mut self, + b: &Block, + targeted_by_break: bool, + ) -> hir::Block<'hir> { + let (stmts, expr) = self.lower_stmts(&b.stmts); + let rules = self.lower_block_check_mode(&b.rules); + let hir_id = self.lower_node_id(b.id); + hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } + } + + fn lower_stmts( + &mut self, + mut ast_stmts: &[Stmt], + ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) { + let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new(); + let mut expr = None; + while let [s, tail @ ..] = ast_stmts { + match s.kind { + StmtKind::Local(ref local) => { + let hir_id = self.lower_node_id(s.id); + match &local.kind { + LocalKind::InitElse(init, els) => { + let (s, e) = self.lower_let_else(hir_id, local, init, els, tail); + stmts.push(s); + expr = Some(e); + // remaining statements are in let-else expression + break; + } + _ => { + let local = self.lower_local(local); + self.alias_attrs(hir_id, local.hir_id); + let kind = hir::StmtKind::Local(local); + let span = self.lower_span(s.span); + stmts.push(hir::Stmt { hir_id, kind, span }); + } + } + } + StmtKind::Item(ref it) => { + stmts.extend(self.lower_item_id(it).into_iter().enumerate().map( + |(i, item_id)| { + let hir_id = match i { + 0 => self.lower_node_id(s.id), + _ => self.next_id(), + }; + let kind = hir::StmtKind::Item(item_id); + let span = self.lower_span(s.span); + hir::Stmt { hir_id, kind, span } + }, + )); + } + StmtKind::Expr(ref e) => { + let e = self.lower_expr(e); + if tail.is_empty() { + expr = Some(e); + } else { + let hir_id = self.lower_node_id(s.id); + self.alias_attrs(hir_id, e.hir_id); + let kind = hir::StmtKind::Expr(e); + let span = self.lower_span(s.span); + stmts.push(hir::Stmt { hir_id, kind, span }); + } + } + StmtKind::Semi(ref e) => { + let e = self.lower_expr(e); + let hir_id = self.lower_node_id(s.id); + self.alias_attrs(hir_id, e.hir_id); + let kind = hir::StmtKind::Semi(e); + let span = self.lower_span(s.span); + stmts.push(hir::Stmt { hir_id, kind, span }); + } + StmtKind::Empty => {} + StmtKind::MacCall(..) => panic!("shouldn't exist here"), + } + ast_stmts = &ast_stmts[1..]; + } + (self.arena.alloc_from_iter(stmts), expr) + } + + fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> { + let ty = l + .ty + .as_ref() + .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding))); + let init = l.kind.init().map(|init| self.lower_expr(init)); + let hir_id = self.lower_node_id(l.id); + let pat = self.lower_pat(&l.pat); + let span = self.lower_span(l.span); + let source = hir::LocalSource::Normal; + self.lower_attrs(hir_id, &l.attrs); + self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source }) + } + + fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { + match *b { + BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock, + BlockCheckMode::Unsafe(u) => { + hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u)) + } + } + } + + fn lower_let_else( + &mut self, + stmt_hir_id: hir::HirId, + local: &Local, + init: &Expr, + els: &Block, + tail: &[Stmt], + ) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) { + let ty = local + .ty + .as_ref() + .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding))); + let span = self.lower_span(local.span); + let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None); + let init = Some(self.lower_expr(init)); + let val = Ident::with_dummy_span(sym::val); + let (pat, val_id) = + self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated); + let local_hir_id = self.lower_node_id(local.id); + self.lower_attrs(local_hir_id, &local.attrs); + // first statement which basically exists for the type annotation + let stmt = { + let local = self.arena.alloc(hir::Local { + hir_id: local_hir_id, + ty, + pat, + init, + span, + source: hir::LocalSource::Normal, + }); + let kind = hir::StmtKind::Local(local); + hir::Stmt { hir_id: stmt_hir_id, kind, span } + }; + let let_expr = { + let scrutinee = self.expr_ident(span, val, val_id); + let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span); + self.arena.alloc(self.expr(span, let_kind, AttrVec::new())) + }; + let then_expr = { + let (stmts, expr) = self.lower_stmts(tail); + let block = self.block_all(span, stmts, expr); + self.arena.alloc(self.expr_block(block, AttrVec::new())) + }; + let else_expr = { + let block = self.lower_block(els, false); + self.arena.alloc(self.expr_block(block, AttrVec::new())) + }; + self.alias_attrs(else_expr.hir_id, local_hir_id); + let if_expr = self.arena.alloc(hir::Expr { + hir_id: self.next_id(), + span, + kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)), + }); + if !self.sess.features_untracked().let_else { + feature_err( + &self.sess.parse_sess, + sym::let_else, + local.span, + "`let...else` statements are unstable", + ) + .emit(); + } + (stmt, if_expr) + } +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0133acfee10..deb7e742e5c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -64,7 +64,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use smallvec::{smallvec, SmallVec}; +use smallvec::SmallVec; use std::collections::BTreeMap; use std::mem; use tracing::{debug, trace}; @@ -77,6 +77,7 @@ macro_rules! arena_vec { } mod asm; +mod block; mod expr; mod item; mod pat; @@ -1793,24 +1794,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } - fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> { - let ty = l - .ty - .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding))); - let init = l.init.as_ref().map(|e| self.lower_expr(e)); - let hir_id = self.lower_node_id(l.id); - self.lower_attrs(hir_id, &l.attrs); - hir::Local { - hir_id, - ty, - pat: self.lower_pat(&l.pat), - init, - span: self.lower_span(l.span), - source: hir::LocalSource::Normal, - } - } - fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { // Skip the `...` (`CVarArgs`) trailing arguments from the AST, // as they are not explicit in HIR/Ty function signatures. @@ -2396,23 +2379,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx.reborrow())) } - fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> &'hir hir::Block<'hir> { - self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break)) - } - - fn lower_block_noalloc(&mut self, b: &Block, targeted_by_break: bool) -> hir::Block<'hir> { - let (stmts, expr) = match &*b.stmts { - [stmts @ .., Stmt { kind: StmtKind::Expr(e), .. }] => (stmts, Some(&*e)), - stmts => (stmts, None), - }; - let stmts = self.arena.alloc_from_iter(stmts.iter().flat_map(|stmt| self.lower_stmt(stmt))); - let expr = expr.map(|e| self.lower_expr(e)); - let rules = self.lower_block_check_mode(&b.rules); - let hir_id = self.lower_node_id(b.id); - - hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } - } - /// Lowers a block directly to an expression, presuming that it /// has no attributes and is not targeted by a `break`. fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> { @@ -2427,65 +2393,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) } - fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt<'hir>; 1]> { - let (hir_id, kind) = match s.kind { - StmtKind::Local(ref l) => { - let l = self.lower_local(l); - let hir_id = self.lower_node_id(s.id); - self.alias_attrs(hir_id, l.hir_id); - return smallvec![hir::Stmt { - hir_id, - kind: hir::StmtKind::Local(self.arena.alloc(l)), - span: self.lower_span(s.span), - }]; - } - StmtKind::Item(ref it) => { - // Can only use the ID once. - let mut id = Some(s.id); - return self - .lower_item_id(it) - .into_iter() - .map(|item_id| { - let hir_id = id - .take() - .map(|id| self.lower_node_id(id)) - .unwrap_or_else(|| self.next_id()); - - hir::Stmt { - hir_id, - kind: hir::StmtKind::Item(item_id), - span: self.lower_span(s.span), - } - }) - .collect(); - } - StmtKind::Expr(ref e) => { - let e = self.lower_expr(e); - let hir_id = self.lower_node_id(s.id); - self.alias_attrs(hir_id, e.hir_id); - (hir_id, hir::StmtKind::Expr(e)) - } - StmtKind::Semi(ref e) => { - let e = self.lower_expr(e); - let hir_id = self.lower_node_id(s.id); - self.alias_attrs(hir_id, e.hir_id); - (hir_id, hir::StmtKind::Semi(e)) - } - StmtKind::Empty => return smallvec![], - StmtKind::MacCall(..) => panic!("shouldn't exist here"), - }; - smallvec![hir::Stmt { hir_id, kind, span: self.lower_span(s.span) }] - } - - fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { - match *b { - BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock, - BlockCheckMode::Unsafe(u) => { - hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u)) - } - } - } - fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource { match u { CompilerGenerated => hir::UnsafeSource::CompilerGenerated, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 949e7a1fbb8..3cf04be160c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1518,13 +1518,19 @@ impl<'a> State<'a> { self.ibox(INDENT_UNIT); self.print_local_decl(loc); self.end(); - if let Some(ref init) = loc.init { + if let Some((init, els)) = loc.kind.init_else_opt() { self.nbsp(); self.word_space("="); self.print_expr(init); + if let Some(els) = els { + self.cbox(INDENT_UNIT); + self.ibox(INDENT_UNIT); + self.s.word(" else "); + self.print_block(els); + } } self.s.word(";"); - self.end(); + self.end(); // `let` ibox } ast::StmtKind::Item(ref item) => self.print_item(item), ast::StmtKind::Expr(ref expr) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index cc6dac52d76..14506f296bf 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -3,7 +3,7 @@ use crate::deriving::generic::*; use crate::deriving::path_std; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, MetaItem}; +use rustc_ast::{self as ast, Expr, LocalKind, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; @@ -135,8 +135,8 @@ fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> as let local = P(ast::Local { pat: cx.pat_wild(sp), ty: None, - init: Some(expr), id: ast::DUMMY_NODE_ID, + kind: LocalKind::Init(expr), span: sp, attrs: ast::AttrVec::new(), tokens: None, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1689fdd4f2e..e0d312727a5 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -616,6 +616,10 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { @@ -755,6 +759,10 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 930b4dc4d41..1446624b881 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -36,6 +36,6 @@ rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } [dependencies.object] -version = "0.26.1" +version = "0.26.2" default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 4f5d8d7ea48..293ef4caac4 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -222,6 +222,10 @@ cfg_if! { let msg = "file locks not supported on this platform"; Err(io::Error::new(io::ErrorKind::Other, msg)) } + + pub fn error_unsupported(_err: &io::Error) -> bool { + true + } } } } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index c2e62328cb1..45d91c2047d 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -480,6 +480,7 @@ E0781: include_str!("./error_codes/E0781.md"), E0782: include_str!("./error_codes/E0782.md"), E0783: include_str!("./error_codes/E0783.md"), E0784: include_str!("./error_codes/E0784.md"), +E0785: include_str!("./error_codes/E0785.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0785.md b/compiler/rustc_error_codes/src/error_codes/E0785.md new file mode 100644 index 00000000000..373320539ef --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0785.md @@ -0,0 +1,30 @@ +An inherent `impl` was written on a dyn auto trait. + +Erroneous code example: + +```compile_fail,E0785 +#![feature(auto_traits)] + +auto trait AutoTrait {} + +impl dyn AutoTrait {} +``` + +Dyn objects allow any number of auto traits, plus at most one non-auto trait. +The non-auto trait becomes the "principal trait". + +When checking if an impl on a dyn trait is coherent, the principal trait is +normally the only one considered. Since the erroneous code has no principal +trait, it cannot be implemented at all. + +Working example: + +``` +#![feature(auto_traits)] + +trait PrincipalTrait {} + +auto trait AutoTrait {} + +impl dyn PrincipalTrait + AutoTrait + Send {} +``` diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 824df2757ea..1d83ecbfd40 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -2,7 +2,7 @@ use crate::base::ExtCtxt; use rustc_ast::attr; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, PatKind, UnOp}; +use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -153,8 +153,8 @@ impl<'a> ExtCtxt<'a> { let local = P(ast::Local { pat, ty: None, - init: Some(ex), id: ast::DUMMY_NODE_ID, + kind: LocalKind::Init(ex), span: sp, attrs: AttrVec::new(), tokens: None, @@ -167,8 +167,8 @@ impl<'a> ExtCtxt<'a> { let local = P(ast::Local { pat: self.pat_wild(span), ty: Some(ty), - init: None, id: ast::DUMMY_NODE_ID, + kind: LocalKind::Decl, span, attrs: AttrVec::new(), tokens: None, diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1ff2c75966a..a3807a2bb9f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -676,6 +676,9 @@ declare_features! ( /// Allows additional const parameter types, such as `&'static str` or user defined types (incomplete, adt_const_params, "1.56.0", Some(44580), None), + /// Allows `let...else` statements. + (active, let_else, "1.56.0", Some(87335), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 299dcf5f17a..d54933841fd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -781,6 +781,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } } + ObligationCauseCode::LetElse => { + err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); + err.help("...or use `match` instead of `let...else`"); + } _ => (), } } @@ -2592,6 +2596,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { } IfExpression { .. } => Error0308("`if` and `else` have incompatible types"), IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"), + LetElse => Error0308("`else` clause of `let...else` does not diverge"), MainFunctionType => Error0580("`main` function has wrong type"), StartFunctionType => Error0308("`#[start]` function has wrong type"), IntrinsicType => Error0308("intrinsic has wrong type"), diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index be137884b4b..f04ac8dd942 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,7 +1,7 @@ use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_ast::util::parser; +use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; use rustc_ast_pretty::pprust; use rustc_errors::{pluralize, Applicability}; @@ -382,6 +382,7 @@ enum UnusedDelimsCtx { FunctionArg, MethodArg, AssignedValue, + AssignedValueLetElse, IfCond, WhileCond, ForIterExpr, @@ -398,7 +399,9 @@ impl From<UnusedDelimsCtx> for &'static str { match ctx { UnusedDelimsCtx::FunctionArg => "function argument", UnusedDelimsCtx::MethodArg => "method argument", - UnusedDelimsCtx::AssignedValue => "assigned value", + UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => { + "assigned value" + } UnusedDelimsCtx::IfCond => "`if` condition", UnusedDelimsCtx::WhileCond => "`while` condition", UnusedDelimsCtx::ForIterExpr => "`for` iterator expression", @@ -441,14 +444,26 @@ trait UnusedDelimLint { right_pos: Option<BytePos>, ); - fn is_expr_delims_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool { + fn is_expr_delims_necessary( + inner: &ast::Expr, + followed_by_block: bool, + followed_by_else: bool, + ) -> bool { + if followed_by_else { + match inner.kind { + ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true, + _ if classify::expr_trailing_brace(inner).is_some() => return true, + _ => {} + } + } + // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }` let lhs_needs_parens = { let mut innermost = inner; loop { if let ExprKind::Binary(_, lhs, _rhs) = &innermost.kind { innermost = lhs; - if !rustc_ast::util::classify::expr_requires_semi_to_be_stmt(innermost) { + if !classify::expr_requires_semi_to_be_stmt(innermost) { break true; } } else { @@ -618,15 +633,12 @@ trait UnusedDelimLint { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { match s.kind { StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { - if let Some(ref value) = local.init { - self.check_unused_delims_expr( - cx, - &value, - UnusedDelimsCtx::AssignedValue, - false, - None, - None, - ); + if let Some((init, els)) = local.kind.init_else_opt() { + let ctx = match els { + None => UnusedDelimsCtx::AssignedValue, + Some(_) => UnusedDelimsCtx::AssignedValueLetElse, + }; + self.check_unused_delims_expr(cx, init, ctx, false, None, None); } } StmtKind::Expr(ref expr) => { @@ -702,7 +714,8 @@ impl UnusedDelimLint for UnusedParens { ) { match value.kind { ast::ExprKind::Paren(ref inner) => { - if !Self::is_expr_delims_necessary(inner, followed_by_block) + let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse; + if !Self::is_expr_delims_necessary(inner, followed_by_block, followed_by_else) && value.attrs.is_empty() && !value.span.from_expansion() && (ctx != UnusedDelimsCtx::LetScrutineeExpr @@ -941,7 +954,7 @@ impl UnusedDelimLint for UnusedBraces { // FIXME(const_generics): handle paths when #67075 is fixed. if let [stmt] = inner.stmts.as_slice() { if let ast::StmtKind::Expr(ref expr) = stmt.kind { - if !Self::is_expr_delims_necessary(expr, followed_by_block) + if !Self::is_expr_delims_necessary(expr, followed_by_block, false) && (ctx != UnusedDelimsCtx::AnonConst || matches!(expr.kind, ast::ExprKind::Lit(_))) && !cx.sess().source_map().is_multiline(value.span) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 07407540975..dada94edc95 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -120,7 +120,18 @@ rustc_queries! { /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { - desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } + desc { |tcx| + "{action} `{path}`", + action = { + use rustc_hir::def::DefKind; + match tcx.def_kind(key) { + DefKind::TyAlias => "expanding type alias", + DefKind::TraitAlias => "expanding trait alias", + _ => "computing type of", + } + }, + path = tcx.def_path_str(key), + } cache_on_disk_if { key.is_local() } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 676cb7fe41d..74edb17fe32 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -305,6 +305,9 @@ pub enum ObligationCauseCode<'tcx> { /// Intrinsic has wrong type IntrinsicType, + /// A let else block does not diverge + LetElse, + /// Method receiver MethodReceiver, diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs index e9ab62e1664..12fceeff088 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs @@ -82,15 +82,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .find(|ur_vid| self.eval_equal(vid, **ur_vid)) .and_then(|ur_vid| self.definitions[*ur_vid].external_name) .unwrap_or(infcx.tcx.lifetimes.re_root_empty), - ty::ReLateBound(..) => region, - ty::ReStatic => region, - _ => { - infcx.tcx.sess.delay_span_bug( - span, - &format!("unexpected concrete region in borrowck: {:?}", region), - ); - region - } + _ => region, }); debug!(?universal_concrete_type, ?universal_substs); diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 50cbe0f71f5..b34c1e07be7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; use rustc_session::Session; -use rustc_span::Span; +use rustc_span::{DesugaringKind, ExpnKind, Span}; use std::slice; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { @@ -118,31 +118,6 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { check_for_bindings_named_same_as_variants(self, pat); } - fn let_source(&mut self, pat: &'tcx hir::Pat<'tcx>, _expr: &hir::Expr<'_>) -> LetSource { - let hir = self.tcx.hir(); - let parent = hir.get_parent_node(pat.hir_id); - let parent_parent = hir.get_parent_node(parent); - let parent_parent_node = hir.get(parent_parent); - - let parent_parent_parent = hir.get_parent_node(parent_parent); - let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent); - let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent); - - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), - .. - }) = parent_parent_parent_parent_node - { - LetSource::WhileLet - } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) = - parent_parent_node - { - LetSource::IfLet - } else { - LetSource::GenericLet - } - } - fn lower_pattern<'p>( &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, @@ -172,10 +147,9 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) { self.check_patterns(pat); - let ls = self.let_source(pat, expr); let mut cx = self.new_cx(expr.hir_id); let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_let_reachability(&mut cx, ls, pat.hir_id, &tpat, span); + check_let_reachability(&mut cx, pat.hir_id, &tpat, span); } fn check_match( @@ -192,13 +166,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { self.check_patterns(pat); let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_let_reachability( - &mut cx, - LetSource::IfLetGuard, - pat.hir_id, - &tpat, - tpat.span, - ); + check_let_reachability(&mut cx, pat.hir_id, &tpat, tpat.span); } } @@ -397,7 +365,7 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option< }); } -fn irrefutable_let_pattern(id: HirId, ls: LetSource, span: Span, tcx: TyCtxt<'_>) { +fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) { macro_rules! emit_diag { ( $lint:expr, @@ -412,7 +380,12 @@ fn irrefutable_let_pattern(id: HirId, ls: LetSource, span: Span, tcx: TyCtxt<'_> }}; } - tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match ls { + let source = let_source(tcx, id); + let span = match source { + LetSource::LetElse(span) => span, + _ => span, + }; + tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source { LetSource::GenericLet => { emit_diag!(lint, "`let`", "`let` is useless", "removing `let`"); } @@ -432,6 +405,14 @@ fn irrefutable_let_pattern(id: HirId, ls: LetSource, span: Span, tcx: TyCtxt<'_> "removing the guard and adding a `let` inside the match arm" ); } + LetSource::LetElse(..) => { + emit_diag!( + lint, + "`let...else`", + "`else` clause is useless", + "removing the `else` clause" + ); + } LetSource::WhileLet => { emit_diag!( lint, @@ -445,7 +426,6 @@ fn irrefutable_let_pattern(id: HirId, ls: LetSource, span: Span, tcx: TyCtxt<'_> fn check_let_reachability<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, - ls: LetSource, pat_id: HirId, pat: &'p super::Pat<'tcx>, span: Span, @@ -454,13 +434,13 @@ fn check_let_reachability<'p, 'tcx>( let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); report_arm_reachability(&cx, &report, |arm_index, arm_span, arm_hir_id, _| { - match ls { + match let_source(cx.tcx, pat_id) { LetSource::IfLet | LetSource::WhileLet => { match arm_index { // The arm with the user-specified pattern. 0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None), // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(pat_id, ls, arm_span, cx.tcx), + 1 => irrefutable_let_pattern(cx.tcx, pat_id, arm_span), _ => bug!(), } } @@ -473,7 +453,7 @@ fn check_let_reachability<'p, 'tcx>( if report.non_exhaustiveness_witnesses.is_empty() { // The match is exhaustive, i.e. the `if let` pattern is irrefutable. - irrefutable_let_pattern(pat_id, ls, span, cx.tcx); + irrefutable_let_pattern(cx.tcx, pat_id, span); } } @@ -787,5 +767,46 @@ pub enum LetSource { GenericLet, IfLet, IfLetGuard, + LetElse(Span), WhileLet, } + +fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource { + let hir = tcx.hir(); + let parent = hir.get_parent_node(pat_id); + match hir.get(parent) { + hir::Node::Arm(hir::Arm { + guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)), + .. + }) if hir_id == pat_id => { + return LetSource::IfLetGuard; + } + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => { + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind { + return LetSource::LetElse(expn_data.call_site); + } + } + _ => {} + } + let parent_parent = hir.get_parent_node(parent); + let parent_parent_node = hir.get(parent_parent); + + let parent_parent_parent = hir.get_parent_node(parent_parent); + let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent); + let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent); + + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), + .. + }) = parent_parent_parent_parent_node + { + LetSource::WhileLet + } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) = + parent_parent_node + { + LetSource::IfLet + } else { + LetSource::GenericLet + } +} diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 85515bd2a63..068bd36af55 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -11,8 +11,9 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::util::classify; -use rustc_ast::AstLike; -use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}; +use rustc_ast::{ + AstLike, AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle, +}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, PResult}; @@ -292,8 +293,65 @@ impl<'a> Parser<'a> { return Err(err); } }; + let kind = match init { + None => LocalKind::Decl, + Some(init) => { + if self.eat_keyword(kw::Else) { + let els = self.parse_block()?; + self.check_let_else_init_bool_expr(&init); + self.check_let_else_init_trailing_brace(&init); + LocalKind::InitElse(init, els) + } else { + LocalKind::Init(init) + } + } + }; let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span }; - Ok(P(ast::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) + Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) + } + + fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { + if let ast::ExprKind::Binary(op, ..) = init.kind { + if op.node.lazy() { + let suggs = vec![ + (init.span.shrink_to_lo(), "(".to_string()), + (init.span.shrink_to_hi(), ")".to_string()), + ]; + self.struct_span_err( + init.span, + &format!( + "a `{}` expression cannot be directly assigned in `let...else`", + op.node.to_string() + ), + ) + .multipart_suggestion( + "wrap the expression in parenthesis", + suggs, + Applicability::MachineApplicable, + ) + .emit(); + } + } + } + + fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) { + if let Some(trailing) = classify::expr_trailing_brace(init) { + let err_span = trailing.span.with_lo(trailing.span.hi() - BytePos(1)); + let suggs = vec![ + (trailing.span.shrink_to_lo(), "(".to_string()), + (trailing.span.shrink_to_hi(), ")".to_string()), + ]; + self.struct_span_err( + err_span, + "right curly brace `}` before `else` in a `let...else` statement not allowed", + ) + .multipart_suggestion( + "try wrapping the expression in parenthesis", + suggs, + Applicability::MachineApplicable, + ) + .emit(); + } } /// Parses the RHS of a local variable declaration (e.g., `= 14;`). @@ -495,13 +553,13 @@ impl<'a> Parser<'a> { StmtKind::Expr(_) | StmtKind::MacCall(_) => {} StmtKind::Local(ref mut local) if let Err(e) = self.expect_semi() => { // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover. - match &mut local.init { - Some(ref mut expr) => { - self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; - // We found `foo<bar, baz>`, have we fully recovered? - self.expect_semi()?; - } - None => return Err(e), + match &mut local.kind { + LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => { + self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; + // We found `foo<bar, baz>`, have we fully recovered? + self.expect_semi()?; + } + LocalKind::Decl => return Err(e), } eat_semi = false; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d3dac35d2c9..fd438bdc900 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1331,6 +1331,36 @@ impl CheckAttrVisitor<'tcx> { Target::Field | Target::Arm | Target::MacroDef => { self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle"); } + // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error + // The error should specify that the item that is wrong is specifically a *foreign* fn/static + // otherwise the error seems odd + Target::ForeignFn | Target::ForeignStatic => { + let foreign_item_kind = match target { + Target::ForeignFn => "function", + Target::ForeignStatic => "static", + _ => unreachable!(), + }; + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build(&format!( + "`#[no_mangle]` has no effect on a foreign {}", + foreign_item_kind + )) + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, format!("foreign {}", foreign_item_kind)) + .note("symbol names in extern blocks are not mangled") + .span_suggestion( + attr.span, + "remove this attribute", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + }); + } _ => { // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some // crates used this, so only emit a warning. diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index d85f1c04524..c973eae6b06 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -20,6 +20,12 @@ pub trait Key { /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? fn default_span(&self, tcx: TyCtxt<'_>) -> Span; + + /// If the key is a [`DefId`] or `DefId`--equivalent, return that `DefId`. + /// Otherwise, return `None`. + fn key_as_def_id(&self) -> Option<DefId> { + None + } } impl Key for () { @@ -95,6 +101,9 @@ impl Key for LocalDefId { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option<DefId> { + Some(self.to_def_id()) + } } impl Key for DefId { @@ -105,6 +114,10 @@ impl Key for DefId { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) } + #[inline(always)] + fn key_as_def_id(&self) -> Option<DefId> { + Some(*self) + } } impl Key for ty::WithOptConstParam<LocalDefId> { @@ -165,6 +178,10 @@ impl Key for (DefId, Option<Ident>) { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) } + #[inline(always)] + fn key_as_def_id(&self) -> Option<DefId> { + Some(self.0) + } } impl Key for (DefId, LocalDefId, Ident) { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 5022bf26532..bb0e6511159 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -51,6 +51,8 @@ pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; +mod util; + rustc_query_append! { [define_queries!][<'tcx>] } impl<'tcx> Queries<'tcx> { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 5774d021373..90a6ba474b4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -337,6 +337,13 @@ macro_rules! define_queries { } else { Some(key.default_span(*tcx)) }; + let def_id = key.key_as_def_id(); + let def_kind = def_id + .and_then(|def_id| def_id.as_local()) + // Use `tcx.hir().opt_def_kind()` to reduce the chance of + // accidentally triggering an infinite query loop. + .and_then(|def_id| tcx.hir().opt_def_kind(def_id)) + .map(|def_kind| $crate::util::def_kind_to_simple_def_kind(def_kind)); let hash = || { let mut hcx = tcx.create_stable_hashing_context(); let mut hasher = StableHasher::new(); @@ -345,7 +352,7 @@ macro_rules! define_queries { hasher.finish::<u64>() }; - QueryStackFrame::new(name, description, span, hash) + QueryStackFrame::new(name, description, span, def_kind, hash) })* } diff --git a/compiler/rustc_query_impl/src/util.rs b/compiler/rustc_query_impl/src/util.rs new file mode 100644 index 00000000000..517c107b5d9 --- /dev/null +++ b/compiler/rustc_query_impl/src/util.rs @@ -0,0 +1,18 @@ +use rustc_hir::def::DefKind; +use rustc_query_system::query::SimpleDefKind; + +/// Convert a [`DefKind`] to a [`SimpleDefKind`]. +/// +/// *See [`SimpleDefKind`]'s docs for more information.* +pub(crate) fn def_kind_to_simple_def_kind(def_kind: DefKind) -> SimpleDefKind { + match def_kind { + DefKind::Struct => SimpleDefKind::Struct, + DefKind::Enum => SimpleDefKind::Enum, + DefKind::Union => SimpleDefKind::Union, + DefKind::Trait => SimpleDefKind::Trait, + DefKind::TyAlias => SimpleDefKind::TyAlias, + DefKind::TraitAlias => SimpleDefKind::TraitAlias, + + _ => SimpleDefKind::Other, + } +} diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index a967670280f..63a8f062475 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,6 +1,6 @@ use crate::dep_graph::DepContext; use crate::query::plumbing::CycleError; -use crate::query::{QueryContext, QueryStackFrame}; +use crate::query::{QueryContext, QueryStackFrame, SimpleDefKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level}; @@ -591,10 +591,33 @@ pub(crate) fn report_cycle<'a>( err.span_note(span, &format!("...which requires {}...", query.description)); } - err.note(&format!( - "...which again requires {}, completing the cycle", - stack[0].query.description - )); + if stack.len() == 1 { + err.note(&format!("...which immediately requires {} again", stack[0].query.description)); + } else { + err.note(&format!( + "...which again requires {}, completing the cycle", + stack[0].query.description + )); + } + + if stack.iter().all(|entry| { + entry.query.def_kind.map_or(false, |def_kind| { + matches!(def_kind, SimpleDefKind::TyAlias | SimpleDefKind::TraitAlias) + }) + }) { + if stack.iter().all(|entry| { + entry + .query + .def_kind + .map_or(false, |def_kind| matches!(def_kind, SimpleDefKind::TyAlias)) + }) { + err.note("type aliases cannot be recursive"); + err.help("consider using a struct, enum, or union instead to break the cycle"); + err.help("see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information"); + } else { + err.note("trait aliases cannot be recursive"); + } + } if let Some((span, query)) = usage { err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description)); diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 7288aaef8f2..dffe7f3689f 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -29,24 +29,53 @@ pub struct QueryStackFrame { pub name: &'static str, pub description: String, span: Option<Span>, + /// The `DefKind` this query frame is associated with, if applicable. + /// + /// We can't use `rustc_hir::def::DefKind` because `rustc_hir` is not + /// available in `rustc_query_system`. Instead, we have a simplified + /// custom version of it, called [`SimpleDefKind`]. + def_kind: Option<SimpleDefKind>, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. #[cfg(parallel_compiler)] hash: u64, } +/// A simplified version of `rustc_hir::def::DefKind`. +/// +/// It was added to help improve cycle errors caused by recursive type aliases. +/// As of August 2021, `rustc_query_system` cannot depend on `rustc_hir` +/// because it would create a dependency cycle. So, instead, a simplified +/// version of `DefKind` was added to `rustc_query_system`. +/// +/// `DefKind`s are converted to `SimpleDefKind`s in `rustc_query_impl`. +#[derive(Debug, Copy, Clone)] +pub enum SimpleDefKind { + Struct, + Enum, + Union, + Trait, + TyAlias, + TraitAlias, + + // FIXME: add more from `rustc_hir::def::DefKind` and then remove `Other` + Other, +} + impl QueryStackFrame { #[inline] pub fn new( name: &'static str, description: String, span: Option<Span>, + def_kind: Option<SimpleDefKind>, _hash: impl FnOnce() -> u64, ) -> Self { Self { name, description, span, + def_kind, #[cfg(parallel_compiler)] hash: _hash(), } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0b552aa07f5..5c7b4b02822 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -454,7 +454,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { _ => Some(( local.pat.span, local.ty.as_ref().map(|ty| ty.span), - local.init.as_ref().map(|init| init.span), + local.kind.init().map(|init| init.span), )), }; let original = replace(&mut self.diagnostic_metadata.current_let_binding, local_spans); @@ -1426,7 +1426,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { walk_list!(self, visit_ty, &local.ty); // Resolve the initializer. - walk_list!(self, visit_expr, &local.init); + if let Some((init, els)) = local.kind.init_else_opt() { + self.visit_expr(init); + + // Resolve the `else` block + if let Some(els) = els { + self.visit_block(els); + } + } // Resolve the pattern. self.resolve_pattern_top(&local.pat, PatternSource::Let); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e44a2e96598..c22093c5a42 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1097,6 +1097,7 @@ pub enum DesugaringKind { Async, Await, ForLoop(ForLoopLoc), + LetElse, } /// A location in the desugaring of a `for` loop @@ -1117,6 +1118,7 @@ impl DesugaringKind { DesugaringKind::TryBlock => "`try` block", DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop(_) => "`for` loop", + DesugaringKind::LetElse => "`let...else`", } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 19c02ba45c4..24023163cc3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -479,6 +479,7 @@ symbols! { core_panic_macro, cosf32, cosf64, + cr, crate_id, crate_in_paths, crate_local, @@ -744,6 +745,7 @@ symbols! { le, len, let_chains, + let_else, lhs, lib, libc, @@ -1417,6 +1419,7 @@ symbols! { wreg, write_bytes, x87_reg, + xer, xmm_reg, ymm_reg, zmm_reg, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index fb23e5c85a1..99699c50df5 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -355,7 +355,7 @@ impl InlineAsmReg { Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), - Self::PowerPC(_) => cb(self), + Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::Mips(_) => cb(self), Self::S390x(_) => cb(self), diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index 42fc25c4ff5..51a4303689e 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -7,6 +7,8 @@ def_reg_class! { reg, reg_nonzero, freg, + cr, + xer, } } @@ -44,6 +46,7 @@ impl PowerPCInlineAsmRegClass { } } Self::freg => types! { _: F32, F64; }, + Self::cr | Self::xer => &[], } } } @@ -108,6 +111,16 @@ def_regs! { f29: freg = ["f29", "fr29"], f30: freg = ["f30", "fr30"], f31: freg = ["f31", "fr31"], + cr: cr = ["cr"], + cr0: cr = ["cr0"], + cr1: cr = ["cr1"], + cr2: cr = ["cr2"], + cr3: cr = ["cr3"], + cr4: cr = ["cr4"], + cr5: cr = ["cr5"], + cr6: cr = ["cr6"], + cr7: cr = ["cr7"], + xer: xer = ["xer"], #error = ["r1", "1", "sp"] => "the stack pointer cannot be used as an operand for inline asm", #error = ["r2", "2"] => @@ -136,17 +149,55 @@ impl PowerPCInlineAsmReg { _arch: InlineAsmArch, _modifier: Option<char>, ) -> fmt::Result { + macro_rules! do_emit { + ( + $($(($reg:ident, $value:literal)),*;)* + ) => { + out.write_str(match self { + $($(Self::$reg => $value,)*)* + }) + }; + } // Strip off the leading prefix. - if self as u32 <= Self::r28 as u32 { - let index = self as u32 - Self::r28 as u32; - write!(out, "{}", index) - } else if self as u32 >= Self::f0 as u32 && self as u32 <= Self::f31 as u32 { - let index = self as u32 - Self::f31 as u32; - write!(out, "{}", index) - } else { - unreachable!() + do_emit! { + (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7"); + (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15"); + (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23"); + (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"); + (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7"); + (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15"); + (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23"); + (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31"); + (cr, "cr"); + (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7"); + (xer, "xer"); } } - pub fn overlapping_regs(self, mut _cb: impl FnMut(PowerPCInlineAsmReg)) {} + pub fn overlapping_regs(self, mut cb: impl FnMut(PowerPCInlineAsmReg)) { + macro_rules! reg_conflicts { + ( + $( + $full:ident : $($field:ident)* + ),*; + ) => { + match self { + $( + Self::$full => { + cb(Self::$full); + $(cb(Self::$field);)* + } + $(Self::$field)|* => { + cb(Self::$full); + cb(self); + } + )* + r => cb(r), + } + }; + } + reg_conflicts! { + cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7; + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 40841a6e32d..db3432b0142 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1928,7 +1928,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::OpaqueType | ObligationCauseCode::MiscObligation | ObligationCauseCode::WellFormed(..) - | ObligationCauseCode::MatchImpl(..) => {} + | ObligationCauseCode::MatchImpl(..) + | ObligationCauseCode::ReturnType + | ObligationCauseCode::ReturnValue(_) + | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::LetElse => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } @@ -2338,9 +2342,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate )); } - ObligationCauseCode::ReturnType - | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) => (), ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); if tcx.sess.opts.unstable_features.is_nightly_build() { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 51c646e500c..10f5b000aca 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -849,7 +849,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce(self, &self.misc(sp), then_expr, then_ty); if let Some(else_expr) = opt_else_expr { - let else_ty = self.check_expr_with_expectation(else_expr, expected); + let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) { + // todo introduce `check_expr_with_expectation(.., Expectation::LetElse)` + // for errors that point to the offending expression rather than the entire block. + // We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no + // way to detect that the expected type originated from let-else and provide + // a customized error. + let else_ty = self.check_expr(else_expr); + let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse); + + if let Some(mut err) = + self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + { + err.emit(); + self.tcx.ty_error() + } else { + else_ty + } + } else { + self.check_expr_with_expectation(else_expr, expected) + }; let else_diverges = self.diverges.get(); let opt_suggest_box_span = diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 51698437a30..c7be9e21235 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -60,6 +60,17 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => { self.check_def_id(item, data.principal_def_id().unwrap()); } + ty::Dynamic(..) => { + struct_span_err!( + self.tcx.sess, + ty.span, + E0785, + "cannot define inherent `impl` for a dyn auto trait" + ) + .span_label(ty.span, "impl requires at least one non-auto trait") + .note("define and implement a new trait or type instead") + .emit(); + } ty::Bool => { self.check_primitive_impl( item.def_id, diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 4b649e43371..70a838a35f9 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -233,9 +233,7 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> { } if self.is_empty() { - // Ideally we'd call `BTreeMap::new` here, but that has the `K: - // Ord` constraint, which this method lacks. - BTreeMap { root: None, length: 0 } + BTreeMap::new() } else { clone_subtree(self.root.as_ref().unwrap().reborrow()) // unwrap succeeds because not empty } @@ -499,10 +497,7 @@ impl<K, V> BTreeMap<K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] - pub const fn new() -> BTreeMap<K, V> - where - K: Ord, - { + pub const fn new() -> BTreeMap<K, V> { BTreeMap { root: None, length: 0 } } @@ -522,7 +517,7 @@ impl<K, V> BTreeMap<K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - *self = BTreeMap { root: None, length: 0 }; + *self = BTreeMap::new(); } /// Returns a reference to the value corresponding to the key. @@ -1957,7 +1952,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<K: Ord, V> Default for BTreeMap<K, V> { +impl<K, V> Default for BTreeMap<K, V> { /// Creates an empty `BTreeMap`. fn default() -> BTreeMap<K, V> { BTreeMap::new() diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 17e53848343..a99d6c49ab7 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1745,7 +1745,7 @@ fn test_send() { } } -#[allow(dead_code)] +#[test] fn test_ord_absence() { fn map<K>(mut map: BTreeMap<K, ()>) { map.is_empty(); @@ -1784,6 +1784,12 @@ fn test_ord_absence() { fn map_clone<K: Clone>(mut map: BTreeMap<K, ()>) { map.clone_from(&map.clone()); } + + #[derive(Debug, Clone)] + struct NonOrd; + map(BTreeMap::<NonOrd, _>::new()); + map_debug(BTreeMap::<NonOrd, _>::new()); + map_clone(BTreeMap::<NonOrd, _>::default()); } #[test] diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 0c268ad32b2..ff0db22e0cc 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -246,10 +246,7 @@ impl<T> BTreeSet<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] - pub const fn new() -> BTreeSet<T> - where - T: Ord, - { + pub const fn new() -> BTreeSet<T> { BTreeSet { map: BTreeMap::new() } } @@ -1192,7 +1189,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Ord> Default for BTreeSet<T> { +impl<T> Default for BTreeSet<T> { /// Creates an empty `BTreeSet`. fn default() -> BTreeSet<T> { BTreeSet::new() diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 5d590a26281..0a87ae12d61 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -607,7 +607,7 @@ fn test_send() { } } -#[allow(dead_code)] +#[test] fn test_ord_absence() { fn set<K>(mut set: BTreeSet<K>) { set.is_empty(); @@ -626,6 +626,12 @@ fn test_ord_absence() { fn set_clone<K: Clone>(mut set: BTreeSet<K>) { set.clone_from(&set.clone()); } + + #[derive(Debug, Clone)] + struct NonOrd; + set(BTreeSet::<NonOrd>::new()); + set_debug(BTreeSet::<NonOrd>::new()); + set_clone(BTreeSet::<NonOrd>::default()); } #[test] diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs index da58ae92e11..f448b3eb7c3 100644 --- a/library/alloc/tests/const_fns.rs +++ b/library/alloc/tests/const_fns.rs @@ -1,29 +1,5 @@ // Test const functions in the library -use core::cmp::Ordering; - -// FIXME remove this struct once we put `K: ?const Ord` on BTreeMap::new. -#[derive(PartialEq, Eq, PartialOrd)] -pub struct MyType; - -impl const Ord for MyType { - fn cmp(&self, _: &Self) -> Ordering { - Ordering::Equal - } - - fn max(self, _: Self) -> Self { - Self - } - - fn min(self, _: Self) -> Self { - Self - } - - fn clamp(self, _: Self, _: Self) -> Self { - Self - } -} - pub const MY_VEC: Vec<usize> = Vec::new(); pub const MY_VEC2: Vec<usize> = Default::default(); @@ -32,13 +8,13 @@ pub const MY_STRING2: String = Default::default(); use std::collections::{BTreeMap, BTreeSet}; -pub const MY_BTREEMAP: BTreeMap<MyType, MyType> = BTreeMap::new(); -pub const MAP: &'static BTreeMap<MyType, MyType> = &MY_BTREEMAP; +pub const MY_BTREEMAP: BTreeMap<usize, usize> = BTreeMap::new(); +pub const MAP: &'static BTreeMap<usize, usize> = &MY_BTREEMAP; pub const MAP_LEN: usize = MAP.len(); pub const MAP_IS_EMPTY: bool = MAP.is_empty(); -pub const MY_BTREESET: BTreeSet<MyType> = BTreeSet::new(); -pub const SET: &'static BTreeSet<MyType> = &MY_BTREESET; +pub const MY_BTREESET: BTreeSet<usize> = BTreeSet::new(); +pub const SET: &'static BTreeSet<usize> = &MY_BTREESET; pub const SET_LEN: usize = SET.len(); pub const SET_IS_EMPTY: bool = SET.is_empty(); diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index d8bbd424cf2..bd21872e1ad 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -4,7 +4,7 @@ use super::Peekable; /// /// This `struct` is created by [`Iterator::intersperse`]. See its documentation /// for more information. -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] #[derive(Debug, Clone)] pub struct Intersperse<I: Iterator> where @@ -24,7 +24,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] impl<I> Iterator for Intersperse<I> where I: Iterator, @@ -61,7 +61,7 @@ where /// /// This `struct` is created by [`Iterator::intersperse_with`]. See its /// documentation for more information. -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] pub struct IntersperseWith<I, G> where I: Iterator, @@ -71,7 +71,7 @@ where needs_sep: bool, } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] impl<I, G> crate::fmt::Debug for IntersperseWith<I, G> where I: Iterator + crate::fmt::Debug, @@ -87,7 +87,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] impl<I, G> crate::clone::Clone for IntersperseWith<I, G> where I: Iterator + crate::clone::Clone, @@ -113,7 +113,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] impl<I, G> Iterator for IntersperseWith<I, G> where I: Iterator, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 056ccca1d01..f02d278aff5 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -42,7 +42,7 @@ pub use self::flatten::Flatten; #[stable(feature = "iter_copied", since = "1.36.0")] pub use self::copied::Copied; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] pub use self::intersperse::{Intersperse, IntersperseWith}; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 7fb80f954ff..cd8a26025ff 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -414,7 +414,7 @@ pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[stable(feature = "iter_intersperse", since = "1.56.0")] pub use self::adapters::{Intersperse, IntersperseWith}; pub(crate) use self::adapters::process_results; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 850435b53cc..330d3714247 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -535,8 +535,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_intersperse)] - /// /// let mut a = [0, 1, 2].iter().intersperse(&100); /// assert_eq!(a.next(), Some(&0)); // The first element from `a`. /// assert_eq!(a.next(), Some(&100)); // The separator. @@ -547,9 +545,8 @@ pub trait Iterator { /// ``` /// /// `intersperse` can be very useful to join an iterator's items using a common element: - /// ``` - /// #![feature(iter_intersperse)] /// + /// ``` /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::<String>(); /// assert_eq!(hello, "Hello World !"); /// ``` @@ -557,7 +554,7 @@ pub trait Iterator { /// [`Clone`]: crate::clone::Clone /// [`intersperse_with`]: Iterator::intersperse_with #[inline] - #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + #[stable(feature = "iter_intersperse", since = "1.56.0")] fn intersperse(self, separator: Self::Item) -> Intersperse<Self> where Self: Sized, @@ -582,8 +579,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_intersperse)] - /// /// #[derive(PartialEq, Debug)] /// struct NotClone(usize); /// @@ -600,9 +595,8 @@ pub trait Iterator { /// /// `intersperse_with` can be used in situations where the separator needs /// to be computed: - /// ``` - /// #![feature(iter_intersperse)] /// + /// ``` /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); /// /// // The closure mutably borrows its context to generate an item. @@ -615,7 +609,7 @@ pub trait Iterator { /// [`Clone`]: crate::clone::Clone /// [`intersperse`]: Iterator::intersperse #[inline] - #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + #[stable(feature = "iter_intersperse", since = "1.56.0")] fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G> where Self: Sized, diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 13f483f19b7..7853b571be3 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -48,7 +48,6 @@ #![feature(int_log)] #![feature(iter_advance_by)] #![feature(iter_partition_in_place)] -#![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] #![feature(iter_map_while)] diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 6075eb5c7c5..6d7524a733a 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -506,7 +506,8 @@ impl Iterator for ReadDir { let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) }; let mut entry_ptr = ptr::null_mut(); loop { - if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + let err = readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr); + if err != 0 { if entry_ptr.is_null() { // We encountered an error (which will be returned in this iteration), but // we also reached the end of the directory stream. The `end_of_stream` @@ -514,7 +515,7 @@ impl Iterator for ReadDir { // (instead of looping forever) self.end_of_stream = true; } - return Some(Err(Error::last_os_error())); + return Some(Err(Error::from_raw_os_error(err))); } if entry_ptr.is_null() { return None; diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 4715388408f..a10928a7471 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -585,6 +585,8 @@ Here is the list of currently supported register classes: | PowerPC | `reg` | `r[0-31]` | `r` | | PowerPC | `reg_nonzero` | | `r[1-31]` | `b` | | PowerPC | `freg` | `f[0-31]` | `f` | +| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers | +| PowerPC | `xer` | `xer` | Only clobbers | | wasm32 | `local` | None\* | `r` | | BPF | `reg` | `r[0-10]` | `r` | | BPF | `wreg` | `w[0-10]` | `w` | @@ -638,6 +640,8 @@ Each register class has constraints on which value types they can be used with. | PowerPC | `reg` | None | `i8`, `i16`, `i32` | | PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | | PowerPC | `freg` | None | `f32`, `f64` | +| PowerPC | `cr` | N/A | Only clobbers | +| PowerPC | `xer` | N/A | Only clobbers | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | | BPF | `reg` | None | `i8` `i16` `i32` `i64` | | BPF | `wreg` | `alu32` | `i8` `i16` `i32` | diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7704abc9a72..620b4cdf9da 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -753,7 +753,7 @@ fn assoc_const( ) { write!( w, - "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}", + "{}{}const <a href=\"{}\" class=\"constant\">{}</a>: {}", extra, it.visibility.print_with_space(it.def_id, cx), naive_assoc_href(it, link, cx), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index de32e31ca87..b81acd1a93f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,7 +13,6 @@ #![feature(never_type)] #![feature(once_cell)] #![feature(type_ascription)] -#![feature(iter_intersperse)] #![recursion_limit = "256"] #![warn(rustc::internal)] diff --git a/src/test/assembly/asm/powerpc-types.rs b/src/test/assembly/asm/powerpc-types.rs index 1e263649e86..55ca8ee836c 100644 --- a/src/test/assembly/asm/powerpc-types.rs +++ b/src/test/assembly/asm/powerpc-types.rs @@ -194,3 +194,15 @@ check_reg!(reg_f32_f0, f32, "0", "f0", "fmr"); // CHECK: fmr 0, 0 // CHECK: #NO_APP check_reg!(reg_f64_f0, f64, "0", "f0", "fmr"); + +// CHECK-LABEL: reg_f32_f18: +// CHECK: #APP +// CHECK: fmr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_f32_f18, f32, "18", "f18", "fmr"); + +// CHECK-LABEL: reg_f64_f18: +// CHECK: #APP +// CHECK: fmr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_f64_f18, f64, "18", "f18", "fmr"); diff --git a/src/test/codegen/asm-powerpc-clobbers.rs b/src/test/codegen/asm-powerpc-clobbers.rs new file mode 100644 index 00000000000..91a82c60120 --- /dev/null +++ b/src/test/codegen/asm-powerpc-clobbers.rs @@ -0,0 +1,48 @@ +// min-llvm-version: 10.0.1 +// revisions: powerpc powerpc64 powerpc64le +//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +//[powerpc] needs-llvm-components: powerpc +//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//[powerpc64] needs-llvm-components: powerpc +//[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu +//[powerpc64le] needs-llvm-components: powerpc + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +// CHECK-LABEL: @cr_clobber +// CHECK: call void asm sideeffect "", "~{cr}"() +#[no_mangle] +pub unsafe fn cr_clobber() { + asm!("", out("cr") _, options(nostack, nomem)); +} + +// CHECK-LABEL: @cr0_clobber +// CHECK: call void asm sideeffect "", "~{cr0}"() +#[no_mangle] +pub unsafe fn cr0_clobber() { + asm!("", out("cr0") _, options(nostack, nomem)); +} + +// CHECK-LABEL: @cr5_clobber +// CHECK: call void asm sideeffect "", "~{cr5}"() +#[no_mangle] +pub unsafe fn cr5_clobber() { + asm!("", out("cr5") _, options(nostack, nomem)); +} + +// CHECK-LABEL: @xer_clobber +// CHECK: call void asm sideeffect "", "~{xer}"() +#[no_mangle] +pub unsafe fn xer_clobber() { + asm!("", out("xer") _, options(nostack, nomem)); +} diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml index 92ad92a8c34..d8411511c5a 100644 --- a/src/test/rustdoc-gui/font-weight.goml +++ b/src/test/rustdoc-gui/font-weight.goml @@ -13,6 +13,21 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html assert-css: (".impl-items .method", {"font-weight": "600"}, ALL) goto: file://|DOC_PATH|/lib2/trait.Trait.html + +// This is a complex selector, so here's how it works: +// +// * //*[@class='docblock type-decl'] — selects element of any tag with classes docblock and type-decl +// * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait +// * /code — selects immediate child with tag code +// * /a[@class='constant'] — selects immediate child with tag a and class constant +// * //text() — selects child that is text node +// * /parent::* — selects immediate parent of the text node (the * means it can be any tag) +// +// This uses '/parent::*' as a proxy for the style of the text node. +// We can't just select the '<a>' because intermediate tags could be added. +assert-count: ("//*[@class='docblock type-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", 1) +assert-css: ("//*[@class='docblock type-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", {"font-weight": "400"}) + assert-count: (".methods .type", 1) assert-css: (".methods .type", {"font-weight": "600"}) assert-count: (".methods .constant", 1) diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr index e72ef0e4b33..4162cdaa8dc 100644 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super traits of `Baz` with assoc LL | trait Baz: Foo + Bar<Self::Item> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the super traits of `Baz` with associated type name `Item`, completing the cycle + = note: ...which immediately requires computing the super traits of `Baz` with associated type name `Item` again note: cycle used when computing the super traits of `Baz` --> $DIR/ambiguous-associated-type2.rs:7:1 | diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index f3edf1c350f..97f3c759355 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -14,7 +14,7 @@ error[E0391]: cycle detected when building specialization graph of trait `Trait` LL | trait Trait<T> { type Assoc; } | ^^^^^^^^^^^^^^ | - = note: ...which again requires building specialization graph of trait `Trait`, completing the cycle + = note: ...which immediately requires building specialization graph of trait `Trait` again note: cycle used when coherence checking all impls of trait `Trait` --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 | diff --git a/src/test/ui/coherence/issue-85026.rs b/src/test/ui/coherence/issue-85026.rs new file mode 100644 index 00000000000..8b116545aa6 --- /dev/null +++ b/src/test/ui/coherence/issue-85026.rs @@ -0,0 +1,10 @@ +#![feature(auto_traits)] +auto trait AutoTrait {} + +// You cannot impl your own `dyn AutoTrait`. +impl dyn AutoTrait {} //~ERROR E0785 + +// You cannot impl someone else's `dyn AutoTrait` +impl dyn Unpin {} //~ERROR E0785 + +fn main() {} diff --git a/src/test/ui/coherence/issue-85026.stderr b/src/test/ui/coherence/issue-85026.stderr new file mode 100644 index 00000000000..a5da19bbfaa --- /dev/null +++ b/src/test/ui/coherence/issue-85026.stderr @@ -0,0 +1,19 @@ +error[E0785]: cannot define inherent `impl` for a dyn auto trait + --> $DIR/issue-85026.rs:5:6 + | +LL | impl dyn AutoTrait {} + | ^^^^^^^^^^^^^ impl requires at least one non-auto trait + | + = note: define and implement a new trait or type instead + +error[E0785]: cannot define inherent `impl` for a dyn auto trait + --> $DIR/issue-85026.rs:8:6 + | +LL | impl dyn Unpin {} + | ^^^^^^^^^ impl requires at least one non-auto trait + | + = note: define and implement a new trait or type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0785`. diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr index 58c458709a8..fc842fada5a 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of `Foo::X` LL | trait Foo<X = Box<dyn Foo>> { | ^^^ | - = note: ...which again requires computing type of `Foo::X`, completing the cycle + = note: ...which immediately requires computing type of `Foo::X` again note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | @@ -17,7 +17,7 @@ error[E0391]: cycle detected when computing type of `Foo::X` LL | trait Foo<X = Box<dyn Foo>> { | ^^^ | - = note: ...which again requires computing type of `Foo::X`, completing the cycle + = note: ...which immediately requires computing type of `Foo::X` again note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index f4bc5aef82d..d2938435ece 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -31,11 +31,11 @@ help: use `::<...>` instead of `<...>` to specify type or const arguments LL | (0..13).collect::<Vec<i32>(); | ++ -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` --> $DIR/issue-40396.rs:11:43 | LL | let x = std::collections::HashMap<i128, i128>::new(); - | ^ expected one of 7 possible tokens + | ^ expected one of 8 possible tokens | help: use `::<...>` instead of `<...>` to specify type or const arguments | diff --git a/src/test/ui/extern/extern-no-mangle.rs b/src/test/ui/extern/extern-no-mangle.rs new file mode 100644 index 00000000000..ab7c9824af0 --- /dev/null +++ b/src/test/ui/extern/extern-no-mangle.rs @@ -0,0 +1,30 @@ +#![warn(unused_attributes)] + +// Tests that placing the #[no_mangle] attribute on a foreign fn or static emits +// a specialized warning. +// The previous warning only talks about a "function or static" but foreign fns/statics +// are also not allowed to have #[no_mangle] + +// build-pass + +extern "C" { + #[no_mangle] + //~^ WARNING `#[no_mangle]` has no effect on a foreign static + //~^^ WARNING this was previously accepted by the compiler + pub static FOO: u8; + + #[no_mangle] + //~^ WARNING `#[no_mangle]` has no effect on a foreign function + //~^^ WARNING this was previously accepted by the compiler + pub fn bar(); +} + +fn no_new_warn() { + // Should emit the generic "not a function or static" warning + #[no_mangle] + //~^ WARNING attribute should be applied to a free function, impl method or static + //~^^ WARNING this was previously accepted by the compiler + let x = 0_u8; +} + +fn main() {} diff --git a/src/test/ui/extern/extern-no-mangle.stderr b/src/test/ui/extern/extern-no-mangle.stderr new file mode 100644 index 00000000000..b5642814114 --- /dev/null +++ b/src/test/ui/extern/extern-no-mangle.stderr @@ -0,0 +1,42 @@ +warning: attribute should be applied to a free function, impl method or static + --> $DIR/extern-no-mangle.rs:24:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ +... +LL | let x = 0_u8; + | ------------- not a free function, impl method or static + | +note: the lint level is defined here + --> $DIR/extern-no-mangle.rs:1:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: `#[no_mangle]` has no effect on a foreign static + --> $DIR/extern-no-mangle.rs:11:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ help: remove this attribute +... +LL | pub static FOO: u8; + | ------------------- foreign static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: symbol names in extern blocks are not mangled + +warning: `#[no_mangle]` has no effect on a foreign function + --> $DIR/extern-no-mangle.rs:16:5 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ help: remove this attribute +... +LL | pub fn bar(); + | ------------- foreign function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: symbol names in extern blocks are not mangled + +warning: 3 warnings emitted + diff --git a/src/test/ui/feature-gates/feature-gate-let_else.rs b/src/test/ui/feature-gates/feature-gate-let_else.rs new file mode 100644 index 00000000000..3f04a9dabfd --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-let_else.rs @@ -0,0 +1,5 @@ +fn main() { + let Some(x) = Some(1) else { //~ ERROR `let...else` statements are unstable + return; + }; +} diff --git a/src/test/ui/feature-gates/feature-gate-let_else.stderr b/src/test/ui/feature-gates/feature-gate-let_else.stderr new file mode 100644 index 00000000000..86252604154 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-let_else.stderr @@ -0,0 +1,14 @@ +error[E0658]: `let...else` statements are unstable + --> $DIR/feature-gate-let_else.rs:2:5 + | +LL | / let Some(x) = Some(1) else { +LL | | return; +LL | | }; + | |______^ + | + = note: see issue #87335 <https://github.com/rust-lang/rust/issues/87335> for more information + = help: add `#![feature(let_else)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr index 7ffb51061b7..369645f9030 100644 --- a/src/test/ui/infinite/infinite-struct.stderr +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -18,7 +18,7 @@ error[E0391]: cycle detected when computing drop-check constraints for `Take` LL | struct Take(Take); | ^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing drop-check constraints for `Take`, completing the cycle + = note: ...which immediately requires computing drop-check constraints for `Take` again = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 1f147e070b4..61b5e946775 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -17,7 +17,7 @@ error[E0391]: cycle detected when computing drop-check constraints for `MList` LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | - = note: ...which again requires computing drop-check constraints for `MList`, completing the cycle + = note: ...which immediately requires computing drop-check constraints for `MList` again = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-trait-alias-recursion.rs b/src/test/ui/infinite/infinite-trait-alias-recursion.rs new file mode 100644 index 00000000000..ec86744e68c --- /dev/null +++ b/src/test/ui/infinite/infinite-trait-alias-recursion.rs @@ -0,0 +1,10 @@ +#![feature(trait_alias)] + +trait T1 = T2; +//~^ ERROR cycle detected when computing the super predicates of `T1` + +trait T2 = T3; + +trait T3 = T1 + T3; + +fn main() {} diff --git a/src/test/ui/infinite/infinite-trait-alias-recursion.stderr b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr new file mode 100644 index 00000000000..5ecaedb3cb2 --- /dev/null +++ b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr @@ -0,0 +1,42 @@ +error[E0391]: cycle detected when computing the super predicates of `T1` + --> $DIR/infinite-trait-alias-recursion.rs:3:1 + | +LL | trait T1 = T2; + | ^^^^^^^^^^^^^^ + | +note: ...which requires computing the super traits of `T1`... + --> $DIR/infinite-trait-alias-recursion.rs:3:12 + | +LL | trait T1 = T2; + | ^^ +note: ...which requires computing the super predicates of `T2`... + --> $DIR/infinite-trait-alias-recursion.rs:6:1 + | +LL | trait T2 = T3; + | ^^^^^^^^^^^^^^ +note: ...which requires computing the super traits of `T2`... + --> $DIR/infinite-trait-alias-recursion.rs:6:12 + | +LL | trait T2 = T3; + | ^^ +note: ...which requires computing the super predicates of `T3`... + --> $DIR/infinite-trait-alias-recursion.rs:8:1 + | +LL | trait T3 = T1 + T3; + | ^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing the super traits of `T3`... + --> $DIR/infinite-trait-alias-recursion.rs:8:12 + | +LL | trait T3 = T1 + T3; + | ^^ + = note: ...which again requires computing the super predicates of `T1`, completing the cycle + = note: trait aliases cannot be recursive +note: cycle used when collecting item types in top-level module + --> $DIR/infinite-trait-alias-recursion.rs:3:1 + | +LL | trait T1 = T2; + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs new file mode 100644 index 00000000000..5381eedcfac --- /dev/null +++ b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.rs @@ -0,0 +1,6 @@ +type X1 = X2; +//~^ ERROR cycle detected when expanding type alias `X1` +type X2 = X3; +type X3 = X1; + +fn main() {} diff --git a/src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr new file mode 100644 index 00000000000..7f82b294434 --- /dev/null +++ b/src/test/ui/infinite/infinite-type-alias-mutual-recursion.stderr @@ -0,0 +1,34 @@ +error[E0391]: cycle detected when expanding type alias `X1` + --> $DIR/infinite-type-alias-mutual-recursion.rs:1:11 + | +LL | type X1 = X2; + | ^^ + | +note: ...which requires expanding type alias `X2`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:3:11 + | +LL | type X2 = X3; + | ^^ +note: ...which requires expanding type alias `X3`... + --> $DIR/infinite-type-alias-mutual-recursion.rs:4:11 + | +LL | type X3 = X1; + | ^^ + = note: ...which again requires expanding type alias `X1`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information +note: cycle used when collecting item types in top-level module + --> $DIR/infinite-type-alias-mutual-recursion.rs:1:1 + | +LL | / type X1 = X2; +LL | | +LL | | type X2 = X3; +LL | | type X3 = X1; +LL | | +LL | | fn main() {} + | |____________^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/infinite/infinite-vec-type-recursion.stderr b/src/test/ui/infinite/infinite-vec-type-recursion.stderr index 77adefeb124..1e487a5b11c 100644 --- a/src/test/ui/infinite/infinite-vec-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-vec-type-recursion.stderr @@ -1,10 +1,13 @@ -error[E0391]: cycle detected when computing type of `X` +error[E0391]: cycle detected when expanding type alias `X` --> $DIR/infinite-vec-type-recursion.rs:1:14 | LL | type X = Vec<X>; | ^ | - = note: ...which again requires computing type of `X`, completing the cycle + = note: ...which immediately requires expanding type alias `X` again + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information note: cycle used when collecting item types in top-level module --> $DIR/infinite-vec-type-recursion.rs:1:1 | diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index 4aecc7eab46..c964dc41dce 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -6,7 +6,7 @@ LL | | LL | | {} | |__^ | - = note: ...which again requires computing the super traits of `T` with associated type name `Item`, completing the cycle + = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again note: cycle used when computing the super traits of `T` --> $DIR/issue-20772.rs:1:1 | diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index ccbe06d9c0d..be2bbd44800 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the super traits of `Processor` with LL | pub trait Processor: Subscriber<Input = Self::Input> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the super traits of `Processor` with associated type name `Input`, completing the cycle + = note: ...which immediately requires computing the super traits of `Processor` with associated type name `Input` again note: cycle used when computing the super traits of `Processor` --> $DIR/issue-20825.rs:5:1 | diff --git a/src/test/ui/issues/issue-21177.stderr b/src/test/ui/issues/issue-21177.stderr index 59cc6550a8b..6877a184605 100644 --- a/src/test/ui/issues/issue-21177.stderr +++ b/src/test/ui/issues/issue-21177.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing the bounds for type parameter `T` LL | fn foo<T: Trait<A = T::B>>() { } | ^^^^ | - = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle + = note: ...which immediately requires computing the bounds for type parameter `T` again note: cycle used when computing explicit predicates of `foo` --> $DIR/issue-21177.rs:6:21 | diff --git a/src/test/ui/issues/issue-34373.stderr b/src/test/ui/issues/issue-34373.stderr index e8c1e8f9669..8be3cfa72fb 100644 --- a/src/test/ui/issues/issue-34373.stderr +++ b/src/test/ui/issues/issue-34373.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of `Foo::T` LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>; | ^^^^^^^^^^ | -note: ...which requires computing type of `DefaultFoo`... +note: ...which requires expanding type alias `DefaultFoo`... --> $DIR/issue-34373.rs:8:19 | LL | type DefaultFoo = Foo; diff --git a/src/test/ui/let-else/let-else-bool-binop-init.fixed b/src/test/ui/let-else/let-else-bool-binop-init.fixed new file mode 100644 index 00000000000..e47f7f23d7e --- /dev/null +++ b/src/test/ui/let-else/let-else-bool-binop-init.fixed @@ -0,0 +1,8 @@ +// run-rustfix + +#![feature(let_else)] + +fn main() { + let true = (true && false) else { return }; //~ ERROR a `&&` expression cannot be directly assigned in `let...else` + let true = (true || false) else { return }; //~ ERROR a `||` expression cannot be directly assigned in `let...else` +} diff --git a/src/test/ui/let-else/let-else-bool-binop-init.rs b/src/test/ui/let-else/let-else-bool-binop-init.rs new file mode 100644 index 00000000000..e443fb0d6a3 --- /dev/null +++ b/src/test/ui/let-else/let-else-bool-binop-init.rs @@ -0,0 +1,8 @@ +// run-rustfix + +#![feature(let_else)] + +fn main() { + let true = true && false else { return }; //~ ERROR a `&&` expression cannot be directly assigned in `let...else` + let true = true || false else { return }; //~ ERROR a `||` expression cannot be directly assigned in `let...else` +} diff --git a/src/test/ui/let-else/let-else-bool-binop-init.stderr b/src/test/ui/let-else/let-else-bool-binop-init.stderr new file mode 100644 index 00000000000..6551e24cc83 --- /dev/null +++ b/src/test/ui/let-else/let-else-bool-binop-init.stderr @@ -0,0 +1,24 @@ +error: a `&&` expression cannot be directly assigned in `let...else` + --> $DIR/let-else-bool-binop-init.rs:6:16 + | +LL | let true = true && false else { return }; + | ^^^^^^^^^^^^^ + | +help: wrap the expression in parenthesis + | +LL | let true = (true && false) else { return }; + | + + + +error: a `||` expression cannot be directly assigned in `let...else` + --> $DIR/let-else-bool-binop-init.rs:7:16 + | +LL | let true = true || false else { return }; + | ^^^^^^^^^^^^^ + | +help: wrap the expression in parenthesis + | +LL | let true = (true || false) else { return }; + | + + + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/let-else/let-else-brace-before-else.fixed b/src/test/ui/let-else/let-else-brace-before-else.fixed new file mode 100644 index 00000000000..fb4fd77791e --- /dev/null +++ b/src/test/ui/let-else/let-else-brace-before-else.fixed @@ -0,0 +1,26 @@ +// run-rustfix + +#![feature(let_else)] + +fn main() { + let Some(1) = ({ Some(1) }) else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; + let Some(1) = (loop { break Some(1) }) else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; + let 2 = 1 + (match 1 { n => n }) else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; + let Some(1) = (unsafe { unsafe_fn() }) else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; +} + +unsafe fn unsafe_fn<T>() -> T { + unimplemented!(); +} diff --git a/src/test/ui/let-else/let-else-brace-before-else.rs b/src/test/ui/let-else/let-else-brace-before-else.rs new file mode 100644 index 00000000000..c4c5a1ca28b --- /dev/null +++ b/src/test/ui/let-else/let-else-brace-before-else.rs @@ -0,0 +1,26 @@ +// run-rustfix + +#![feature(let_else)] + +fn main() { + let Some(1) = { Some(1) } else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; + let Some(1) = loop { break Some(1) } else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; + let 2 = 1 + match 1 { n => n } else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; + let Some(1) = unsafe { unsafe_fn() } else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + return; + }; +} + +unsafe fn unsafe_fn<T>() -> T { + unimplemented!(); +} diff --git a/src/test/ui/let-else/let-else-brace-before-else.stderr b/src/test/ui/let-else/let-else-brace-before-else.stderr new file mode 100644 index 00000000000..eac029c848b --- /dev/null +++ b/src/test/ui/let-else/let-else-brace-before-else.stderr @@ -0,0 +1,46 @@ +error: right curly brace `}` before `else` in a `let...else` statement not allowed + --> $DIR/let-else-brace-before-else.rs:6:29 + | +LL | let Some(1) = { Some(1) } else { + | ^ + | +help: try wrapping the expression in parenthesis + | +LL | let Some(1) = ({ Some(1) }) else { + | + + + +error: right curly brace `}` before `else` in a `let...else` statement not allowed + --> $DIR/let-else-brace-before-else.rs:10:40 + | +LL | let Some(1) = loop { break Some(1) } else { + | ^ + | +help: try wrapping the expression in parenthesis + | +LL | let Some(1) = (loop { break Some(1) }) else { + | + + + +error: right curly brace `}` before `else` in a `let...else` statement not allowed + --> $DIR/let-else-brace-before-else.rs:14:34 + | +LL | let 2 = 1 + match 1 { n => n } else { + | ^ + | +help: try wrapping the expression in parenthesis + | +LL | let 2 = 1 + (match 1 { n => n }) else { + | + + + +error: right curly brace `}` before `else` in a `let...else` statement not allowed + --> $DIR/let-else-brace-before-else.rs:18:40 + | +LL | let Some(1) = unsafe { unsafe_fn() } else { + | ^ + | +help: try wrapping the expression in parenthesis + | +LL | let Some(1) = (unsafe { unsafe_fn() }) else { + | + + + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/let-else/let-else-check.rs b/src/test/ui/let-else/let-else-check.rs new file mode 100644 index 00000000000..ab763447ef7 --- /dev/null +++ b/src/test/ui/let-else/let-else-check.rs @@ -0,0 +1,14 @@ +#![feature(let_else)] + +#![deny(unused_variables)] + +fn main() { + // type annotation, attributes + #[allow(unused_variables)] + let Some(_): Option<u32> = Some(Default::default()) else { + let x = 1; // OK + return; + }; + + let x = 1; //~ ERROR unused variable: `x` +} diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr new file mode 100644 index 00000000000..50e54d320b0 --- /dev/null +++ b/src/test/ui/let-else/let-else-check.stderr @@ -0,0 +1,14 @@ +error: unused variable: `x` + --> $DIR/let-else-check.rs:13:9 + | +LL | let x = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/let-else-check.rs:3:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/let-else/let-else-irrefutable.rs b/src/test/ui/let-else/let-else-irrefutable.rs new file mode 100644 index 00000000000..b1e09a1248f --- /dev/null +++ b/src/test/ui/let-else/let-else-irrefutable.rs @@ -0,0 +1,7 @@ +// check-pass + +#![feature(let_else)] + +fn main() { + let x = 1 else { return }; //~ WARN irrefutable `let...else` pattern +} diff --git a/src/test/ui/let-else/let-else-irrefutable.stderr b/src/test/ui/let-else/let-else-irrefutable.stderr new file mode 100644 index 00000000000..e030c50d45d --- /dev/null +++ b/src/test/ui/let-else/let-else-irrefutable.stderr @@ -0,0 +1,12 @@ +warning: irrefutable `let...else` pattern + --> $DIR/let-else-irrefutable.rs:6:5 + | +LL | let x = 1 else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(irrefutable_let_patterns)]` on by default + = note: this pattern will always match, so the `else` clause is useless + = help: consider removing the `else` clause + +warning: 1 warning emitted + diff --git a/src/test/ui/let-else/let-else-missing-semicolon.rs b/src/test/ui/let-else/let-else-missing-semicolon.rs new file mode 100644 index 00000000000..ed9d79f1ebd --- /dev/null +++ b/src/test/ui/let-else/let-else-missing-semicolon.rs @@ -0,0 +1,11 @@ +#![feature(let_else)] + +fn main() { + let Some(x) = Some(1) else { + return; + } //~ ERROR expected `;`, found keyword `let` + let _ = ""; + let Some(x) = Some(1) else { + panic!(); + } //~ ERROR expected `;`, found `}` +} diff --git a/src/test/ui/let-else/let-else-missing-semicolon.stderr b/src/test/ui/let-else/let-else-missing-semicolon.stderr new file mode 100644 index 00000000000..1818a0b1263 --- /dev/null +++ b/src/test/ui/let-else/let-else-missing-semicolon.stderr @@ -0,0 +1,18 @@ +error: expected `;`, found keyword `let` + --> $DIR/let-else-missing-semicolon.rs:6:6 + | +LL | } + | ^ help: add `;` here +LL | let _ = ""; + | --- unexpected token + +error: expected `;`, found `}` + --> $DIR/let-else-missing-semicolon.rs:10:6 + | +LL | } + | ^ help: add `;` here +LL | } + | - unexpected token + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/let-else/let-else-non-diverging.rs b/src/test/ui/let-else/let-else-non-diverging.rs new file mode 100644 index 00000000000..a1cee335aee --- /dev/null +++ b/src/test/ui/let-else/let-else-non-diverging.rs @@ -0,0 +1,13 @@ +#![feature(let_else)] + +fn main() { + let Some(x) = Some(1) else { //~ ERROR does not diverge + Some(2) + }; + let Some(x) = Some(1) else { //~ ERROR does not diverge + if 1 == 1 { + panic!(); + } + }; + let Some(x) = Some(1) else { Some(2) }; //~ ERROR does not diverge +} diff --git a/src/test/ui/let-else/let-else-non-diverging.stderr b/src/test/ui/let-else/let-else-non-diverging.stderr new file mode 100644 index 00000000000..fd5a18ce7ea --- /dev/null +++ b/src/test/ui/let-else/let-else-non-diverging.stderr @@ -0,0 +1,44 @@ +error[E0308]: `else` clause of `let...else` does not diverge + --> $DIR/let-else-non-diverging.rs:12:32 + | +LL | let Some(x) = Some(1) else { Some(2) }; + | ^^^^^^^^^^^ expected `!`, found enum `Option` + | + = note: expected type `!` + found type `Option<{integer}>` + = help: try adding a diverging expression, such as `return` or `panic!(..)` + = help: ...or use `match` instead of `let...else` + +error[E0308]: `else` clause of `let...else` does not diverge + --> $DIR/let-else-non-diverging.rs:7:32 + | +LL | let Some(x) = Some(1) else { + | ________________________________^ +LL | | if 1 == 1 { +LL | | panic!(); +LL | | } +LL | | }; + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found type `()` + = help: try adding a diverging expression, such as `return` or `panic!(..)` + = help: ...or use `match` instead of `let...else` + +error[E0308]: `else` clause of `let...else` does not diverge + --> $DIR/let-else-non-diverging.rs:4:32 + | +LL | let Some(x) = Some(1) else { + | ________________________________^ +LL | | Some(2) +LL | | }; + | |_____^ expected `!`, found enum `Option` + | + = note: expected type `!` + found type `Option<{integer}>` + = help: try adding a diverging expression, such as `return` or `panic!(..)` + = help: ...or use `match` instead of `let...else` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/let-else/let-else-run-pass.rs b/src/test/ui/let-else/let-else-run-pass.rs new file mode 100644 index 00000000000..5d96623236d --- /dev/null +++ b/src/test/ui/let-else/let-else-run-pass.rs @@ -0,0 +1,35 @@ +// run-pass + +#![feature(let_else)] + +fn main() { + #[allow(dead_code)] + enum MyEnum { + A(String), + B { f: String }, + C, + } + // ref binding to non-copy value and or-pattern + let (MyEnum::A(ref x) | MyEnum::B { f: ref x }) = (MyEnum::B { f: String::new() }) else { + panic!(); + }; + assert_eq!(x, ""); + + // nested let-else + let mut x = 1; + loop { + let 4 = x else { + let 3 = x else { + x += 1; + continue; + }; + break; + }; + panic!(); + } + assert_eq!(x, 3); + + // else return + let Some(1) = Some(2) else { return }; + panic!(); +} diff --git a/src/test/ui/let-else/let-else-scope.rs b/src/test/ui/let-else/let-else-scope.rs new file mode 100644 index 00000000000..f17682db4c3 --- /dev/null +++ b/src/test/ui/let-else/let-else-scope.rs @@ -0,0 +1,7 @@ +#![feature(let_else)] + +fn main() { + let Some(x) = Some(2) else { + panic!("{}", x); //~ ERROR cannot find value `x` in this scope + }; +} diff --git a/src/test/ui/let-else/let-else-scope.stderr b/src/test/ui/let-else/let-else-scope.stderr new file mode 100644 index 00000000000..4b3936eac4b --- /dev/null +++ b/src/test/ui/let-else/let-else-scope.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/let-else-scope.rs:5:22 + | +LL | panic!("{}", x); + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr index 6dfe7aad6ea..cec6980c008 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr @@ -12,11 +12,11 @@ error: expected expression, found `]` LL | #[cfg(FALSE)] fn e() { let _ = [#[attr]]; } | ^ expected expression -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `#` +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:9:35 | LL | #[cfg(FALSE)] fn e() { let _ = foo#[attr](); } - | ^ expected one of 7 possible tokens + | ^ expected one of 8 possible tokens error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:11:36 @@ -70,11 +70,11 @@ LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `#` +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:23:34 | LL | #[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; } - | ^ expected one of 7 possible tokens + | ^ expected one of 8 possible tokens error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:25:35 @@ -372,11 +372,11 @@ error: unexpected token: `#` LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } | ^ -error: expected one of `.`, `;`, `?`, or an operator, found `#` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } - | ^ expected one of `.`, `;`, `?`, or an operator + | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: unexpected token: `#` --> $DIR/attr-stmt-expr-attr-bad.rs:103:34 @@ -384,11 +384,11 @@ error: unexpected token: `#` LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } | ^ -error: expected one of `.`, `;`, `?`, or an operator, found `#` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:103:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } - | ^ expected one of `.`, `;`, `?`, or an operator + | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: expected statement after outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:108:37 diff --git a/src/test/ui/parser/issue-72253.rs b/src/test/ui/parser/issue-72253.rs index 6f9af73b039..1446a796fa0 100644 --- a/src/test/ui/parser/issue-72253.rs +++ b/src/test/ui/parser/issue-72253.rs @@ -1,6 +1,6 @@ fn main() { let a = std::process::Command::new("echo") .arg("1") - ,arg("2") //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `,` + ,arg("2") //~ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `,` .output(); } diff --git a/src/test/ui/parser/issue-72253.stderr b/src/test/ui/parser/issue-72253.stderr index 3819fd92a9e..477fa09f495 100644 --- a/src/test/ui/parser/issue-72253.stderr +++ b/src/test/ui/parser/issue-72253.stderr @@ -1,8 +1,8 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `,` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `,` --> $DIR/issue-72253.rs:4:9 | LL | .arg("1") - | - expected one of `.`, `;`, `?`, or an operator + | - expected one of `.`, `;`, `?`, `else`, or an operator LL | ,arg("2") | ^ unexpected token diff --git a/src/test/ui/parser/issue-84117.rs b/src/test/ui/parser/issue-84117.rs index 0f200735915..919585877cf 100644 --- a/src/test/ui/parser/issue-84117.rs +++ b/src/test/ui/parser/issue-84117.rs @@ -2,8 +2,8 @@ fn main() { let outer_local:e_outer<&str, { let inner_local:e_inner<&str, } //~^ ERROR expected one of `>`, a const expression //~| ERROR expected one of `>`, a const expression, lifetime, or type, found `}` - //~| ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` - //~| ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` - //~| ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` + //~| ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` + //~| ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` + //~| ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` } //~^ ERROR expected one of `,`, `:`, `=`, or `>`, found `}` diff --git a/src/test/ui/parser/issue-84117.stderr b/src/test/ui/parser/issue-84117.stderr index d667a4977d0..5b9cc53baa5 100644 --- a/src/test/ui/parser/issue-84117.stderr +++ b/src/test/ui/parser/issue-84117.stderr @@ -7,11 +7,11 @@ LL | let outer_local:e_outer<&str, { let inner_local:e_inner<&str, } | | help: use `=` if you meant to assign | while parsing the type for `inner_local` -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` --> $DIR/issue-84117.rs:2:65 | LL | let outer_local:e_outer<&str, { let inner_local:e_inner<&str, } - | ^ expected one of 7 possible tokens + | ^ expected one of 8 possible tokens error: expected one of `,`, `:`, `=`, or `>`, found `}` --> $DIR/issue-84117.rs:8:1 @@ -33,17 +33,17 @@ LL | let outer_local:e_outer<&str, { let inner_local:e_inner<&str, } | | help: use `=` if you meant to assign | while parsing the type for `inner_local` -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` --> $DIR/issue-84117.rs:2:65 | LL | let outer_local:e_outer<&str, { let inner_local:e_inner<&str, } - | ^ expected one of 7 possible tokens + | ^ expected one of 8 possible tokens -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` --> $DIR/issue-84117.rs:2:33 | LL | let outer_local:e_outer<&str, { let inner_local:e_inner<&str, } - | ^ expected one of 7 possible tokens + | ^ expected one of 8 possible tokens error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/macro/issue-37234.stderr b/src/test/ui/parser/macro/issue-37234.stderr index f0ec79e5357..8d9636d401c 100644 --- a/src/test/ui/parser/macro/issue-37234.stderr +++ b/src/test/ui/parser/macro/issue-37234.stderr @@ -1,8 +1,8 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `""` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `""` --> $DIR/issue-37234.rs:3:19 | LL | let x = 5 ""; - | ^^ expected one of `.`, `;`, `?`, or an operator + | ^^ expected one of `.`, `;`, `?`, `else`, or an operator ... LL | failed!(); | ---------- in this macro invocation diff --git a/src/test/ui/parser/missing-semicolon.rs b/src/test/ui/parser/missing-semicolon.rs index a24dfa761a6..f68d177c01f 100644 --- a/src/test/ui/parser/missing-semicolon.rs +++ b/src/test/ui/parser/missing-semicolon.rs @@ -1,6 +1,6 @@ macro_rules! m { ($($e1:expr),*; $($e2:expr),*) => { - $( let x = $e1 )*; //~ ERROR expected one of `.`, `;`, `?`, or + $( let x = $e1 )*; //~ ERROR expected one of `.`, `;`, `?`, `else`, or $( println!("{}", $e2) )*; } } diff --git a/src/test/ui/parser/missing-semicolon.stderr b/src/test/ui/parser/missing-semicolon.stderr index 68f0f440c46..72f76b6fe3f 100644 --- a/src/test/ui/parser/missing-semicolon.stderr +++ b/src/test/ui/parser/missing-semicolon.stderr @@ -1,8 +1,8 @@ -error: expected one of `.`, `;`, `?`, or an operator, found keyword `let` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found keyword `let` --> $DIR/missing-semicolon.rs:3:12 | LL | $( let x = $e1 )*; - | ^^^ expected one of `.`, `;`, `?`, or an operator + | ^^^ expected one of `.`, `;`, `?`, `else`, or an operator ... LL | fn main() { m!(0, 0; 0, 0); } | --------------- in this macro invocation diff --git a/src/test/ui/parser/range-3.rs b/src/test/ui/parser/range-3.rs index 931839fb282..2c917a24e90 100644 --- a/src/test/ui/parser/range-3.rs +++ b/src/test/ui/parser/range-3.rs @@ -2,5 +2,5 @@ pub fn main() { let r = 1..2..3; - //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` + //~^ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `..` } diff --git a/src/test/ui/parser/range-3.stderr b/src/test/ui/parser/range-3.stderr index f866ea59983..340167f1804 100644 --- a/src/test/ui/parser/range-3.stderr +++ b/src/test/ui/parser/range-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `..` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `..` --> $DIR/range-3.rs:4:17 | LL | let r = 1..2..3; - | ^^ expected one of `.`, `;`, `?`, or an operator + | ^^ expected one of `.`, `;`, `?`, `else`, or an operator error: aborting due to previous error diff --git a/src/test/ui/parser/range-4.rs b/src/test/ui/parser/range-4.rs index 20af9567205..c970c96de84 100644 --- a/src/test/ui/parser/range-4.rs +++ b/src/test/ui/parser/range-4.rs @@ -2,5 +2,5 @@ pub fn main() { let r = ..1..2; - //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` + //~^ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `..` } diff --git a/src/test/ui/parser/range-4.stderr b/src/test/ui/parser/range-4.stderr index dcb85170c1d..720d489389b 100644 --- a/src/test/ui/parser/range-4.stderr +++ b/src/test/ui/parser/range-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `..` +error: expected one of `.`, `;`, `?`, `else`, or an operator, found `..` --> $DIR/range-4.rs:4:16 | LL | let r = ..1..2; - | ^^ expected one of `.`, `;`, `?`, or an operator + | ^^ expected one of `.`, `;`, `?`, `else`, or an operator error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/top-level-alternation.rs b/src/test/ui/pattern/usefulness/top-level-alternation.rs index 4b47b978930..076de846129 100644 --- a/src/test/ui/pattern/usefulness/top-level-alternation.rs +++ b/src/test/ui/pattern/usefulness/top-level-alternation.rs @@ -1,3 +1,5 @@ +#![feature(let_else)] + #![deny(unreachable_patterns)] fn main() { @@ -53,4 +55,5 @@ fn main() { 1..=2 => {}, //~ ERROR unreachable pattern _ => {}, } + let (0 | 0) = 0 else { return }; //~ ERROR unreachable pattern } diff --git a/src/test/ui/pattern/usefulness/top-level-alternation.stderr b/src/test/ui/pattern/usefulness/top-level-alternation.stderr index 76bc4f8d091..dd5936fdcc4 100644 --- a/src/test/ui/pattern/usefulness/top-level-alternation.stderr +++ b/src/test/ui/pattern/usefulness/top-level-alternation.stderr @@ -1,68 +1,74 @@ error: unreachable pattern - --> $DIR/top-level-alternation.rs:4:23 + --> $DIR/top-level-alternation.rs:6:23 | LL | while let 0..=2 | 1 = 0 {} | ^ | note: the lint level is defined here - --> $DIR/top-level-alternation.rs:1:9 + --> $DIR/top-level-alternation.rs:3:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:5:20 + --> $DIR/top-level-alternation.rs:7:20 | LL | if let 0..=2 | 1 = 0 {} | ^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:9:15 + --> $DIR/top-level-alternation.rs:11:15 | LL | | 0 => {} | ^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:14:15 + --> $DIR/top-level-alternation.rs:16:15 | LL | | Some(0) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:19:9 + --> $DIR/top-level-alternation.rs:21:9 | LL | (0, 0) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:39:9 + --> $DIR/top-level-alternation.rs:41:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:43:9 + --> $DIR/top-level-alternation.rs:45:9 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:44:9 + --> $DIR/top-level-alternation.rs:46:9 | LL | None => {} | ^^^^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:49:9 + --> $DIR/top-level-alternation.rs:51:9 | LL | None | Some(_) => {} | ^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/top-level-alternation.rs:53:9 + --> $DIR/top-level-alternation.rs:55:9 | LL | 1..=2 => {}, | ^^^^^ -error: aborting due to 10 previous errors +error: unreachable pattern + --> $DIR/top-level-alternation.rs:58:14 + | +LL | let (0 | 0) = 0 else { return }; + | ^ + +error: aborting due to 11 previous errors diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 525b5cf7d84..0dcf0184db1 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of `<impl at $DIR/issue-23305.r LL | impl dyn ToNbt<Self> {} | ^^^^ | - = note: ...which again requires computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:24>`, completing the cycle + = note: ...which immediately requires computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:24>` again note: cycle used when collecting item types in top-level module --> $DIR/issue-23305.rs:1:1 | diff --git a/src/test/ui/resolve/resolve-self-in-impl.stderr b/src/test/ui/resolve/resolve-self-in-impl.stderr index 5b5c1834cad..7f623e47353 100644 --- a/src/test/ui/resolve/resolve-self-in-impl.stderr +++ b/src/test/ui/resolve/resolve-self-in-impl.stderr @@ -4,7 +4,7 @@ error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self- LL | impl Tr for Self {} | ^^^^ | - = note: ...which again requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:20>`, completing the cycle + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:20>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -23,7 +23,7 @@ error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self- LL | impl Tr for S<Self> {} | ^^^^ | - = note: ...which again requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:23>`, completing the cycle + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:23>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -42,7 +42,7 @@ error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self- LL | impl Self {} | ^^^^ | - = note: ...which again requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:13>`, completing the cycle + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:13>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -61,7 +61,7 @@ error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self- LL | impl S<Self> {} | ^^^^ | - = note: ...which again requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:16>`, completing the cycle + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:16>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -80,7 +80,7 @@ error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/ LL | impl Tr<Self::A> for S {} | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:26>`, completing the cycle + = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:26>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index ac21eb5275f..2ffc00b449d 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -316,8 +316,11 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { fn visit_local(&mut self, local: &'tcx Local) { - if let Some(ref init) = local.init { - self.apply(|this| walk_expr(this, &**init)); + if let Some((init, els)) = &local.kind.init_else_opt() { + self.apply(|this| walk_expr(this, init)); + if let Some(els) = els { + self.apply(|this| walk_block(this, els)); + } } // add the pattern after the expression because the bindings aren't available // yet in the init diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 7ea07a15aea..133f6c29f7d 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -221,7 +221,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Local(l), Local(r)) => { eq_pat(&l.pat, &r.pat) && both(&l.ty, &r.ty, |l, r| eq_ty(l, r)) - && eq_expr_opt(&l.init, &r.init) + && eq_local_kind(&l.kind, &r.kind) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) }, (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), @@ -234,6 +234,16 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { } } +pub fn eq_local_kind(l: &LocalKind, r: &LocalKind) -> bool { + use LocalKind::*; + match (l, r) { + (Decl, Decl) => true, + (Init(l), Init(r)) => eq_expr(l, r), + (InitElse(li, le), InitElse(ri, re)) => eq_expr(li, ri) && eq_block(le, re), + _ => false, + } +} + pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool { eq_id(l.ident, r.ident) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 0542358c6e7..2483d0570d9 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -48,7 +48,7 @@ impl Rewrite for ast::Local { skip_out_of_file_lines_range!(context, self.span); - if contains_skip(&self.attrs) { + if contains_skip(&self.attrs) || matches!(self.kind, ast::LocalKind::InitElse(..)) { return None; } @@ -97,7 +97,7 @@ impl Rewrite for ast::Local { infix.push_str(&rewrite); } - if self.init.is_some() { + if self.kind.init().is_some() { infix.push_str(" ="); } @@ -106,11 +106,12 @@ impl Rewrite for ast::Local { result.push_str(&infix); - if let Some(ref ex) = self.init { + if let Some((init, _els)) = self.kind.init_else_opt() { // 1 = trailing semicolon; let nested_shape = shape.sub_width(1)?; - result = rewrite_assign_rhs(context, result, &**ex, nested_shape)?; + result = rewrite_assign_rhs(context, result, init, nested_shape)?; + // todo else } result.push(';'); diff --git a/src/tools/rustfmt/tests/source/let_else.rs b/src/tools/rustfmt/tests/source/let_else.rs new file mode 100644 index 00000000000..a6e816fb524 --- /dev/null +++ b/src/tools/rustfmt/tests/source/let_else.rs @@ -0,0 +1,3 @@ +fn main() { + let Some(1) = Some(1) else { return }; +} diff --git a/src/tools/rustfmt/tests/target/let_else.rs b/src/tools/rustfmt/tests/target/let_else.rs new file mode 100644 index 00000000000..a6e816fb524 --- /dev/null +++ b/src/tools/rustfmt/tests/target/let_else.rs @@ -0,0 +1,3 @@ +fn main() { + let Some(1) = Some(1) else { return }; +} |
