diff options
107 files changed, 1661 insertions, 1004 deletions
diff --git a/Cargo.lock b/Cargo.lock index a912eee97db..1fe03a06c79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,9 +1505,9 @@ dependencies = [ [[package]] name = "gsgdt" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb958139bb971f37d2f5423436f137768f88b9c616b4c21d4f634dd129508d60" +checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825" dependencies = [ "serde", ] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6ee1dbe4ae3..75f384405bb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -34,7 +34,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Repeat(ref expr, ref count) => { let expr = self.lower_expr(expr); - let count = self.lower_anon_const(count); + let count = self.lower_array_length(count); hir::ExprKind::Repeat(expr, count) } ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 77738b2c5cc..35eb716949a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -56,6 +56,7 @@ use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::LintBuffer; +use rustc_session::parse::feature_err; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::hygiene::ExpnId; @@ -1248,7 +1249,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )) } TyKind::Array(ref ty, ref length) => { - hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length)) + hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) } TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)), TyKind::TraitObject(ref bounds, kind) => { @@ -2039,6 +2040,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block, AttrVec::new()) } + fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen { + match c.value.kind { + ExprKind::Underscore => { + if self.sess.features_untracked().generic_arg_infer { + hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span) + } else { + feature_err( + &self.sess.parse_sess, + sym::generic_arg_infer, + c.value.span, + "using `_` for array lengths is unstable", + ) + .emit(); + hir::ArrayLen::Body(self.lower_anon_const(c)) + } + } + _ => hir::ArrayLen::Body(self.lower_anon_const(c)), + } + } + fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { self.with_new_scopes(|this| hir::AnonConst { hir_id: this.lower_node_id(c.id), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b87dd449a1e..91fa4595241 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2461,7 +2461,11 @@ impl<'a> State<'a> { self.print_path(path, true, 0); } self.nbsp(); - self.word_space("{"); + self.word("{"); + let empty = fields.is_empty() && !etc; + if !empty { + self.space(); + } self.commasep_cmnt( Consistent, &fields, @@ -2482,7 +2486,9 @@ impl<'a> State<'a> { } self.word(".."); } - self.space(); + if !empty { + self.space(); + } self.word("}"); } PatKind::Tuple(ref elts) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 63ffcb3ec45..fe34d6e7ca9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1394,10 +1394,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::NullaryOp(_op, _ty) => { // nullary ops take no dynamic input; no borrowck effect. - // - // FIXME: is above actually true? Do we want to track - // the fact that uninitialized data can be created via - // `NullOp::Box`? } Rvalue::Aggregate(ref aggregate_kind, ref operands) => { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fc2f04f146e..b16f5af66f2 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -715,30 +715,6 @@ fn codegen_stmt<'tcx>( let operand = operand.load_scalar(fx); lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } - Rvalue::NullaryOp(NullOp::Box, content_ty) => { - let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap(); - let content_ty = fx.monomorphize(content_ty); - let layout = fx.layout_of(content_ty); - let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64); - let llalign = fx.bcx.ins().iconst(usize_type, layout.align.abi.bytes() as i64); - let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); - - // Allocate space: - let def_id = - match fx.tcx.lang_items().require(rustc_hir::LangItem::ExchangeMalloc) { - Ok(id) => id, - Err(s) => { - fx.tcx - .sess - .fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); - let func_ref = fx.get_function_ref(instance); - let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]); - let ptr = fx.bcx.inst_results(call)[0]; - lval.write_cvalue(fx, CValue::by_val(ptr, box_layout)); - } Rvalue::NullaryOp(null_op, ty) => { assert!( lval.layout() @@ -749,7 +725,6 @@ fn codegen_stmt<'tcx>( let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::Box => unreachable!(), }; let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into()); lval.write_cvalue(fx, val); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 3e7371179cc..01f7868df34 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -160,17 +160,17 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { // the values should match the ones in the DWARF standard anyway. let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() }; let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() }; - let mut addr_ops = SmallVec::<[_; 8]>::new(); + let mut addr_ops = SmallVec::<[u64; 8]>::new(); if direct_offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(direct_offset.bytes() as i64); + addr_ops.push(direct_offset.bytes() as u64); } for &offset in indirect_offsets { addr_ops.push(op_deref()); if offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(offset.bytes() as i64); + addr_ops.push(offset.bytes() as u64); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 6450b7490bd..f2782f84f55 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2108,7 +2108,7 @@ extern "C" { Builder: &DIBuilder<'a>, Val: &'a Value, VarInfo: &'a DIVariable, - AddrOps: *const i64, + AddrOps: *const u64, AddrOpsCount: c_uint, DL: &'a DILocation, InsertAtEnd: &'a BasicBlock, @@ -2199,8 +2199,8 @@ extern "C" { Scope: &'a DIScope, InlinedAt: Option<&'a DILocation>, ) -> &'a DILocation; - pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; - pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64; + pub fn LLVMRustDIBuilderCreateOpDeref() -> u64; + pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64; #[allow(improper_ctypes)] pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 7c97143e807..79c24f0f172 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -6,8 +6,8 @@ use std::path::Path; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ - elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags, - SectionKind, SymbolFlags, SymbolKind, SymbolScope, + elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, + SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, }; use snap::write::FrameEncoder; @@ -216,13 +216,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> { ); match file.format() { BinaryFormat::Coff => { - const IMAGE_SCN_LNK_REMOVE: u32 = 0; file.section_mut(section).flags = - SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE }; + SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE }; } BinaryFormat::Elf => { - const SHF_EXCLUDE: u64 = 0x80000000; - file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE }; + file.section_mut(section).flags = + SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 }; } _ => {} }; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6f960ca44cd..679c4576701 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,7 +8,6 @@ use crate::traits::*; use crate::MemFlags; use rustc_apfloat::{ieee, Float, Round, Status}; -use rustc_hir::lang_items::LangItem; use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; @@ -486,31 +485,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) } - mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { - let content_ty = self.monomorphize(content_ty); - let content_layout = bx.cx().layout_of(content_ty); - let llsize = bx.cx().const_usize(content_layout.size.bytes()); - let llalign = bx.cx().const_usize(content_layout.align.abi.bytes()); - let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); - let llty_ptr = bx.cx().backend_type(box_layout); - - // Allocate space: - let def_id = match bx.tcx().lang_items().require(LangItem::ExchangeMalloc) { - Ok(id) => id, - Err(s) => { - bx.cx().sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(bx.tcx(), def_id); - let r = bx.cx().get_fn_addr(instance); - let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p()); - let call = bx.call(ty, r, &[llsize, llalign], None); - let val = bx.pointercast(call, llty_ptr); - - let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; - (bx, operand) - } - mir::Rvalue::NullaryOp(null_op, ty) => { let ty = self.monomorphize(ty); assert!(bx.cx().type_is_sized(ty)); @@ -518,7 +492,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), - mir::NullOp::Box => unreachable!(), }; let val = bx.cx().const_usize(val); let tcx = self.cx.tcx(); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c5412affafe..3ec9f3ca3b8 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -63,7 +63,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( cid.instance, body, Some(&ret.into()), - StackPopCleanup::None { cleanup: false }, + StackPopCleanup::Root { cleanup: false }, )?; // The main interpreter loop. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fef0e00e507..30e9cbe4403 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -398,13 +398,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) } - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) - } - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // The step limit has already been hit in a previous call to `before_terminator`. if ecx.machine.steps_remaining == 0 { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 246807a112a..0a8112da2ab 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -156,11 +156,11 @@ pub enum StackPopCleanup { /// `ret` stores the block we jump to on a normal return, while `unwind` /// stores the block used for cleanup during unwinding. Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind }, - /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. + /// The root frame of the stack: nowhere else to jump to. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away /// the entire `ecx` when it is done). - None { cleanup: bool }, + Root { cleanup: bool }, } /// State of a local variable including a memoized layout @@ -849,7 +849,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // because this is CTFE and the final value will be thoroughly validated anyway. let cleanup = match return_to_block { StackPopCleanup::Goto { .. } => true, - StackPopCleanup::None { cleanup, .. } => cleanup, + StackPopCleanup::Root { cleanup, .. } => cleanup, }; if !cleanup { @@ -874,8 +874,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Follow the unwind edge. let unwind = match return_to_block { StackPopCleanup::Goto { unwind, .. } => unwind, - StackPopCleanup::None { .. } => { - panic!("Encountered StackPopCleanup::None when unwinding!") + StackPopCleanup::Root { .. } => { + panic!("encountered StackPopCleanup::Root when unwinding!") } }; self.unwind_to_block(unwind) @@ -883,7 +883,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Follow the normal return edge. match return_to_block { StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), - StackPopCleanup::None { .. } => Ok(()), + StackPopCleanup::Root { .. } => { + assert!( + self.stack().is_empty(), + "only the topmost frame can have StackPopCleanup::Root" + ); + Ok(()) + } } } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 6a03b699d47..23ec3875cbc 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -212,12 +212,6 @@ pub trait Machine<'mir, 'tcx>: Sized { right: &ImmTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>; - /// Heap allocations via the `box` keyword. - fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: &PlaceTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx>; - /// Called to read the specified `local` from the `frame`. /// Since reading a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6e37aae0f5e..3daa1d3c2b3 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -271,10 +271,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(place.to_ref(self), &dest)?; } - NullaryOp(mir::NullOp::Box, _) => { - M::box_alloc(self, &dest)?; - } - NullaryOp(null_op, ty) => { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; @@ -289,7 +285,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), - mir::NullOp::Box => unreachable!(), }; self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 1d5f4630152..dd749c03934 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -632,7 +632,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} - Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, ref operand) => { diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 1537de993d1..55fba5d7ddf 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -508,7 +508,6 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::NullaryOp(op, _) => match op { - NullOp::Box => return Err(Unpromotable), NullOp::SizeOf => {} NullOp::AlignOf => {} }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 69572807e7c..d59756239d9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1407,6 +1407,20 @@ impl fmt::Display for ConstContext { /// A literal. pub type Lit = Spanned<LitKind>; +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] +pub enum ArrayLen { + Infer(HirId, Span), + Body(AnonConst), +} + +impl ArrayLen { + pub fn hir_id(&self) -> HirId { + match self { + &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id, + } + } +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> { /// /// E.g., `[1; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. - Repeat(&'hir Expr<'hir>, AnonConst), + Repeat(&'hir Expr<'hir>, ArrayLen), /// A suspension point for generators (i.e., `yield <expr>`). Yield(&'hir Expr<'hir>, YieldSource), @@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> { /// A variable length slice (i.e., `[T]`). Slice(&'hir Ty<'hir>), /// A fixed length array (i.e., `[T; n]`). - Array(&'hir Ty<'hir>, AnonConst), + Array(&'hir Ty<'hir>, ArrayLen), /// A raw pointer (i.e., `*const T` or `*mut T`). Ptr(MutTy<'hir>), /// A reference (i.e., `&'a T` or `&'a mut T`). @@ -2484,7 +2498,7 @@ impl FnRetTy<'_> { } } -#[derive(Encodable, Debug)] +#[derive(Encodable, Debug, HashStable_Generic)] pub struct Mod<'hir> { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 0fab7cbfeea..d0eee422202 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -383,6 +383,9 @@ pub trait Visitor<'v>: Sized { fn visit_pat(&mut self, p: &'v Pat<'v>) { walk_pat(self, p) } + fn visit_array_length(&mut self, len: &'v ArrayLen) { + walk_array_len(self, len) + } fn visit_anon_const(&mut self, c: &'v AnonConst) { walk_anon_const(self, c) } @@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::Array(ref ty, ref length) => { visitor.visit_ty(ty); - visitor.visit_anon_const(length) + visitor.visit_array_length(length) } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { for bound in bounds { @@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { } } +pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { + match len { + &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id), + ArrayLen::Body(c) => visitor.visit_anon_const(c), + } +} + pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { visitor.visit_id(constant.hir_id); visitor.visit_nested_body(constant.body); @@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); - visitor.visit_anon_const(count) + visitor.visit_array_length(count) } ExprKind::Struct(ref qpath, fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.hir_id, expression.span); diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index c8d729a999e..a43c1f9d9ae 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas use crate::hir::{ AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, - ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind, + ItemId, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -16,7 +16,6 @@ pub trait HashStableContext: fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher); fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher); fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher); - fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher); fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher); fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher); @@ -132,12 +131,6 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId { } } -impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Mod<'_> { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_hir_mod(self, hasher) - } -} - impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { hcx.hash_hir_expr(self, hasher) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fb11aaf24c4..4c9e2d7fe42 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -358,7 +358,7 @@ impl<'a> State<'a> { self.word("["); self.print_type(&ty); self.word("; "); - self.print_anon_const(length); + self.print_array_length(length); self.word("]"); } hir::TyKind::Typeof(ref e) => { @@ -1065,6 +1065,13 @@ impl<'a> State<'a> { self.print_else(elseopt) } + pub fn print_array_length(&mut self, len: &hir::ArrayLen) { + match len { + hir::ArrayLen::Infer(_, _) => self.word("_"), + hir::ArrayLen::Body(ct) => self.print_anon_const(ct), + } + } + pub fn print_anon_const(&mut self, constant: &hir::AnonConst) { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1140,12 +1147,12 @@ impl<'a> State<'a> { self.end() } - fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) { + fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) { self.ibox(INDENT_UNIT); self.word("["); self.print_expr(element); self.word_space(";"); - self.print_anon_const(count); + self.print_array_length(count); self.word("]"); self.end() } @@ -1874,7 +1881,11 @@ impl<'a> State<'a> { PatKind::Struct(ref qpath, ref fields, etc) => { self.print_qpath(qpath, true); self.nbsp(); - self.word_space("{"); + self.word("{"); + let empty = fields.is_empty() && !etc; + if !empty { + self.space(); + } self.commasep_cmnt( Consistent, &fields, @@ -1895,7 +1906,9 @@ impl<'a> State<'a> { } self.word(".."); } - self.space(); + if !empty { + self.space(); + } self.word("}"); } PatKind::Or(ref pats) => { diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 7ac00b4609a..88795679943 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -9,6 +9,13 @@ //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the //! fingerprints must be the SAME (along with all other fingerprints). //! +//! - `#[rustc_clean(cfg="rev2", loaded_from_disk='typeck")]` asserts that +//! the query result for `DepNode::typeck(X)` was actually +//! loaded from disk (not just marked green). This can be useful +//! to ensure that a test is actually exercising the deserialization +//! logic for a particular query result. This can be combined with +//! `except` +//! //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. @@ -28,6 +35,7 @@ use rustc_span::Span; use std::iter::FromIterator; use std::vec::Vec; +const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk; const EXCEPT: Symbol = sym::except; const CFG: Symbol = sym::cfg; @@ -124,6 +132,7 @@ type Labels = FxHashSet<String>; struct Assertion { clean: Labels, dirty: Labels, + loaded_from_disk: Labels, } pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { @@ -174,6 +183,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion { let (name, mut auto) = self.auto_labels(item_id, attr); let except = self.except(attr); + let loaded_from_disk = self.loaded_from_disk(attr); for e in except.iter() { if !auto.remove(e) { let msg = format!( @@ -183,7 +193,19 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { self.tcx.sess.span_fatal(attr.span, &msg); } } - Assertion { clean: auto, dirty: except } + Assertion { clean: auto, dirty: except, loaded_from_disk } + } + + /// `loaded_from_disk=` attribute value + fn loaded_from_disk(&self, attr: &Attribute) -> Labels { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.has_name(LOADED_FROM_DISK) { + let value = expect_associated_value(self.tcx, &item); + return self.resolve_labels(&item, value); + } + } + // If `loaded_from_disk=` is not specified, don't assert anything + Labels::default() } /// `except=` attribute value @@ -332,6 +354,18 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { } } + fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) { + debug!("assert_loaded_from_disk({:?})", dep_node); + + if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) { + let dep_node_str = self.dep_node_str(&dep_node); + self.tcx.sess.span_err( + item_span, + &format!("`{}` should have been loaded from disk but it was not", dep_node_str), + ); + } + } + fn check_item(&mut self, item_id: LocalDefId, item_span: Span) { let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() { @@ -348,6 +382,10 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_dirty(item_span, dep_node); } + for label in assertion.loaded_from_disk { + let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); + self.assert_loaded_from_disk(item_span, dep_node); + } } } } @@ -382,7 +420,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); - } else if !item.has_name(EXCEPT) { + } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty())); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9a76c05e4f6..f0c73d0c2f3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2041,11 +2041,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) = trace.values { - // If a tuple of length one was expected and the found expression has - // parentheses around it, perhaps the user meant to write `(expr,)` to - // build a tuple (issue #86100) match (expected.kind(), found.kind()) { (ty::Tuple(_), ty::Tuple(_)) => {} + // If a tuple of length one was expected and the found expression has + // parentheses around it, perhaps the user meant to write `(expr,)` to + // build a tuple (issue #86100) (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => { if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { if let Some(code) = @@ -2060,6 +2060,41 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } + // If a character was expected and the found expression is a string literal + // containing a single character, perhaps the user meant to write `'c'` to + // specify a character literal (issue #92479) + (ty::Char, ty::Ref(_, r, _)) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) + { + if code.chars().nth(1).is_none() { + err.span_suggestion( + span, + "if you meant to write a `char` literal, use single quotes", + format!("'{}'", code), + Applicability::MachineApplicable, + ); + } + } + } + } + // If a string was expected and the found expression is a character literal, + // perhaps the user meant to write `"s"` to specify a string literal. + (ty::Ref(_, r, _), ty::Char) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + { + err.span_suggestion( + span, + "if you meant to write a `str` literal, use double quotes", + format!("\"{}\"", code), + Applicability::MachineApplicable, + ); + } + } + } _ => {} } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 025a0ee376e..2a0f4fdc774 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -979,11 +979,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, - int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, + uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( unwrap(V), unwrap<DILocalVariable>(VarInfo), - Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)), + Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd))); } @@ -1057,11 +1057,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, return wrap(Loc); } -extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() { return dwarf::DW_OP_deref; } -extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 66e6b571beb..3351564299c 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -1,6 +1,7 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, quote_spanned}; use syn::parse_quote; +use syn::spanned::Spanned; pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; @@ -104,6 +105,8 @@ fn decodable_body( } fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream { + let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span()); + let decode_inner_method = if let syn::Type::Reference(_) = field.ty { quote! { ::rustc_middle::ty::codec::RefDecodable::decode } } else { @@ -111,20 +114,21 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro }; let (decode_method, opt_field_name) = if is_struct { let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string()); - ( - proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()), - quote! { #field_name, }, - ) + (proc_macro2::Ident::new("read_struct_field", field_span), quote! { #field_name, }) } else { - ( - proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()), - quote! {}, - ) + (proc_macro2::Ident::new("read_enum_variant_arg", field_span), quote! {}) + }; + + let __decoder = quote! { __decoder }; + // Use the span of the field for the method call, so + // that backtraces will point to the field. + let decode_call = quote_spanned! {field_span=> + ::rustc_serialize::Decoder::#decode_method( + #__decoder, #opt_field_name #decode_inner_method) }; quote! { - match ::rustc_serialize::Decoder::#decode_method( - __decoder, #opt_field_name #decode_inner_method) { + match #decode_call { ::std::result::Result::Ok(__res) => __res, ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f8d3fb6c48d..a9db8469384 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -10,7 +10,7 @@ doctest = false rustc_arena = { path = "../rustc_arena" } bitflags = "1.2.1" either = "1.5.0" -gsgdt = "0.1.3" +gsgdt = "0.1.2" tracing = "0.1" rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index 44d0ce935df..770b52a4d4b 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -55,7 +55,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); stmts.push(terminator_head); - Node::from_list(stmts, label, title, style) + Node::new(stmts, label, title, style) } // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c7c306e7d06..52ef380001c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2336,8 +2336,6 @@ pub enum NullOp { SizeOf, /// Returns the minimum alignment of a type AlignOf, - /// Creates a new uninitialized box for a value of that type - Box, } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index e577df48205..dc53dc8de9d 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -195,7 +195,6 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), @@ -215,9 +214,7 @@ impl<'tcx> Rvalue<'tcx> { /// whether its only shallowly initialized (`Rvalue::Box`). pub fn initialization_state(&self) -> RvalueInitializationState { match *self { - Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => { - RvalueInitializationState::Shallow - } + Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, _ => RvalueInitializationState::Deep, } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 092fe131174..bdde6b4a356 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -583,9 +583,12 @@ impl<'tcx> Cx<'tcx> { ExprKind::ConstBlock { value } } // Now comes the rote stuff: - hir::ExprKind::Repeat(ref v, ref count) => { - let count_def_id = self.tcx.hir().local_def_id(count.hir_id); - let count = ty::Const::from_anon_const(self.tcx, count_def_id); + hir::ExprKind::Repeat(ref v, _) => { + let ty = self.typeck_results().expr_ty(expr); + let count = match ty.kind() { + ty::Array(_, ct) => ct, + _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty), + }; ExprKind::Repeat { value: self.mirror_expr(v), count } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index feb85d4ffdf..2e00b4f9a5e 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -343,19 +343,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) | Rvalue::Len(..) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) - | Rvalue::NullaryOp(NullOp::Box, _) => { - // This returns an rvalue with uninitialized contents. We can't - // move out of it here because it is an rvalue - assignments always - // completely initialize their place. - // - // However, this does not matter - MIR building is careful to - // only emit a shallow free for the partially-initialized - // temporary. - // - // In any case, if we want to fix this, we have to register a - // special move and change the `statement_effect` functions. - } + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 7e56e062fc9..e3ff6ad4549 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -239,13 +239,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("can't const prop heap allocations") - } - fn access_local( _ecx: &InterpCx<'mir, 'tcx, Self>, frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, @@ -413,7 +406,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Instance::new(def_id, substs), dummy_body, ret.as_ref(), - StackPopCleanup::None { cleanup: false }, + StackPopCleanup::Root { cleanup: false }, ) .expect("failed to push initial stack frame"); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b1fa9041342..b70c24b76d5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -688,15 +688,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => bug!(), } } - mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.tcx; - let exchange_malloc_fn_def_id = - tcx.require_lang_item(LangItem::ExchangeMalloc, None); - let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index a8be1ca34c0..7bc3fd718e0 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -88,6 +88,11 @@ struct DepGraphData<K: DepKind> { previous_work_products: FxHashMap<WorkProductId, WorkProduct>, dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>, + + /// Used by incremental compilation tests to assert that + /// a particular query result was decoded from disk + /// (not just marked green) + debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>, } pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint @@ -135,6 +140,7 @@ impl<K: DepKind> DepGraph<K> { processed_side_effects: Default::default(), previous: prev_graph, colors: DepNodeColorMap::new(prev_graph_node_count), + debug_loaded_from_disk: Default::default(), })), virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), } @@ -438,6 +444,14 @@ impl<K: DepKind> DepGraph<K> { &self.data.as_ref().unwrap().previous_work_products } + pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) { + self.data.as_ref().unwrap().debug_loaded_from_disk.lock().insert(dep_node); + } + + pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool { + self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) + } + #[inline(always)] pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F) where diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs index 3a0aab81fdb..3117140a5b6 100644 --- a/compiler/rustc_query_system/src/ich/impls_hir.rs +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -3,8 +3,7 @@ use crate::ich::hcx::BodyResolver; use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use std::mem; @@ -47,28 +46,6 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { }) } - #[inline] - fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { - let hcx = self; - let hir::Mod { inner: ref inner_span, ref item_ids } = *module; - - inner_span.hash_stable(hcx, hasher); - - // Combining the `DefPathHash`s directly is faster than feeding them - // into the hasher. Because we use a commutative combine, we also don't - // have to sort the array. - let item_ids_hash = item_ids - .iter() - .map(|id| { - let def_path_hash = id.to_stable_hash_key(hcx); - def_path_hash.0 - }) - .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b)); - - item_ids.len().hash_stable(hcx, hasher); - item_ids_hash.hash_stable(hcx, hasher); - } - fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) { self.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { hir_id: _, ref span, ref kind } = *expr; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index b08db39e245..33732f9df73 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -519,6 +519,10 @@ where prof_timer.finish_with_query_invocation_id(dep_node_index.into()); if let Some(result) = result { + if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) { + dep_graph.mark_debug_loaded_from_disk(*dep_node) + } + let prev_fingerprint = tcx .dep_context() .dep_graph() diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5098cef11e8..57305023138 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2379,7 +2379,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::While(ref cond, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { this.with_rib(ValueNS, NormalRibKind, |this| { + let old = this.diagnostic_metadata.in_if_condition.replace(cond); this.visit_expr(cond); + this.diagnostic_metadata.in_if_condition = old; this.visit_block(block); }) }); diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index f1a5282b088..23f5b17fa78 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -1326,12 +1326,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } intravisit::walk_qpath(self, path, t.hir_id, t.span); } - hir::TyKind::Array(ref ty, ref anon_const) => { + hir::TyKind::Array(ref ty, ref length) => { self.visit_ty(ty); let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { - v.visit_expr(&map.body(anon_const.body).value) - }); + match length { + // FIXME(generic_arg_infer): We probably want to + // output the inferred type here? :shrug: + hir::ArrayLen::Infer(..) => {} + hir::ArrayLen::Body(anon_const) => self + .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + v.visit_expr(&map.body(anon_const.body).value) + }), + } } hir::TyKind::OpaqueDef(item_id, _) => { let item = self.tcx.hir().item(item_id); @@ -1390,12 +1396,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { v.visit_expr(&body.value) }); } - hir::ExprKind::Repeat(ref expr, ref anon_const) => { + hir::ExprKind::Repeat(ref expr, ref length) => { self.visit_expr(expr); let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { - v.visit_expr(&map.body(anon_const.body).value) - }); + match length { + // FIXME(generic_arg_infer): We probably want to + // output the inferred type here? :shrug: + hir::ArrayLen::Infer(..) => {} + hir::ArrayLen::Body(anon_const) => self + .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + v.visit_expr(&map.body(anon_const.body).value) + }), + } } // In particular, we take this branch for call and path expressions, // where we'll index the idents involved just by continuing to walk. diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index e43344ad6d9..4971bb6d1aa 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -310,9 +310,9 @@ impl<'hir> Sig for hir::Ty<'hir> { let nested = bounds_to_string(&bounds); Ok(text_sig(nested)) } - hir::TyKind::Array(ref ty, ref anon_const) => { + hir::TyKind::Array(ref ty, ref length) => { let nested_ty = ty.make(offset + 1, id, scx)?; - let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " "); + let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " "); let text = format!("[{}; {}]", nested_ty.text, expr); Ok(replace_text(nested_ty, text)) } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index cc1216418ae..f2ef1481681 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -92,7 +92,8 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_u16(&mut self, v: u16) -> EncodeResult { - write_leb128!(self, v, u16, write_u16_leb128) + self.data.extend_from_slice(&v.to_le_bytes()); + Ok(()) } #[inline] @@ -123,7 +124,8 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_i16(&mut self, v: i16) -> EncodeResult { - write_leb128!(self, v, i16, write_i16_leb128) + self.data.extend_from_slice(&v.to_le_bytes()); + Ok(()) } #[inline] @@ -446,7 +448,7 @@ impl serialize::Encoder for FileEncoder { #[inline] fn emit_u16(&mut self, v: u16) -> FileEncodeResult { - file_encoder_write_leb128!(self, v, u16, write_u16_leb128) + self.write_all(&v.to_le_bytes()) } #[inline] @@ -476,13 +478,12 @@ impl serialize::Encoder for FileEncoder { #[inline] fn emit_i16(&mut self, v: i16) -> FileEncodeResult { - file_encoder_write_leb128!(self, v, i16, write_i16_leb128) + self.write_all(&v.to_le_bytes()) } #[inline] fn emit_i8(&mut self, v: i8) -> FileEncodeResult { - let as_u8: u8 = unsafe { std::mem::transmute(v) }; - self.emit_u8(as_u8) + self.emit_u8(v as u8) } #[inline] @@ -591,7 +592,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_u16(&mut self) -> Result<u16, Self::Error> { - read_leb128!(self, read_u16_leb128) + let bytes = [self.data[self.position], self.data[self.position + 1]]; + let value = u16::from_le_bytes(bytes); + self.position += 2; + Ok(value) } #[inline] @@ -623,7 +627,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_i16(&mut self) -> Result<i16, Self::Error> { - read_leb128!(self, read_i16_leb128) + let bytes = [self.data[self.position], self.data[self.position + 1]]; + let value = i16::from_le_bytes(bytes); + self.position += 2; + Ok(value) } #[inline] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 51a7a2644f6..84cf8878af8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -788,6 +788,7 @@ symbols! { literal, llvm_asm, load, + loaded_from_disk, local, local_inner_macros, log10f32, diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index caa5c71e21c..956696546da 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -104,7 +104,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }), GenericParamDefKind::Const { .. }, ) if tcx.type_of(param.def_id) == tcx.types.usize => { - let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id)); + let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id())); if let Ok(snippet) = snippet { err.span_suggestion( arg.span(), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8db706c3709..8226ffbccc4 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2363,8 +2363,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) } hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id(length.hir_id); - let length = ty::Const::from_anon_const(tcx, length_def_id); + let length = match length { + &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), + hir::ArrayLen::Body(constant) => { + let length_def_id = tcx.hir().local_def_id(constant.hir_id); + ty::Const::from_anon_const(tcx, length_def_id) + } + }; + let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8d370e440ea..621938c9b78 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1238,12 +1238,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, - count: &'tcx hir::AnonConst, + count: &'tcx hir::ArrayLen, expected: Expectation<'tcx>, _expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count = self.to_const(count); + let count = self.array_length_to_const(count); let uty = match expected { ExpectHasType(uty) => match *uty.kind() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 67630fd4e58..1aca2911533 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -498,6 +498,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> { + match length { + &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), + hir::ArrayLen::Body(anon_const) => self.to_const(anon_const), + } + } + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2fb5590016e..e1fef84d9d9 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -182,7 +182,7 @@ crate fn placeholder_type_error<'tcx>( sugg.push((span, format!(", {}", type_name))); } - let mut err = bad_placeholder_type(tcx, placeholder_types, kind); + let mut err = bad_placeholder(tcx, "type", placeholder_types, kind); // Suggest, but only if it is not a function in const or static if suggest { @@ -314,8 +314,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. -fn bad_placeholder_type<'tcx>( +fn bad_placeholder<'tcx>( tcx: TyCtxt<'tcx>, + placeholder_kind: &'static str, mut spans: Vec<Span>, kind: &'static str, ) -> rustc_errors::DiagnosticBuilder<'tcx> { @@ -326,7 +327,8 @@ fn bad_placeholder_type<'tcx>( tcx.sess, spans.clone(), E0121, - "the type placeholder `_` is not allowed within types on item signatures for {}", + "the {} placeholder `_` is not allowed within types on item signatures for {}", + placeholder_kind, kind ); for span in spans { @@ -393,7 +395,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { _: Option<&ty::GenericParamDef>, span: Span, ) -> &'tcx Const<'tcx> { - bad_placeholder_type(self.tcx(), vec![span], "generic").emit(); + bad_placeholder(self.tcx(), "const", vec![span], "generic").emit(); // Typeck doesn't expect erased regions to be returned from `type_of`. let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r { ty::ReErased => self.tcx.lifetimes.re_static, @@ -1482,7 +1484,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), // as they shouldn't be able to cause query cycle errors. Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - | Node::Variant(Variant { disr_expr: Some(ref constant), .. }) + if constant.hir_id() == hir_id => + { + Some(parent_def_id.to_def_id()) + } + Node::Variant(Variant { disr_expr: Some(ref constant), .. }) if constant.hir_id == hir_id => { Some(parent_def_id.to_def_id()) @@ -1788,7 +1794,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_ty(ty); - let mut diag = bad_placeholder_type(tcx, visitor.0, "return type"); + let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); if !ret_ty.references_error() { if !ret_ty.is_closure() { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 99fddcb00ce..04e887bf742 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -13,7 +13,7 @@ use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; use super::ItemCtxt; -use super::{bad_placeholder_type, is_suggestable_infer_ty}; +use super::{bad_placeholder, is_suggestable_infer_ty}; /// Computes the relevant generic parameter for a potential generic const argument. /// @@ -490,7 +490,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { match parent_node { Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id == hir_id => + if constant.hir_id() == hir_id => { tcx.types.usize } @@ -788,7 +788,7 @@ fn infer_placeholder_type<'a>( err.emit(); } None => { - let mut diag = bad_placeholder_type(tcx, vec![span], kind); + let mut diag = bad_placeholder(tcx, "type", vec![span], kind); if !ty.references_error() { let mut mk_nameable = MakeNameable::new(tcx); diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 66ef92558d8..d075658f51a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -323,17 +323,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. // For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`, // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well. -pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) { +pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Drop>( + ptr: Unique<T>, + alloc: A, +) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); let layout = Layout::from_size_align_unchecked(size, align); - alloc.deallocate(ptr.cast().into(), layout) + alloc.deallocate(From::from(ptr.cast()), layout) } } @@ -361,13 +365,22 @@ extern "Rust" { /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] +#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[cfg(all(not(no_global_oom_handling), not(test)))] #[rustc_allocator_nounwind] #[cold] -pub fn handle_alloc_error(layout: Layout) -> ! { - unsafe { - __rust_alloc_error_handler(layout.size(), layout.align()); +pub const fn handle_alloc_error(layout: Layout) -> ! { + const fn ct_error(_: Layout) -> ! { + panic!("allocation failed"); } + + fn rt_error(layout: Layout) -> ! { + unsafe { + __rust_alloc_error_handler(layout.size(), layout.align()); + } + } + + unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } } // For alloc test `std::alloc::handle_alloc_error` can be used directly. diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ab41f5646e5..aa7344ba405 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -346,9 +346,13 @@ impl<T, A: Allocator> Box<T, A> { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[must_use] #[inline] - pub fn new_in(x: T, alloc: A) -> Self { + pub const fn new_in(x: T, alloc: A) -> Self + where + A: ~const Allocator + ~const Drop, + { let mut boxed = Self::new_uninit_in(alloc); unsafe { boxed.as_mut_ptr().write(x); @@ -372,8 +376,13 @@ impl<T, A: Allocator> Box<T, A> { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> { + pub const fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> + where + T: ~const Drop, + A: ~const Allocator + ~const Drop, + { let mut boxed = Self::try_new_uninit_in(alloc)?; unsafe { boxed.as_mut_ptr().write(x); @@ -402,10 +411,14 @@ impl<T, A: Allocator> Box<T, A> { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[cfg(not(no_global_oom_handling))] #[must_use] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> { + pub const fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::<mem::MaybeUninit<T>>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -439,7 +452,11 @@ impl<T, A: Allocator> Box<T, A> { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> { + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::<mem::MaybeUninit<T>>(); let ptr = alloc.allocate(layout)?.cast(); unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } @@ -466,10 +483,14 @@ impl<T, A: Allocator> Box<T, A> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[cfg(not(no_global_oom_handling))] // #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] - pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> { + pub const fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::<mem::MaybeUninit<T>>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -503,7 +524,11 @@ impl<T, A: Allocator> Box<T, A> { /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> { + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::<mem::MaybeUninit<T>>(); let ptr = alloc.allocate_zeroed(layout)?.cast(); unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } @@ -513,20 +538,22 @@ impl<T, A: Allocator> Box<T, A> { /// `x` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[must_use] #[inline(always)] - pub fn pin_in(x: T, alloc: A) -> Pin<Self> + pub const fn pin_in(x: T, alloc: A) -> Pin<Self> where - A: 'static, + A: 'static + ~const Allocator + ~const Drop, { - Self::new_in(x, alloc).into() + Self::into_pin(Self::new_in(x, alloc)) } /// Converts a `Box<T>` into a `Box<[T]>` /// /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] - pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> { let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } } @@ -543,8 +570,12 @@ impl<T, A: Allocator> Box<T, A> { /// assert_eq!(Box::into_inner(c), 5); /// ``` #[unstable(feature = "box_into_inner", issue = "80437")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn into_inner(boxed: Self) -> T { + pub const fn into_inner(boxed: Self) -> T + where + Self: ~const Drop, + { *boxed } } @@ -758,8 +789,9 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub unsafe fn assume_init(self) -> Box<T, A> { + pub const unsafe fn assume_init(self) -> Box<T, A> { let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut T, alloc) } } @@ -792,8 +824,9 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { /// } /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn write(mut boxed: Self, value: T) -> Box<T, A> { + pub const fn write(mut boxed: Self, value: T) -> Box<T, A> { unsafe { (*boxed).write(value); boxed.assume_init() @@ -938,8 +971,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// [memory layout]: self#memory-layout /// [`Layout`]: crate::Layout #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { Box(unsafe { Unique::new_unchecked(raw) }, alloc) } @@ -1035,8 +1069,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { + pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); (leaked.as_ptr(), alloc) } @@ -1046,9 +1081,10 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { issue = "none", reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead" )] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] #[doc(hidden)] - pub fn into_unique(b: Self) -> (Unique<T>, A) { + pub const fn into_unique(b: Self) -> (Unique<T>, A) { // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a // raw pointer for the type system. Turning it directly into a raw pointer would not be // recognized as "releasing" the unique pointer to permit aliased raw accesses, @@ -1064,8 +1100,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn allocator(b: &Self) -> &A { + pub const fn allocator(b: &Self) -> &A { &b.1 } @@ -1105,8 +1142,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// assert_eq!(*static_ref, [4, 2, 3]); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn leak<'a>(b: Self) -> &'a mut T + pub const fn leak<'a>(b: Self) -> &'a mut T where A: 'a, { @@ -1119,7 +1157,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// /// This is also available via [`From`]. #[unstable(feature = "box_into_pin", issue = "62370")] - pub fn into_pin(boxed: Self) -> Pin<Self> + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn into_pin(boxed: Self) -> Pin<Self> where A: 'static, { @@ -1131,7 +1170,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> { +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. } @@ -1341,7 +1381,8 @@ impl<T> From<T> for Box<T> { } #[stable(feature = "pin", since = "1.33.0")] -impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>> +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>> where A: 'static, { @@ -1720,7 +1761,8 @@ impl<T: ?Sized, A: Allocator> fmt::Pointer for Box<T, A> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized, A: Allocator> Deref for Box<T, A> { +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> { type Target = T; fn deref(&self) -> &T { @@ -1729,7 +1771,8 @@ impl<T: ?Sized, A: Allocator> Deref for Box<T, A> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> { +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl<T: ?Sized, A: Allocator> const DerefMut for Box<T, A> { fn deref_mut(&mut self) -> &mut T { &mut **self } @@ -1908,7 +1951,8 @@ impl<T: ?Sized, A: Allocator> AsMut<T> for Box<T, A> { * could have a method to project a Pin<T> from it. */ #[stable(feature = "pin", since = "1.33.0")] -impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {} +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl<T: ?Sized, A: Allocator> const Unpin for Box<T, A> where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A> diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 600862c4224..7e663fab16a 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -96,9 +96,20 @@ #![feature(array_windows)] #![feature(async_stream)] #![feature(coerce_unsized)] +#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] +#![feature(const_box)] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] #![feature(const_cow_is_borrowed)] +#![feature(const_convert)] +#![feature(const_size_of_val)] +#![feature(const_align_of_val)] +#![feature(const_ptr_read)] +#![feature(const_maybe_uninit_write)] +#![feature(const_maybe_uninit_as_mut_ptr)] +#![feature(const_refs_to_cell)] #![feature(core_intrinsics)] +#![feature(const_eval_select)] +#![feature(const_pin)] #![feature(dispatch_from_dyn)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -134,8 +145,13 @@ #![feature(box_syntax)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] +#![feature(const_deref)] #![feature(const_fn_trait_bound)] +#![feature(const_mut_refs)] +#![feature(const_ptr_write)] +#![feature(const_precise_live_drops)] #![feature(const_trait_impl)] +#![feature(const_try)] #![cfg_attr(bootstrap, feature(destructuring_assignment))] #![feature(dropck_eyepatch)] #![feature(exclusive_range_pattern)] diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index bfe66b2687e..0d7acfed8c6 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -1,6 +1,7 @@ -use std::cell::Cell; -use std::mem::MaybeUninit; -use std::ptr::NonNull; +use core::alloc::{AllocError, Allocator, Layout}; +use core::cell::Cell; +use core::mem::MaybeUninit; +use core::ptr::NonNull; #[test] fn uninitialized_zero_size_box() { @@ -57,3 +58,110 @@ fn box_deref_lval() { x.set(1000); assert_eq!(x.get(), 1000); } + +pub struct ConstAllocator; + +unsafe impl const Allocator for ConstAllocator { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + _ => unsafe { + let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); + Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) + }, + } + } + + unsafe fn deallocate(&self, _ptr: NonNull<u8>, layout: Layout) { + match layout.size() { + 0 => { /* do nothing */ } + _ => { /* do nothing too */ } + } + } + + fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + let ptr = self.allocate(layout)?; + if layout.size() > 0 { + unsafe { + ptr.as_mut_ptr().write_bytes(0, layout.size()); + } + } + Ok(ptr) + } + + unsafe fn grow( + &self, + ptr: NonNull<u8>, + old_layout: Layout, + new_layout: Layout, + ) -> Result<NonNull<[u8]>, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + + unsafe fn grow_zeroed( + &self, + ptr: NonNull<u8>, + old_layout: Layout, + new_layout: Layout, + ) -> Result<NonNull<[u8]>, AllocError> { + let new_ptr = self.grow(ptr, old_layout, new_layout)?; + if new_layout.size() > 0 { + let old_size = old_layout.size(); + let new_size = new_layout.size(); + let raw_ptr = new_ptr.as_mut_ptr(); + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } + Ok(new_ptr) + } + + unsafe fn shrink( + &self, + ptr: NonNull<u8>, + old_layout: Layout, + new_layout: Layout, + ) -> Result<NonNull<[u8]>, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + + fn by_ref(&self) -> &Self + where + Self: Sized, + { + self + } +} + +#[test] +fn const_box() { + const VALUE: u32 = { + let mut boxed = Box::new_in(1u32, ConstAllocator); + assert!(*boxed == 1); + + *boxed = 42; + assert!(*boxed == 42); + + *boxed + }; + + assert!(VALUE == 42); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 68e48348b07..eec24a5c3f7 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,8 +1,19 @@ #![feature(allocator_api)] +#![feature(alloc_layout_extra)] #![feature(assert_matches)] #![feature(box_syntax)] #![feature(cow_is_borrowed)] +#![feature(const_box)] +#![feature(const_convert)] #![feature(const_cow_is_borrowed)] +#![feature(const_heap)] +#![feature(const_intrinsic_copy)] +#![feature(const_mut_refs)] +#![feature(const_nonnull_slice_from_raw_parts)] +#![feature(const_ptr_offset)] +#![feature(const_ptr_write)] +#![feature(const_try)] +#![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] @@ -26,6 +37,7 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(const_str_from_utf8)] +#![feature(nonnull_slice_from_raw_parts)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 6fc3cd0b7c4..8a2a64f8dc9 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -570,11 +570,30 @@ impl Display for Arguments<'_> { /// There are a number of helper methods on the [`Formatter`] struct to help you with manual /// implementations, such as [`debug_struct`]. /// +/// [`debug_struct`]: Formatter::debug_struct +/// +/// Types that do not wish to use the standard suite of debug representations +/// provided by the `Formatter` trait (`debug_struct`, `debug_tuple`, +/// `debut_list`, `debug_set`, `debug_map`) can do something totally custom by +/// manually writing an arbitrary representation to the `Formatter`. +/// +/// ``` +/// # use std::fmt; +/// # struct Point { +/// # x: i32, +/// # y: i32, +/// # } +/// # +/// impl fmt::Debug for Point { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "Point [{} {}]", self.x, self.y) +/// } +/// } +/// ``` +/// /// `Debug` implementations using either `derive` or the debug builder API /// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`. /// -/// [`debug_struct`]: Formatter::debug_struct -/// /// Pretty-printing with `#?`: /// /// ``` diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d9389892c0c..d8f6c85e428 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -866,7 +866,6 @@ pub(crate) mod builtin { language use and is subject to change" )] #[allow_internal_unstable(fmt_internals)] - #[doc(hidden)] #[rustc_builtin_macro] #[macro_export] macro_rules! format_args_nl { @@ -1428,6 +1427,10 @@ pub(crate) mod builtin { } /// Attribute macro used to apply derive macros. + /// + /// See [the reference] for more info. + /// + /// [the reference]: ../../../reference/attributes/derive.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] pub macro derive($item:item) { @@ -1435,6 +1438,10 @@ pub(crate) mod builtin { } /// Attribute macro applied to a function to turn it into a unit test. + /// + /// See [the reference] for more info. + /// + /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] @@ -1469,7 +1476,7 @@ pub(crate) mod builtin { /// Attribute macro applied to a static to register it as a global allocator. /// - /// See also [`std::alloc::GlobalAlloc`](../std/alloc/trait.GlobalAlloc.html). + /// See also [`std::alloc::GlobalAlloc`](../../../std/alloc/trait.GlobalAlloc.html). #[stable(feature = "global_allocator", since = "1.28.0")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] @@ -1507,6 +1514,7 @@ pub(crate) mod builtin { since = "1.52.0", reason = "rustc-serialize is deprecated and no longer supported" )] + #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcDecodable($item:item) { /* compiler built-in */ } @@ -1519,6 +1527,7 @@ pub(crate) mod builtin { since = "1.52.0", reason = "rustc-serialize is deprecated and no longer supported" )] + #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcEncodable($item:item) { /* compiler built-in */ } diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs index 483362023b2..a920b9165c1 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -68,7 +68,38 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} -/// This is used for object safety, to check that a method's receiver type can be dispatched on. +/// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing +/// arbitrary self types), to guarantee that a method's receiver type can be dispatched on. +/// +/// Note: `DispatchFromDyn` was briefly named `CoerceSized` (and had a slightly different +/// interpretation). +/// +/// Imagine we have a trait object `t` with type `&dyn Tr`, where `Tr` is some trait with a method +/// `m` defined as `fn m(&self);`. When calling `t.m()`, the receiver `t` is a wide pointer, but an +/// implementation of `m` will expect a narrow pointer as `&self` (a reference to the concrete +/// type). The compiler must generate an implicit conversion from the trait object/wide pointer to +/// the concrete reference/narrow pointer. Implementing `DispatchFromDyn` indicates that that +/// conversion is allowed and thus that the type implementing `DispatchFromDyn` is safe to use as +/// the self type in an object-safe method. (in the above example, the compiler will require +/// `DispatchFromDyn` is implemented for `&'a U`). +/// +/// `DispatchFromDyn` does not specify the conversion from wide pointer to narrow pointer; the +/// conversion is hard-wired into the compiler. For the conversion to work, the following +/// properties must hold (i.e., it is only safe to implement `DispatchFromDyn` for types which have +/// these properties, these are also checked by the compiler): +/// +/// * EITHER `Self` and `T` are either both references or both raw pointers; in either case, with +/// the same mutability. +/// * OR, all of the following hold +/// - `Self` and `T` must have the same type constructor, and only vary in a single type parameter +/// formal (the *coerced type*, e.g., `impl DispatchFromDyn<Rc<T>> for Rc<U>` is ok and the +/// single type parameter (instantiated with `T` or `U`) is the coerced type, +/// `impl DispatchFromDyn<Arc<T>> for Rc<U>` is not ok). +/// - The definition for `Self` must be a struct. +/// - The definition for `Self` must not be `#[repr(packed)]` or `#[repr(C)]`. +/// - Other than one-aligned, zero-sized fields, the definition for `Self` must have exactly one +/// field and that field's type must be the coerced type. Furthermore, `Self`'s field type must +/// implement `DispatchFromDyn<F>` where `F` is the type of `T`'s field type. /// /// An example implementation of the trait: /// diff --git a/library/core/src/option.rs b/library/core/src/option.rs index e6312b8b2d9..1ec119a71e4 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -571,36 +571,6 @@ impl<T> Option<T> { !self.is_some() } - /// Returns `true` if the option is a [`Some`] value containing the given value. - /// - /// # Examples - /// - /// ``` - /// #![feature(option_result_contains)] - /// - /// let x: Option<u32> = Some(2); - /// assert_eq!(x.contains(&2), true); - /// - /// let x: Option<u32> = Some(3); - /// assert_eq!(x.contains(&2), false); - /// - /// let x: Option<u32> = None; - /// assert_eq!(x.contains(&2), false); - /// ``` - #[must_use] - #[inline] - #[unstable(feature = "option_result_contains", issue = "62358")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] - pub const fn contains<U>(&self, x: &U) -> bool - where - U: ~const PartialEq<T>, - { - match self { - Some(y) => x.eq(y), - None => false, - } - } - ///////////////////////////////////////////////////////////////////////// // Adapter for working with references ///////////////////////////////////////////////////////////////////////// @@ -810,6 +780,45 @@ impl<T> Option<T> { } } + /// Returns the contained [`Some`] value or a default. + /// + /// Consumes the `self` argument then, if [`Some`], returns the contained + /// value, otherwise if [`None`], returns the [default value] for that + /// type. + /// + /// # Examples + /// + /// Converts a string to an integer, turning poorly-formed strings + /// into 0 (the default value for integers). [`parse`] converts + /// a string to any other type that implements [`FromStr`], returning + /// [`None`] on error. + /// + /// ``` + /// let good_year_from_input = "1909"; + /// let bad_year_from_input = "190blarg"; + /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); + /// + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); + /// ``` + /// + /// [default value]: Default::default + /// [`parse`]: str::parse + /// [`FromStr`]: crate::str::FromStr + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn unwrap_or_default(self) -> T + where + T: ~const Default, + { + match self { + Some(x) => x, + None => Default::default(), + } + } + /// Returns the contained [`Some`] value, consuming the `self` value, /// without checking that the value is not [`None`]. /// @@ -1033,6 +1042,58 @@ impl<T> Option<T> { } } + /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`. + /// + /// Leaves the original Option in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via [`Deref`]. + /// + /// # Examples + /// + /// ``` + /// let x: Option<String> = Some("hey".to_owned()); + /// assert_eq!(x.as_deref(), Some("hey")); + /// + /// let x: Option<String> = None; + /// assert_eq!(x.as_deref(), None); + /// ``` + #[stable(feature = "option_deref", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn as_deref(&self) -> Option<&T::Target> + where + T: ~const Deref, + { + match self.as_ref() { + Some(t) => Some(t.deref()), + None => None, + } + } + + /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`. + /// + /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to + /// the inner type's [`Deref::Target`] type. + /// + /// # Examples + /// + /// ``` + /// let mut x: Option<String> = Some("hey".to_owned()); + /// assert_eq!(x.as_deref_mut().map(|x| { + /// x.make_ascii_uppercase(); + /// x + /// }), Some("HEY".to_owned().as_mut_str())); + /// ``` + #[stable(feature = "option_deref", since = "1.40.0")] + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target> + where + T: ~const DerefMut, + { + match self.as_mut() { + Some(t) => Some(t.deref_mut()), + None => None, + } + } + ///////////////////////////////////////////////////////////////////////// // Iterator constructors ///////////////////////////////////////////////////////////////////////// @@ -1482,6 +1543,36 @@ impl<T> Option<T> { mem::replace(self, Some(value)) } + /// Returns `true` if the option is a [`Some`] value containing the given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_contains)] + /// + /// let x: Option<u32> = Some(2); + /// assert_eq!(x.contains(&2), true); + /// + /// let x: Option<u32> = Some(3); + /// assert_eq!(x.contains(&2), false); + /// + /// let x: Option<u32> = None; + /// assert_eq!(x.contains(&2), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "option_result_contains", issue = "62358")] + #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + pub const fn contains<U>(&self, x: &U) -> bool + where + U: ~const PartialEq<T>, + { + match self { + Some(y) => x.eq(y), + None => false, + } + } + /// Zips `self` with another `Option`. /// /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`. @@ -1581,7 +1672,7 @@ impl<T, U> Option<(T, U)> { } } -impl<T: Copy> Option<&T> { +impl<T> Option<&T> { /// Maps an `Option<&T>` to an `Option<T>` by copying the contents of the /// option. /// @@ -1597,7 +1688,10 @@ impl<T: Copy> Option<&T> { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "copied", since = "1.35.0")] #[rustc_const_unstable(feature = "const_option", issue = "67441")] - pub const fn copied(self) -> Option<T> { + pub const fn copied(self) -> Option<T> + where + T: Copy, + { // FIXME: this implementation, which sidesteps using `Option::map` since it's not const // ready yet, should be reverted when possible to avoid code repetition match self { @@ -1605,33 +1699,7 @@ impl<T: Copy> Option<&T> { None => None, } } -} - -impl<T: Copy> Option<&mut T> { - /// Maps an `Option<&mut T>` to an `Option<T>` by copying the contents of the - /// option. - /// - /// # Examples - /// - /// ``` - /// let mut x = 12; - /// let opt_x = Some(&mut x); - /// assert_eq!(opt_x, Some(&mut 12)); - /// let copied = opt_x.copied(); - /// assert_eq!(copied, Some(12)); - /// ``` - #[must_use = "`self` will be dropped if the result is not used"] - #[stable(feature = "copied", since = "1.35.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] - pub const fn copied(self) -> Option<T> { - match self { - Some(&mut t) => Some(t), - None => None, - } - } -} -impl<T: Clone> Option<&T> { /// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the /// option. /// @@ -1658,8 +1726,8 @@ impl<T: Clone> Option<&T> { } } -impl<T: Clone> Option<&mut T> { - /// Maps an `Option<&mut T>` to an `Option<T>` by cloning the contents of the +impl<T> Option<&mut T> { + /// Maps an `Option<&mut T>` to an `Option<T>` by copying the contents of the /// option. /// /// # Examples @@ -1668,115 +1736,43 @@ impl<T: Clone> Option<&mut T> { /// let mut x = 12; /// let opt_x = Some(&mut x); /// assert_eq!(opt_x, Some(&mut 12)); - /// let cloned = opt_x.cloned(); - /// assert_eq!(cloned, Some(12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, Some(12)); /// ``` #[must_use = "`self` will be dropped if the result is not used"] - #[stable(since = "1.26.0", feature = "option_ref_mut_cloned")] - #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")] - pub const fn cloned(self) -> Option<T> - where - T: ~const Clone, - { - match self { - Some(t) => Some(t.clone()), - None => None, - } - } -} - -impl<T: Default> Option<T> { - /// Returns the contained [`Some`] value or a default. - /// - /// Consumes the `self` argument then, if [`Some`], returns the contained - /// value, otherwise if [`None`], returns the [default value] for that - /// type. - /// - /// # Examples - /// - /// Converts a string to an integer, turning poorly-formed strings - /// into 0 (the default value for integers). [`parse`] converts - /// a string to any other type that implements [`FromStr`], returning - /// [`None`] on error. - /// - /// ``` - /// let good_year_from_input = "1909"; - /// let bad_year_from_input = "190blarg"; - /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); - /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); - /// - /// assert_eq!(1909, good_year); - /// assert_eq!(0, bad_year); - /// ``` - /// - /// [default value]: Default::default - /// [`parse`]: str::parse - /// [`FromStr`]: crate::str::FromStr - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] + #[stable(feature = "copied", since = "1.35.0")] #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] - pub const fn unwrap_or_default(self) -> T + pub const fn copied(self) -> Option<T> where - T: ~const Default, + T: Copy, { match self { - Some(x) => x, - None => Default::default(), - } - } -} - -impl<T: Deref> Option<T> { - /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`. - /// - /// Leaves the original Option in-place, creating a new one with a reference - /// to the original one, additionally coercing the contents via [`Deref`]. - /// - /// # Examples - /// - /// ``` - /// let x: Option<String> = Some("hey".to_owned()); - /// assert_eq!(x.as_deref(), Some("hey")); - /// - /// let x: Option<String> = None; - /// assert_eq!(x.as_deref(), None); - /// ``` - #[stable(feature = "option_deref", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] - pub const fn as_deref(&self) -> Option<&T::Target> - where - T: ~const Deref, - { - match self.as_ref() { - Some(t) => Some(t.deref()), + Some(&mut t) => Some(t), None => None, } } -} -impl<T: DerefMut> Option<T> { - /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`. - /// - /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to - /// the inner type's [`Deref::Target`] type. + /// Maps an `Option<&mut T>` to an `Option<T>` by cloning the contents of the + /// option. /// /// # Examples /// /// ``` - /// let mut x: Option<String> = Some("hey".to_owned()); - /// assert_eq!(x.as_deref_mut().map(|x| { - /// x.make_ascii_uppercase(); - /// x - /// }), Some("HEY".to_owned().as_mut_str())); + /// let mut x = 12; + /// let opt_x = Some(&mut x); + /// assert_eq!(opt_x, Some(&mut 12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, Some(12)); /// ``` - #[stable(feature = "option_deref", since = "1.40.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] - pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target> + #[must_use = "`self` will be dropped if the result is not used"] + #[stable(since = "1.26.0", feature = "option_ref_mut_cloned")] + #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")] + pub const fn cloned(self) -> Option<T> where - T: ~const DerefMut, + T: ~const Clone, { - match self.as_mut() { - Some(t) => Some(t.deref_mut()), + match self { + Some(t) => Some(t.clone()), None => None, } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 54f498d1dc1..0fb8846288b 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -69,23 +69,21 @@ pub use crate::{ #[doc(no_inline)] pub use crate::concat_bytes; +// Do not `doc(inline)` these `doc(hidden)` items. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated, deprecated_in_future)] -#[doc(no_inline)] -pub use crate::macros::builtin::{ - bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable, -}; +#[allow(deprecated)] +pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; +// Do not `doc(no_inline)` so that they become doc items on their own +// (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[doc(no_inline)] -pub use crate::macros::builtin::derive; +pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case}; #[unstable( feature = "cfg_accessible", issue = "64797", reason = "`cfg_accessible` is not fully implemented" )] -#[doc(no_inline)] pub use crate::macros::builtin::cfg_accessible; #[unstable( @@ -93,5 +91,4 @@ pub use crate::macros::builtin::cfg_accessible; issue = "82679", reason = "`cfg_eval` is a recently implemented feature" )] -#[doc(no_inline)] pub use crate::macros::builtin::cfg_eval; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 3cde63493d3..504a01813ac 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -563,64 +563,6 @@ impl<T, E> Result<T, E> { !self.is_ok() } - /// Returns `true` if the result is an [`Ok`] value containing the given value. - /// - /// # Examples - /// - /// ``` - /// #![feature(option_result_contains)] - /// - /// let x: Result<u32, &str> = Ok(2); - /// assert_eq!(x.contains(&2), true); - /// - /// let x: Result<u32, &str> = Ok(3); - /// assert_eq!(x.contains(&2), false); - /// - /// let x: Result<u32, &str> = Err("Some error message"); - /// assert_eq!(x.contains(&2), false); - /// ``` - #[must_use] - #[inline] - #[unstable(feature = "option_result_contains", issue = "62358")] - pub fn contains<U>(&self, x: &U) -> bool - where - U: PartialEq<T>, - { - match self { - Ok(y) => x == y, - Err(_) => false, - } - } - - /// Returns `true` if the result is an [`Err`] value containing the given value. - /// - /// # Examples - /// - /// ``` - /// #![feature(result_contains_err)] - /// - /// let x: Result<u32, &str> = Ok(2); - /// assert_eq!(x.contains_err(&"Some error message"), false); - /// - /// let x: Result<u32, &str> = Err("Some error message"); - /// assert_eq!(x.contains_err(&"Some error message"), true); - /// - /// let x: Result<u32, &str> = Err("Some other error message"); - /// assert_eq!(x.contains_err(&"Some error message"), false); - /// ``` - #[must_use] - #[inline] - #[unstable(feature = "result_contains_err", issue = "62358")] - pub fn contains_err<F>(&self, f: &F) -> bool - where - F: PartialEq<E>, - { - match self { - Ok(_) => false, - Err(e) => f == e, - } - } - ///////////////////////////////////////////////////////////////////////// // Adapter for each variant ///////////////////////////////////////////////////////////////////////// @@ -901,6 +843,56 @@ impl<T, E> Result<T, E> { self } + /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`. + /// + /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref) + /// and returns the new [`Result`]. + /// + /// # Examples + /// + /// ``` + /// let x: Result<String, u32> = Ok("hello".to_string()); + /// let y: Result<&str, &u32> = Ok("hello"); + /// assert_eq!(x.as_deref(), y); + /// + /// let x: Result<String, u32> = Err(42); + /// let y: Result<&str, &u32> = Err(&42); + /// assert_eq!(x.as_deref(), y); + /// ``` + #[stable(feature = "inner_deref", since = "1.47.0")] + pub fn as_deref(&self) -> Result<&T::Target, &E> + where + T: Deref, + { + self.as_ref().map(|t| t.deref()) + } + + /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`. + /// + /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut) + /// and returns the new [`Result`]. + /// + /// # Examples + /// + /// ``` + /// let mut s = "HELLO".to_string(); + /// let mut x: Result<String, u32> = Ok("hello".to_string()); + /// let y: Result<&mut str, &mut u32> = Ok(&mut s); + /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); + /// + /// let mut i = 42; + /// let mut x: Result<String, u32> = Err(42); + /// let y: Result<&mut str, &mut u32> = Err(&mut i); + /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); + /// ``` + #[stable(feature = "inner_deref", since = "1.47.0")] + pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> + where + T: DerefMut, + { + self.as_mut().map(|t| t.deref_mut()) + } + ///////////////////////////////////////////////////////////////////////// // Iterator constructors ///////////////////////////////////////////////////////////////////////// @@ -951,6 +943,253 @@ impl<T, E> Result<T, E> { IterMut { inner: self.as_mut().ok() } } + ///////////////////////////////////////////////////////////////////////// + // Extract a value + ///////////////////////////////////////////////////////////////////////// + + /// Returns the contained [`Ok`] value, consuming the `self` value. + /// + /// # Panics + /// + /// Panics if the value is an [`Err`], with a panic message including the + /// passed message, and the content of the [`Err`]. + /// + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```should_panic + /// let x: Result<u32, &str> = Err("emergency failure"); + /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` + /// ``` + #[inline] + #[track_caller] + #[stable(feature = "result_expect", since = "1.4.0")] + pub fn expect(self, msg: &str) -> T + where + E: fmt::Debug, + { + match self { + Ok(t) => t, + Err(e) => unwrap_failed(msg, &e), + } + } + + /// Returns the contained [`Ok`] value, consuming the `self` value. + /// + /// Because this function may panic, its use is generally discouraged. + /// Instead, prefer to use pattern matching and handle the [`Err`] + /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or + /// [`unwrap_or_default`]. + /// + /// [`unwrap_or`]: Result::unwrap_or + /// [`unwrap_or_else`]: Result::unwrap_or_else + /// [`unwrap_or_default`]: Result::unwrap_or_default + /// + /// # Panics + /// + /// Panics if the value is an [`Err`], with a panic message provided by the + /// [`Err`]'s value. + /// + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let x: Result<u32, &str> = Ok(2); + /// assert_eq!(x.unwrap(), 2); + /// ``` + /// + /// ```should_panic + /// let x: Result<u32, &str> = Err("emergency failure"); + /// x.unwrap(); // panics with `emergency failure` + /// ``` + #[inline] + #[track_caller] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unwrap(self) -> T + where + E: fmt::Debug, + { + match self { + Ok(t) => t, + Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), + } + } + + /// Returns the contained [`Ok`] value or a default + /// + /// Consumes the `self` argument then, if [`Ok`], returns the contained + /// value, otherwise if [`Err`], returns the default value for that + /// type. + /// + /// # Examples + /// + /// Converts a string to an integer, turning poorly-formed strings + /// into 0 (the default value for integers). [`parse`] converts + /// a string to any other type that implements [`FromStr`], returning an + /// [`Err`] on error. + /// + /// ``` + /// let good_year_from_input = "1909"; + /// let bad_year_from_input = "190blarg"; + /// let good_year = good_year_from_input.parse().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().unwrap_or_default(); + /// + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); + /// ``` + /// + /// [`parse`]: str::parse + /// [`FromStr`]: crate::str::FromStr + #[inline] + #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] + pub fn unwrap_or_default(self) -> T + where + T: Default, + { + match self { + Ok(x) => x, + Err(_) => Default::default(), + } + } + + /// Returns the contained [`Err`] value, consuming the `self` value. + /// + /// # Panics + /// + /// Panics if the value is an [`Ok`], with a panic message including the + /// passed message, and the content of the [`Ok`]. + /// + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```should_panic + /// let x: Result<u32, &str> = Ok(10); + /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` + /// ``` + #[inline] + #[track_caller] + #[stable(feature = "result_expect_err", since = "1.17.0")] + pub fn expect_err(self, msg: &str) -> E + where + T: fmt::Debug, + { + match self { + Ok(t) => unwrap_failed(msg, &t), + Err(e) => e, + } + } + + /// Returns the contained [`Err`] value, consuming the `self` value. + /// + /// # Panics + /// + /// Panics if the value is an [`Ok`], with a custom panic message provided + /// by the [`Ok`]'s value. + /// + /// # Examples + /// + /// ```should_panic + /// let x: Result<u32, &str> = Ok(2); + /// x.unwrap_err(); // panics with `2` + /// ``` + /// + /// ``` + /// let x: Result<u32, &str> = Err("emergency failure"); + /// assert_eq!(x.unwrap_err(), "emergency failure"); + /// ``` + #[inline] + #[track_caller] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn unwrap_err(self) -> E + where + T: fmt::Debug, + { + match self { + Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), + Err(e) => e, + } + } + + /// Returns the contained [`Ok`] value, but never panics. + /// + /// Unlike [`unwrap`], this method is known to never panic on the + /// result types it is implemented for. Therefore, it can be used + /// instead of `unwrap` as a maintainability safeguard that will fail + /// to compile if the error type of the `Result` is later changed + /// to an error that can actually occur. + /// + /// [`unwrap`]: Result::unwrap + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(never_type)] + /// # #![feature(unwrap_infallible)] + /// + /// fn only_good_news() -> Result<String, !> { + /// Ok("this is fine".into()) + /// } + /// + /// let s: String = only_good_news().into_ok(); + /// println!("{}", s); + /// ``` + #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] + #[inline] + pub fn into_ok(self) -> T + where + E: Into<!>, + { + match self { + Ok(x) => x, + Err(e) => e.into(), + } + } + + /// Returns the contained [`Err`] value, but never panics. + /// + /// Unlike [`unwrap_err`], this method is known to never panic on the + /// result types it is implemented for. Therefore, it can be used + /// instead of `unwrap_err` as a maintainability safeguard that will fail + /// to compile if the ok type of the `Result` is later changed + /// to a type that can actually occur. + /// + /// [`unwrap_err`]: Result::unwrap_err + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(never_type)] + /// # #![feature(unwrap_infallible)] + /// + /// fn only_bad_news() -> Result<!, String> { + /// Err("Oops, it failed".into()) + /// } + /// + /// let error: String = only_bad_news().into_err(); + /// println!("{}", error); + /// ``` + #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] + #[inline] + pub fn into_err(self) -> E + where + T: Into<!>, + { + match self { + Ok(x) => x.into(), + Err(e) => e, + } + } + //////////////////////////////////////////////////////////////////////// // Boolean operations on the values, eager and lazy ///////////////////////////////////////////////////////////////////////// @@ -1194,365 +1433,155 @@ impl<T, E> Result<T, E> { Err(e) => e, } } -} -impl<T: Copy, E> Result<&T, E> { - /// Maps a `Result<&T, E>` to a `Result<T, E>` by copying the contents of the - /// `Ok` part. - /// - /// # Examples - /// - /// ``` - /// #![feature(result_copied)] - /// let val = 12; - /// let x: Result<&i32, i32> = Ok(&val); - /// assert_eq!(x, Ok(&12)); - /// let copied = x.copied(); - /// assert_eq!(copied, Ok(12)); - /// ``` - #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")] - pub fn copied(self) -> Result<T, E> { - self.map(|&t| t) - } -} - -impl<T: Copy, E> Result<&mut T, E> { - /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by copying the contents of the - /// `Ok` part. - /// - /// # Examples - /// - /// ``` - /// #![feature(result_copied)] - /// let mut val = 12; - /// let x: Result<&mut i32, i32> = Ok(&mut val); - /// assert_eq!(x, Ok(&mut 12)); - /// let copied = x.copied(); - /// assert_eq!(copied, Ok(12)); - /// ``` - #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")] - pub fn copied(self) -> Result<T, E> { - self.map(|&mut t| t) - } -} - -impl<T: Clone, E> Result<&T, E> { - /// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the - /// `Ok` part. - /// - /// # Examples - /// - /// ``` - /// #![feature(result_cloned)] - /// let val = 12; - /// let x: Result<&i32, i32> = Ok(&val); - /// assert_eq!(x, Ok(&12)); - /// let cloned = x.cloned(); - /// assert_eq!(cloned, Ok(12)); - /// ``` - #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")] - pub fn cloned(self) -> Result<T, E> { - self.map(|t| t.clone()) - } -} - -impl<T: Clone, E> Result<&mut T, E> { - /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by cloning the contents of the - /// `Ok` part. - /// - /// # Examples - /// - /// ``` - /// #![feature(result_cloned)] - /// let mut val = 12; - /// let x: Result<&mut i32, i32> = Ok(&mut val); - /// assert_eq!(x, Ok(&mut 12)); - /// let cloned = x.cloned(); - /// assert_eq!(cloned, Ok(12)); - /// ``` - #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")] - pub fn cloned(self) -> Result<T, E> { - self.map(|t| t.clone()) - } -} + ///////////////////////////////////////////////////////////////////////// + // Misc or niche + ///////////////////////////////////////////////////////////////////////// -impl<T, E: fmt::Debug> Result<T, E> { - /// Returns the contained [`Ok`] value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an [`Err`], with a panic message including the - /// passed message, and the content of the [`Err`]. - /// + /// Returns `true` if the result is an [`Ok`] value containing the given value. /// /// # Examples /// - /// Basic usage: - /// - /// ```should_panic - /// let x: Result<u32, &str> = Err("emergency failure"); - /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` /// ``` - #[inline] - #[track_caller] - #[stable(feature = "result_expect", since = "1.4.0")] - pub fn expect(self, msg: &str) -> T { - match self { - Ok(t) => t, - Err(e) => unwrap_failed(msg, &e), - } - } - - /// Returns the contained [`Ok`] value, consuming the `self` value. - /// - /// Because this function may panic, its use is generally discouraged. - /// Instead, prefer to use pattern matching and handle the [`Err`] - /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or - /// [`unwrap_or_default`]. - /// - /// [`unwrap_or`]: Result::unwrap_or - /// [`unwrap_or_else`]: Result::unwrap_or_else - /// [`unwrap_or_default`]: Result::unwrap_or_default - /// - /// # Panics - /// - /// Panics if the value is an [`Err`], with a panic message provided by the - /// [`Err`]'s value. - /// - /// - /// # Examples - /// - /// Basic usage: + /// #![feature(option_result_contains)] /// - /// ``` /// let x: Result<u32, &str> = Ok(2); - /// assert_eq!(x.unwrap(), 2); - /// ``` - /// - /// ```should_panic - /// let x: Result<u32, &str> = Err("emergency failure"); - /// x.unwrap(); // panics with `emergency failure` - /// ``` - #[inline] - #[track_caller] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap(self) -> T { - match self { - Ok(t) => t, - Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e), - } - } -} - -impl<T: fmt::Debug, E> Result<T, E> { - /// Returns the contained [`Err`] value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an [`Ok`], with a panic message including the - /// passed message, and the content of the [`Ok`]. - /// - /// - /// # Examples + /// assert_eq!(x.contains(&2), true); /// - /// Basic usage: + /// let x: Result<u32, &str> = Ok(3); + /// assert_eq!(x.contains(&2), false); /// - /// ```should_panic - /// let x: Result<u32, &str> = Ok(10); - /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` + /// let x: Result<u32, &str> = Err("Some error message"); + /// assert_eq!(x.contains(&2), false); /// ``` + #[must_use] #[inline] - #[track_caller] - #[stable(feature = "result_expect_err", since = "1.17.0")] - pub fn expect_err(self, msg: &str) -> E { + #[unstable(feature = "option_result_contains", issue = "62358")] + pub fn contains<U>(&self, x: &U) -> bool + where + U: PartialEq<T>, + { match self { - Ok(t) => unwrap_failed(msg, &t), - Err(e) => e, + Ok(y) => x == y, + Err(_) => false, } } - /// Returns the contained [`Err`] value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an [`Ok`], with a custom panic message provided - /// by the [`Ok`]'s value. + /// Returns `true` if the result is an [`Err`] value containing the given value. /// /// # Examples /// - /// ```should_panic - /// let x: Result<u32, &str> = Ok(2); - /// x.unwrap_err(); // panics with `2` /// ``` + /// #![feature(result_contains_err)] /// - /// ``` - /// let x: Result<u32, &str> = Err("emergency failure"); - /// assert_eq!(x.unwrap_err(), "emergency failure"); - /// ``` - #[inline] - #[track_caller] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_err(self) -> E { - match self { - Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t), - Err(e) => e, - } - } -} - -impl<T: Default, E> Result<T, E> { - /// Returns the contained [`Ok`] value or a default - /// - /// Consumes the `self` argument then, if [`Ok`], returns the contained - /// value, otherwise if [`Err`], returns the default value for that - /// type. - /// - /// # Examples - /// - /// Converts a string to an integer, turning poorly-formed strings - /// into 0 (the default value for integers). [`parse`] converts - /// a string to any other type that implements [`FromStr`], returning an - /// [`Err`] on error. + /// let x: Result<u32, &str> = Ok(2); + /// assert_eq!(x.contains_err(&"Some error message"), false); /// - /// ``` - /// let good_year_from_input = "1909"; - /// let bad_year_from_input = "190blarg"; - /// let good_year = good_year_from_input.parse().unwrap_or_default(); - /// let bad_year = bad_year_from_input.parse().unwrap_or_default(); + /// let x: Result<u32, &str> = Err("Some error message"); + /// assert_eq!(x.contains_err(&"Some error message"), true); /// - /// assert_eq!(1909, good_year); - /// assert_eq!(0, bad_year); + /// let x: Result<u32, &str> = Err("Some other error message"); + /// assert_eq!(x.contains_err(&"Some error message"), false); /// ``` - /// - /// [`parse`]: str::parse - /// [`FromStr`]: crate::str::FromStr + #[must_use] #[inline] - #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] - pub fn unwrap_or_default(self) -> T { + #[unstable(feature = "result_contains_err", issue = "62358")] + pub fn contains_err<F>(&self, f: &F) -> bool + where + F: PartialEq<E>, + { match self { - Ok(x) => x, - Err(_) => Default::default(), + Ok(_) => false, + Err(e) => f == e, } } } -#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] -impl<T, E: Into<!>> Result<T, E> { - /// Returns the contained [`Ok`] value, but never panics. - /// - /// Unlike [`unwrap`], this method is known to never panic on the - /// result types it is implemented for. Therefore, it can be used - /// instead of `unwrap` as a maintainability safeguard that will fail - /// to compile if the error type of the `Result` is later changed - /// to an error that can actually occur. - /// - /// [`unwrap`]: Result::unwrap +impl<T, E> Result<&T, E> { + /// Maps a `Result<&T, E>` to a `Result<T, E>` by copying the contents of the + /// `Ok` part. /// /// # Examples /// - /// Basic usage: - /// /// ``` - /// # #![feature(never_type)] - /// # #![feature(unwrap_infallible)] - /// - /// fn only_good_news() -> Result<String, !> { - /// Ok("this is fine".into()) - /// } - /// - /// let s: String = only_good_news().into_ok(); - /// println!("{}", s); + /// #![feature(result_copied)] + /// let val = 12; + /// let x: Result<&i32, i32> = Ok(&val); + /// assert_eq!(x, Ok(&12)); + /// let copied = x.copied(); + /// assert_eq!(copied, Ok(12)); /// ``` - #[inline] - pub fn into_ok(self) -> T { - match self { - Ok(x) => x, - Err(e) => e.into(), - } + #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")] + pub fn copied(self) -> Result<T, E> + where + T: Copy, + { + self.map(|&t| t) } -} -#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] -impl<T: Into<!>, E> Result<T, E> { - /// Returns the contained [`Err`] value, but never panics. - /// - /// Unlike [`unwrap_err`], this method is known to never panic on the - /// result types it is implemented for. Therefore, it can be used - /// instead of `unwrap_err` as a maintainability safeguard that will fail - /// to compile if the ok type of the `Result` is later changed - /// to a type that can actually occur. - /// - /// [`unwrap_err`]: Result::unwrap_err + /// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the + /// `Ok` part. /// /// # Examples /// - /// Basic usage: - /// /// ``` - /// # #![feature(never_type)] - /// # #![feature(unwrap_infallible)] - /// - /// fn only_bad_news() -> Result<!, String> { - /// Err("Oops, it failed".into()) - /// } - /// - /// let error: String = only_bad_news().into_err(); - /// println!("{}", error); + /// #![feature(result_cloned)] + /// let val = 12; + /// let x: Result<&i32, i32> = Ok(&val); + /// assert_eq!(x, Ok(&12)); + /// let cloned = x.cloned(); + /// assert_eq!(cloned, Ok(12)); /// ``` - #[inline] - pub fn into_err(self) -> E { - match self { - Ok(x) => x.into(), - Err(e) => e, - } + #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")] + pub fn cloned(self) -> Result<T, E> + where + T: Clone, + { + self.map(|t| t.clone()) } } -impl<T: Deref, E> Result<T, E> { - /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`. - /// - /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref) - /// and returns the new [`Result`]. +impl<T, E> Result<&mut T, E> { + /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by copying the contents of the + /// `Ok` part. /// /// # Examples /// /// ``` - /// let x: Result<String, u32> = Ok("hello".to_string()); - /// let y: Result<&str, &u32> = Ok("hello"); - /// assert_eq!(x.as_deref(), y); - /// - /// let x: Result<String, u32> = Err(42); - /// let y: Result<&str, &u32> = Err(&42); - /// assert_eq!(x.as_deref(), y); + /// #![feature(result_copied)] + /// let mut val = 12; + /// let x: Result<&mut i32, i32> = Ok(&mut val); + /// assert_eq!(x, Ok(&mut 12)); + /// let copied = x.copied(); + /// assert_eq!(copied, Ok(12)); /// ``` - #[stable(feature = "inner_deref", since = "1.47.0")] - pub fn as_deref(&self) -> Result<&T::Target, &E> { - self.as_ref().map(|t| t.deref()) + #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")] + pub fn copied(self) -> Result<T, E> + where + T: Copy, + { + self.map(|&mut t| t) } -} -impl<T: DerefMut, E> Result<T, E> { - /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`. - /// - /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut) - /// and returns the new [`Result`]. + /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by cloning the contents of the + /// `Ok` part. /// /// # Examples /// /// ``` - /// let mut s = "HELLO".to_string(); - /// let mut x: Result<String, u32> = Ok("hello".to_string()); - /// let y: Result<&mut str, &mut u32> = Ok(&mut s); - /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); - /// - /// let mut i = 42; - /// let mut x: Result<String, u32> = Err(42); - /// let y: Result<&mut str, &mut u32> = Err(&mut i); - /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); + /// #![feature(result_cloned)] + /// let mut val = 12; + /// let x: Result<&mut i32, i32> = Ok(&mut val); + /// assert_eq!(x, Ok(&mut 12)); + /// let cloned = x.cloned(); + /// assert_eq!(cloned, Ok(12)); /// ``` - #[stable(feature = "inner_deref", since = "1.47.0")] - pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> { - self.as_mut().map(|t| t.deref_mut()) + #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")] + pub fn cloned(self) -> Result<T, E> + where + T: Clone, + { + self.map(|t| t.clone()) } } diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 743dd51333d..b52bcdfca9e 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -54,33 +54,30 @@ pub use core::prelude::v1::{ #[doc(no_inline)] pub use core::prelude::v1::concat_bytes; -// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates -// dead links which fail link checker testing. +// Do not `doc(inline)` these `doc(hidden)` items. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated, deprecated_in_future)] -#[doc(hidden)] -pub use core::prelude::v1::{ - bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable, -}; +#[allow(deprecated)] +pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; +// Do not `doc(no_inline)` so that they become doc items on their own +// (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[doc(hidden)] -pub use core::prelude::v1::derive; +pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case}; +// Do not `doc(no_inline)` either. #[unstable( feature = "cfg_accessible", issue = "64797", reason = "`cfg_accessible` is not fully implemented" )] -#[doc(hidden)] pub use core::prelude::v1::cfg_accessible; +// Do not `doc(no_inline)` either. #[unstable( feature = "cfg_eval", issue = "82679", reason = "`cfg_eval` is a recently implemented feature" )] -#[doc(hidden)] pub use core::prelude::v1::cfg_eval; // The file so far is equivalent to src/libcore/prelude/v1.rs, diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 2cf678ef69b..2e54321e127 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -429,12 +429,13 @@ pub struct TryIter<'a, T: 'a> { } /// An owning iterator over messages on a [`Receiver`], -/// created by **Receiver::into_iter**. +/// created by [`into_iter`]. /// /// This iterator will block whenever [`next`] /// is called, waiting for a new message, and [`None`] will be /// returned if the corresponding channel has hung up. /// +/// [`into_iter`]: Receiver::into_iter /// [`next`]: Iterator::next /// /// # Examples diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index eb0925b3fda..684b8e3155e 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -15,7 +15,9 @@ use core::str::utf8_char_width; // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490. pub struct Stdin { surrogate: u16, + incomplete_utf8: IncompleteUtf8, } + pub struct Stdout { incomplete_utf8: IncompleteUtf8, } @@ -29,6 +31,25 @@ struct IncompleteUtf8 { len: u8, } +impl IncompleteUtf8 { + // Implemented for use in Stdin::read. + fn read(&mut self, buf: &mut [u8]) -> usize { + // Write to buffer until the buffer is full or we run out of bytes. + let to_write = cmp::min(buf.len(), self.len as usize); + buf[..to_write].copy_from_slice(&self.bytes[..to_write]); + + // Rotate the remaining bytes if not enough remaining space in buffer. + if usize::from(self.len) > buf.len() { + self.bytes.copy_within(to_write.., 0); + self.len -= to_write as u8; + } else { + self.len = 0; + } + + to_write + } +} + // Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see // #13304 for details). // @@ -205,7 +226,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> { impl Stdin { pub const fn new() -> Stdin { - Stdin { surrogate: 0 } + Stdin { surrogate: 0, incomplete_utf8: IncompleteUtf8::new() } } } @@ -221,24 +242,39 @@ impl io::Read for Stdin { } } - if buf.len() == 0 { - return Ok(0); - } else if buf.len() < 4 { - return Err(io::Error::new_const( - io::ErrorKind::InvalidInput, - &"Windows stdin in console mode does not support a buffer too small to \ - guarantee holding one arbitrary UTF-8 character (4 bytes)", - )); + // If there are bytes in the incomplete utf-8, start with those. + // (No-op if there is nothing in the buffer.) + let mut bytes_copied = self.incomplete_utf8.read(buf); + + if bytes_copied == buf.len() { + return Ok(bytes_copied); + } else if buf.len() - bytes_copied < 4 { + // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8. + let mut utf16_buf = [0u16; 1]; + // Read one u16 character. + let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?; + // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space. + let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?; + + // Read in the bytes from incomplete_utf8 until the buffer is full. + self.incomplete_utf8.len = read_bytes as u8; + // No-op if no bytes. + bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]); + Ok(bytes_copied) + } else { + let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; + // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So + // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets + // lost. + let amount = cmp::min(buf.len() / 3, utf16_buf.len()); + let read = + read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; + + match utf16_to_utf8(&utf16_buf[..read], buf) { + Ok(value) => return Ok(bytes_copied + value), + Err(e) => return Err(e), + } } - - let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; - // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So - // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets - // lost. - let amount = cmp::min(buf.len() / 3, utf16_buf.len()); - let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; - - utf16_to_utf8(&utf16_buf[..read], buf) } } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 2516f3452b1..608e587cf34 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -13,20 +13,12 @@ // running tests while providing a base that other test frameworks may // build off of. -// N.B., this is also specified in this crate's Cargo.toml, but librustc_ast contains logic specific to -// this crate, which relies on this attribute (rather than the value of `--crate-name` passed by -// cargo) to detect this crate. - -#![crate_name = "test"] #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] -#![feature(libc)] -#![feature(rustc_private)] #![feature(nll)] #![feature(available_parallelism)] #![feature(bench_black_box)] #![feature(internal_output_capture)] -#![feature(panic_unwind)] #![feature(staged_api)] #![feature(termination_trait_lib)] #![feature(test)] @@ -444,8 +436,8 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd .into_iter() .map(|x| { let testfn = match x.testfn { - DynBenchFn(bench) => DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b))) + DynBenchFn(benchfn) => DynTestFn(Box::new(move || { + bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) })), StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) @@ -544,11 +536,9 @@ pub fn run_test( TestRunOpts { strategy, nocapture: opts.nocapture, concurrency, time: opts.time_options }; match testfn { - DynBenchFn(bencher) => { + DynBenchFn(benchfn) => { // Benchmarks aren't expected to panic, so we run them all in-process. - crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, |harness| { - bencher.run(harness) - }); + crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn); None } StaticBenchFn(benchfn) => { diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index 45fae9c76b4..40b05704b40 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -1,5 +1,4 @@ #![allow(missing_docs)] -#![allow(deprecated)] // Float use std::mem; diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 3512a57e8e4..37bb38fb0df 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -74,11 +74,6 @@ impl fmt::Display for TestName { } } -/// Represents a benchmark function. -pub trait TDynBenchFn: Send { - fn run(&self, harness: &mut Bencher); -} - // A function that runs a test. If the function returns successfully, // the test succeeds; if the function panics then the test fails. We // may need to come up with a more clever definition of test in order @@ -87,7 +82,7 @@ pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), DynTestFn(Box<dyn FnOnce() + Send>), - DynBenchFn(Box<dyn TDynBenchFn + 'static>), + DynBenchFn(Box<dyn Fn(&mut Bencher) + Send>), } impl TestFn { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5a33073e6b0..5235a6b8180 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -974,6 +974,7 @@ class RustBuild(object): def build_bootstrap(self): """Build bootstrap""" + print("Building rustbuild") build_dir = os.path.join(self.build_dir, "bootstrap") if self.clean and os.path.exists(build_dir): shutil.rmtree(build_dir) @@ -1133,7 +1134,7 @@ class RustBuild(object): recorded_submodules[data[3]] = data[2] for module in filtered_submodules: self.update_submodule(module[0], module[1], recorded_submodules) - print("Submodules updated in %.2f seconds" % (time() - start_time)) + print(" Submodules updated in %.2f seconds" % (time() - start_time)) def set_dist_environment(self, url): """Set download URL for normal environment""" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 917abde9de1..6ccf8b1d522 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -988,10 +988,20 @@ impl<'a> Builder<'a> { } }; - if use_new_symbol_mangling { - rustflags.arg("-Zsymbol-mangling-version=v0"); + // cfg(bootstrap) -- drop the compiler.stage == 0 branch. + if compiler.stage == 0 { + if use_new_symbol_mangling { + rustflags.arg("-Zsymbol-mangling-version=v0"); + } else { + rustflags.arg("-Zsymbol-mangling-version=legacy"); + } } else { - rustflags.arg("-Zsymbol-mangling-version=legacy"); + if use_new_symbol_mangling { + rustflags.arg("-Csymbol-mangling-version=v0"); + } else { + rustflags.arg("-Csymbol-mangling-version=legacy"); + rustflags.arg("-Zunstable-options"); + } } // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`, diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2fddda74a28..9180c5f03af 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -401,26 +401,19 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", "\n Arguments: This subcommand accepts a number of paths to directories to the crates - and/or artifacts to compile. For example: - - ./x.py build library/core - ./x.py build library/core library/proc_macro - ./x.py build library/std --stage 1 - - If no arguments are passed then the complete artifacts for that stage are - also compiled. + and/or artifacts to compile. For example, for a quick build of a usable + compiler: - ./x.py build - ./x.py build --stage 1 + ./x.py build --stage 1 library/std - For a quick build of a usable compiler, you can pass: + This will build a compiler and standard library from the local source code. + Once this is done, build/$ARCH/stage1 contains a usable compiler. - ./x.py build --stage 1 library/test + If no arguments are passed then the default artifacts for that stage are + compiled. For example: - This will first build everything once (like `--stage 0` without further - arguments would), and then use the compiler built in stage 0 to build - library/test and its dependencies. - Once this is done, build/$ARCH/stage1 contains a usable compiler.", + ./x.py build --stage 0 + ./x.py build ", ); } "check" | "c" => { @@ -430,14 +423,9 @@ Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: - ./x.py check library/core - ./x.py check library/core library/proc_macro + ./x.py check library/std - If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note - also that since we use `cargo check`, by default this will automatically enable incremental - compilation, so there's no need to pass it separately, though it won't hurt. We also completely - ignore the stage passed, as there's no way to compile in non-stage 0 without actually building - the compiler.", + If no arguments are passed then many artifacts are checked.", ); } "clippy" => { diff --git a/src/doc/book b/src/doc/book -Subproject 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa +Subproject d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3 diff --git a/src/doc/reference b/src/doc/reference -Subproject 06f9e61931bcf58b91dfe6c924057e42ce273ee +Subproject f8ba2f12df60ee19b96de24ae5b73af3de8a446 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 9bf0028b557798ddd07a6f652e4d0c635d3d662 +Subproject 875464457c4104686faf667f47848aa7b0f0a74 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 959be5478b4..d80e79d164a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1350,17 +1350,23 @@ impl Clean<Type> for hir::Ty<'_> { } TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { - let def_id = cx.tcx.hir().local_def_id(length.hir_id); - // NOTE(min_const_generics): We can't use `const_eval_poly` for constants - // as we currently do not supply the parent generics to anonymous constants - // but do allow `ConstKind::Param`. - // - // `const_eval_poly` tries to to first substitute generic parameters which - // results in an ICE while manually constructing the constant and using `eval` - // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_anon_const(cx.tcx, def_id); - let param_env = cx.tcx.param_env(def_id); - let length = print_const(cx, ct.eval(cx.tcx, param_env)); + let length = match length { + hir::ArrayLen::Infer(_, _) => "_".to_string(), + hir::ArrayLen::Body(anon_const) => { + let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + print_const(cx, ct.eval(cx.tcx, param_env)) + } + }; + Array(box ty.clean(cx), length) } TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2ee5de24687..f0f61bb94c8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -889,20 +889,25 @@ impl AttributesExt for [ast::Attribute] { } crate trait NestedAttributesExt { - /// Returns `true` if the attribute list contains a specific `Word` - fn has_word(self, word: Symbol) -> bool; + /// Returns `true` if the attribute list contains a specific `word` + fn has_word(self, word: Symbol) -> bool + where + Self: std::marker::Sized, + { + <Self as NestedAttributesExt>::get_word_attr(self, word).is_some() + } + + /// Returns `Some(attr)` if the attribute list contains 'attr' + /// corresponding to a specific `word` fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>; } -impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>> - NestedAttributesExt for I +impl<I> NestedAttributesExt for I +where + I: IntoIterator<Item = ast::NestedMetaItem>, { - fn has_word(self, word: Symbol) -> bool { - self.into_iter().any(|attr| attr.is_word() && attr.has_name(word)) - } - - fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> { - self.find(|attr| attr.is_word() && attr.has_name(word)) + fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> { + self.into_iter().find(|attr| attr.is_word() && attr.has_name(word)) } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index e5c667a37c6..d82c65398b8 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -108,7 +108,7 @@ html { /* General structure and fonts */ body { - font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif; + font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif; margin: 0; position: relative; @@ -118,13 +118,13 @@ body { } h1 { - font-size: 1.5em; + font-size: 1.5rem; } h2 { - font-size: 1.4em; + font-size: 1.4rem; } h3 { - font-size: 1.3em; + font-size: 1.3rem; } h1, h2, h3, h4, h5, h6 { font-weight: 500; @@ -160,10 +160,10 @@ h2, border-bottom: 1px solid; } h3.code-header { - font-size: 1.1em; + font-size: 1.1rem; } h4.code-header { - font-size: 1em; + font-size: 1rem; } h3.code-header, h4.code-header { font-weight: 600; @@ -206,7 +206,7 @@ div.impl-items > div:not(.docblock):not(.item-info), } .content ul.crate a.crate { - font-size: 16px/1.6; + font-size: 1rem/1.6; } ol, ul { @@ -317,7 +317,7 @@ li { nav.sub { position: relative; - font-size: 16px; + font-size: 1rem; text-transform: uppercase; } @@ -423,7 +423,7 @@ nav.sub { .sidebar .location { border: 1px solid; - font-size: 17px; + font-size: 1.0625rem; margin: 30px 10px 20px 10px; text-align: center; word-wrap: break-word; @@ -432,7 +432,7 @@ nav.sub { } .sidebar .version { - font-size: 15px; + font-size: 0.9375rem; text-align: center; border-bottom: 1px solid; overflow-wrap: break-word; @@ -470,7 +470,7 @@ nav.sub { overflow: hidden; line-height: 15px; padding: 7px 5px; - font-size: 14px; + font-size: 0.875rem; font-weight: 300; transition: border 500ms ease-out; } @@ -479,7 +479,7 @@ nav.sub { border-top: 1px solid; border-bottom: 1px solid; text-align: center; - font-size: 17px; + font-size: 1.0625rem; margin-bottom: 5px; font-weight: inherit; padding: 0; @@ -579,18 +579,18 @@ nav.sub { white-space: pre-wrap; } -.top-doc .docblock h2 { font-size: 1.3em; } -.top-doc .docblock h3 { font-size: 1.15em; } +.top-doc .docblock h2 { font-size: 1.3rem; } +.top-doc .docblock h3 { font-size: 1.15rem; } .top-doc .docblock h4, .top-doc .docblock h5 { - font-size: 1.1em; + font-size: 1.1rem; } .top-doc .docblock h6 { - font-size: 1em; + font-size: 1rem; } -.docblock h5 { font-size: 1em; } -.docblock h6 { font-size: 0.95em; } +.docblock h5 { font-size: 1rem; } +.docblock h6 { font-size: 0.95rem; } .docblock { margin-left: 24px; @@ -605,7 +605,7 @@ nav.sub { .content .out-of-band { flex-grow: 0; text-align: right; - font-size: 23px; + font-size: 1.4375rem; margin: 0px; padding: 0 0 0 12px; font-weight: normal; @@ -646,7 +646,7 @@ nav.sub { .content td { vertical-align: top; } .content td:first-child { padding-right: 20px; } .content td p:first-child { margin-top: 0; } -.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; } +.content td h1, .content td h2 { margin-left: 0; font-size: 1.1rem; } .content tr:first-child td { border-top: 0; } .docblock table { @@ -687,7 +687,7 @@ nav.sub { .content .multi-column li { width: 100%; display: inline-block; } .content > .methods > .method { - font-size: 1em; + font-size: 1rem; position: relative; } /* Shift "where ..." part of method or fn definition down a line */ @@ -695,7 +695,7 @@ nav.sub { .content .fn .where, .content .where.fmt-newline { display: block; - font-size: 0.8em; + font-size: 0.8rem; } .content .methods > div:not(.notable-traits):not(.method) { @@ -718,7 +718,7 @@ nav.sub { } .content .item-info code { - font-size: 90%; + font-size: 0.81rem; } .content .item-info { @@ -732,7 +732,7 @@ nav.sub { .content .item-info::before { content: '⬑'; - font-size: 25px; + font-size: 1.5625rem; position: absolute; top: -6px; left: -19px; @@ -835,7 +835,7 @@ h2.small-section-header > .anchor { position: absolute; top: 0; right: 0; - font-size: 17px; + font-size: 1.0625rem; font-weight: normal; } @@ -905,7 +905,7 @@ h2.small-section-header > .anchor { border-radius: 1px; margin-top: 5px; padding: 10px 16px; - font-size: 17px; + font-size: 1.0625rem; transition: border-color 300ms ease; transition: border-radius 300ms ease-in-out; transition: box-shadow 300ms ease-in-out; @@ -1000,7 +1000,7 @@ body.blur > :not(#help) { #help span.top, #help span.bottom { text-align: center; display: block; - font-size: 18px; + font-size: 1.125rem; } #help span.top { @@ -1030,7 +1030,7 @@ body.blur > :not(#help) { .stab { padding: 3px; margin-bottom: 5px; - font-size: 90%; + font-size: 0.9rem; font-weight: normal; } .stab p { @@ -1038,7 +1038,7 @@ body.blur > :not(#help) { } .stab .emoji { - font-size: 1.2em; + font-size: 1.2rem; } /* Black one-pixel outline around emoji shapes */ @@ -1054,7 +1054,7 @@ body.blur > :not(#help) { .import-item .stab { border-radius: 3px; display: inline-block; - font-size: 80%; + font-size: 0.8rem; line-height: 1.2; margin-bottom: 0; margin-left: .3em; @@ -1080,7 +1080,7 @@ body.blur > :not(#help) { .impl-items .srclink, .impl .srclink, .methods .srclink { /* Override header settings otherwise it's too bold */ - font-size: 17px; + font-size: 1.0625rem; font-weight: normal; } @@ -1089,7 +1089,7 @@ body.blur > :not(#help) { } .has-srclink { - font-size: 16px; + font-size: 1rem; margin-bottom: 12px; /* Push the src link out to the right edge consistently */ justify-content: space-between; @@ -1120,7 +1120,7 @@ a.test-arrow { position: absolute; padding: 5px 10px 5px 10px; border-radius: 5px; - font-size: 130%; + font-size: 1.3rem; top: 5px; right: 5px; z-index: 1; @@ -1155,19 +1155,19 @@ a.test-arrow:hover{ .out-of-band > span.since { position: initial; - font-size: 20px; + font-size: 1.25rem; margin-right: 5px; } h3.variant { font-weight: 600; - font-size: 1.1em; + font-size: 1.1rem; margin-bottom: 10px; border-bottom: none; } .sub-variant h4 { - font-size: 1em; + font-size: 1rem; font-weight: 400; border-bottom: none; margin-top: 0; @@ -1227,7 +1227,7 @@ h3.variant { padding: 5px 3px 3px 3px; border-radius: 6px; margin-left: 5px; - font-size: 16px; + font-size: 1rem; } .tooltip.ignore::after { @@ -1260,7 +1260,7 @@ h3.variant { .tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore { font-weight: bold; - font-size: 20px; + font-size: 1.25rem; } .notable-traits-tooltip { @@ -1279,7 +1279,7 @@ h3.variant { border-radius: 6px; margin-left: 5px; z-index: 10; - font-size: 16px; + font-size: 1rem; cursor: default; position: absolute; border: 1px solid; @@ -1299,14 +1299,14 @@ h3.variant { .notable-traits .notable { margin: 0; margin-bottom: 13px; - font-size: 19px; + font-size: 1.1875rem; font-weight: 600; } .notable-traits .docblock code.content{ margin: 0; padding: 0; - font-size: 20px; + font-size: 1.25rem; } /* Example code has the "Run" button that needs to be positioned relative to the pre */ @@ -1344,7 +1344,7 @@ pre.rust { float: left; width: 33.3%; text-align: center; - font-size: 18px; + font-size: 1.125rem; cursor: pointer; border: 0; border-top: 2px solid; @@ -1357,7 +1357,7 @@ pre.rust { #titles > button > div.count { display: inline-block; - font-size: 16px; + font-size: 1rem; } .notable-traits { @@ -1384,7 +1384,7 @@ pre.rust { left: 0; cursor: pointer; font-weight: bold; - font-size: 1.2em; + font-size: 1.2rem; border-bottom: 1px solid; display: flex; height: 40px; @@ -1398,7 +1398,7 @@ pre.rust { overflow: auto; } #source-sidebar > .title { - font-size: 1.5em; + font-size: 1.5rem; text-align: center; border-bottom: 1px solid; margin-bottom: 6px; @@ -1426,6 +1426,9 @@ pre.rust { #theme-picker, #settings-menu, #help-button, #copy-path { padding: 4px; + /* Rare exception to specifying font sizes in rem. Since these are acting + as icons, it's okay to specify their sizes in pixels. */ + font-size: 16px; width: 27px; height: 29px; border: 1px solid; @@ -1437,7 +1440,9 @@ pre.rust { right: 30px; font-family: "Fira Sans", Arial, sans-serif; text-align: center; - font-size: 17px; + /* Rare exception to specifying font sizes in rem. Since this is acting + as an icon, it's okay to specify their sizes in pixels. */ + font-size: 16px; padding-top: 2px; } @@ -1499,7 +1504,7 @@ kbd { border: 0; border-collapse: collapse; border-spacing: 0; - font-size: 16px; + font-size: 1rem; } .table-display tr td:first-child { @@ -1511,11 +1516,11 @@ kbd { } .table-display .out-of-band { position: relative; - font-size: 19px; + font-size: 1.1875rem; display: block; } #implementors-list > .impl-items .table-display .out-of-band { - font-size: 17px; + font-size: 1.0625rem; } .table-display td:hover .anchor { @@ -1557,7 +1562,7 @@ div.name.expand + .children { div.name::before { content: "\25B6"; padding-left: 4px; - font-size: 0.7em; + font-size: 0.7rem; position: absolute; left: -16px; top: 4px; @@ -1624,7 +1629,7 @@ details.rustdoc-toggle.top-doc > summary::before, details.rustdoc-toggle.non-exhaustive > summary, details.rustdoc-toggle.non-exhaustive > summary::before { font-family: 'Fira Sans'; - font-size: 16px; + font-size: 1rem; } details.non-exhaustive { @@ -1768,7 +1773,7 @@ details.rustdoc-toggle[open] > summary.hideme::after { min-height: 39px; background: inherit; text-align: left; - font-size: 24px; + font-size: 1.5rem; } .sidebar .location:empty { @@ -1909,7 +1914,7 @@ details.rustdoc-toggle[open] > summary.hideme::after { } .show-it > .block.items > ul > li > a { - font-size: 21px; + font-size: 1.3125rem; } /* Because of ios, we need to actually have a full height sidebar title so the diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs index 1791c089cfa..d57267adc6b 100644 --- a/src/test/incremental/change_private_fn/struct_point.rs +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -51,7 +51,11 @@ pub mod point { pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(cfg="cfail2")] + // The cached result should actually be loaded from disk + // (not just marked green) - for example, `DeadVisitor` + // always runs during compilation as a "pass", and loads + // the typeck results for bodies. + #[rustc_clean(cfg="cfail2", loaded_from_disk="typeck")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); diff --git a/src/test/incremental/hash-module-order.rs b/src/test/incremental/hash-module-order.rs new file mode 100644 index 00000000000..fe9af9eeb37 --- /dev/null +++ b/src/test/incremental/hash-module-order.rs @@ -0,0 +1,28 @@ +// revisions: rpass1 rpass2 +// compile-flags: -Z incremental-ignore-spans -Z query-dep-graph + +// Tests that module hashing depends on the order of the items +// (since the order is exposed through `Mod.item_ids`). +// Changing the order of items (while keeping `Span`s the same) +// should still result in `hir_owner` being invalidated. +// Note that it's possible to keep the spans unchanged using +// a proc-macro (e.g. producing the module via `quote!`) +// but we use `-Z incremental-ignore-spans` for simplicity + +#![feature(rustc_attrs)] + +#[cfg(rpass1)] +#[rustc_clean(cfg="rpass1",except="hir_owner")] +mod foo { + struct First; + struct Second; +} + +#[cfg(rpass2)] +#[rustc_clean(cfg="rpass2",except="hir_owner")] +mod foo { + struct Second; + struct First; +} + +fn main() {} diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs new file mode 100644 index 00000000000..56b88a426a1 --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs @@ -0,0 +1,12 @@ +// To avoid having to `or` gate `_` as an expr. +#![feature(generic_arg_infer)] + +fn foo() -> [u8; _] { + //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics + // FIXME(generic_arg_infer): this error message should say in the return type or sth like that. + [0; 3] +} + +fn main() { + foo(); +} diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr new file mode 100644 index 00000000000..eaa12b4192d --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr @@ -0,0 +1,9 @@ +error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics + --> $DIR/array-in-sig.rs:4:18 + | +LL | fn foo() -> [u8; _] { + | ^ not allowed in type signatures + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs new file mode 100644 index 00000000000..d3e53d7a892 --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs @@ -0,0 +1,13 @@ +// run-pass + +// To avoid having to `or` gate `_` as an expr. +#![feature(generic_arg_infer)] + +fn foo() -> [u8; 3] { + let x: [u8; _] = [0; _]; + x +} + +fn main() { + assert_eq!([0; _], foo()); +} diff --git a/src/test/ui/inference/infer-arg-test.rs b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs index 1b67ccd6c43..29aa0f59d74 100644 --- a/src/test/ui/inference/infer-arg-test.rs +++ b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs @@ -18,7 +18,5 @@ fn main() { let a: All<_, _, _>; all_fn(); let v: [u8; _]; - //~^ ERROR in expressions let v: [u8; 10] = [0; _]; - //~^ ERROR in expressions } diff --git a/src/test/ui/inference/infer-arg-test.stderr b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr index 30e171eac21..e6d0c743d01 100644 --- a/src/test/ui/inference/infer-arg-test.stderr +++ b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr @@ -10,18 +10,6 @@ error: expected identifier, found reserved identifier `_` LL | fn bad_infer_fn<_>() {} | ^ expected identifier, found reserved identifier -error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/infer-arg-test.rs:20:15 - | -LL | let v: [u8; _]; - | ^ `_` not allowed here - -error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/infer-arg-test.rs:22:25 - | -LL | let v: [u8; 10] = [0; _]; - | ^ `_` not allowed here - error[E0392]: parameter `_` is never used --> $DIR/infer-arg-test.rs:7:17 | @@ -31,6 +19,6 @@ LL | struct BadInfer<_>; = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `_` to be a const parameter, use `const _: usize` instead -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr index c17f02d58f3..49eede4794b 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr @@ -1,5 +1,35 @@ +error[E0658]: using `_` for array lengths is unstable + --> $DIR/feature-gate-generic_arg_infer.rs:11:27 + | +LL | let _x: [u8; 3] = [0; _]; + | ^ + | + = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/feature-gate-generic_arg_infer.rs:11:27 + | +LL | let _x: [u8; 3] = [0; _]; + | ^ `_` not allowed here + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/feature-gate-generic_arg_infer.rs:14:18 + | +LL | let _y: [u8; _] = [0; 3]; + | ^ + | + = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/feature-gate-generic_arg_infer.rs:14:18 + | +LL | let _y: [u8; _] = [0; 3]; + | ^ `_` not allowed here + error[E0747]: type provided when a constant was expected - --> $DIR/feature-gate-generic_arg_infer.rs:11:20 + --> $DIR/feature-gate-generic_arg_infer.rs:20:20 | LL | let _x = foo::<_>([1,2]); | ^ @@ -7,6 +37,7 @@ LL | let _x = foo::<_>([1,2]); = help: const arguments cannot yet be inferred with `_` = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0747`. +Some errors have detailed explanations: E0658, E0747. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs index 4729773b12e..afd14b7843e 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs @@ -7,7 +7,17 @@ fn foo<const N: usize>(_: [u8; N]) -> [u8; N] { [0; N] } +fn bar() { + let _x: [u8; 3] = [0; _]; + //[normal]~^ ERROR: using `_` for array lengths is unstable + //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment + let _y: [u8; _] = [0; 3]; + //[normal]~^ ERROR: using `_` for array lengths is unstable + //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment +} + fn main() { let _x = foo::<_>([1,2]); //[normal]~^ ERROR: type provided when a constant was expected + let _y = bar(); } diff --git a/src/test/ui/inference/char-as-str-multi.rs b/src/test/ui/inference/char-as-str-multi.rs new file mode 100644 index 00000000000..21bbc6f20b2 --- /dev/null +++ b/src/test/ui/inference/char-as-str-multi.rs @@ -0,0 +1,6 @@ +// When a MULTI-character string literal is used where a char should be, +// DO NOT suggest changing to single quotes. + +fn main() { + let _: char = "foo"; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/char-as-str-multi.stderr b/src/test/ui/inference/char-as-str-multi.stderr new file mode 100644 index 00000000000..c3ba17a5579 --- /dev/null +++ b/src/test/ui/inference/char-as-str-multi.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/char-as-str-multi.rs:5:19 + | +LL | let _: char = "foo"; + | ---- ^^^^^ expected `char`, found `&str` + | | + | expected due to this + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed new file mode 100644 index 00000000000..e401492a830 --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.fixed @@ -0,0 +1,11 @@ +// When a SINGLE-character string literal is used where a char should be, +// suggest changing to single quotes. + +// Testing both single-byte and multi-byte characters, as we should handle both. + +// run-rustfix + +fn main() { + let _: char = 'a'; //~ ERROR mismatched types + let _: char = '人'; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs new file mode 100644 index 00000000000..4f23cea5354 --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.rs @@ -0,0 +1,11 @@ +// When a SINGLE-character string literal is used where a char should be, +// suggest changing to single quotes. + +// Testing both single-byte and multi-byte characters, as we should handle both. + +// run-rustfix + +fn main() { + let _: char = "a"; //~ ERROR mismatched types + let _: char = "人"; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr new file mode 100644 index 00000000000..29075c15414 --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/char-as-str-single.rs:9:19 + | +LL | let _: char = "a"; + | ---- ^^^ expected `char`, found `&str` + | | + | expected due to this + | +help: if you meant to write a `char` literal, use single quotes + | +LL | let _: char = 'a'; + | ~~~ + +error[E0308]: mismatched types + --> $DIR/char-as-str-single.rs:10:19 + | +LL | let _: char = "人"; + | ---- ^^^^ expected `char`, found `&str` + | | + | expected due to this + | +help: if you meant to write a `char` literal, use single quotes + | +LL | let _: char = '人'; + | ~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed new file mode 100644 index 00000000000..09f3dec5a17 --- /dev/null +++ b/src/test/ui/inference/str-as-char.fixed @@ -0,0 +1,8 @@ +// When a char literal is used where a str should be, +// suggest changing to double quotes. + +// run-rustfix + +fn main() { + let _: &str = "a"; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs new file mode 100644 index 00000000000..7092a612442 --- /dev/null +++ b/src/test/ui/inference/str-as-char.rs @@ -0,0 +1,8 @@ +// When a char literal is used where a str should be, +// suggest changing to double quotes. + +// run-rustfix + +fn main() { + let _: &str = 'a'; //~ ERROR mismatched types +} diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr new file mode 100644 index 00000000000..ebbe7c80f77 --- /dev/null +++ b/src/test/ui/inference/str-as-char.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/str-as-char.rs:7:19 + | +LL | let _: &str = 'a'; + | ---- ^^^ expected `&str`, found `char` + | | + | expected due to this + | +help: if you meant to write a `str` literal, use double quotes + | +LL | let _: &str = "a"; + | ~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-23589.stderr b/src/test/ui/issues/issue-23589.stderr index d126e1bf0b5..e065e17c280 100644 --- a/src/test/ui/issues/issue-23589.stderr +++ b/src/test/ui/issues/issue-23589.stderr @@ -12,6 +12,11 @@ error[E0308]: mismatched types | LL | let v: Vec(&str) = vec!['1', '2']; | ^^^ expected `&str`, found `char` + | +help: if you meant to write a `str` literal, use double quotes + | +LL | let v: Vec(&str) = vec!["1", '2']; + | ~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index e4e9705b07d..52ee1db5b15 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -5,7 +5,6 @@ LL | let _result = &mut Some(42).as_deref_mut(); | ^^^^^^^^^^^^ method cannot be called on `Option<{integer}>` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: - `{integer}: DerefMut` `{integer}: Deref` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 98a7091dd05..018557881ef 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -5,7 +5,6 @@ LL | let _result = &mut Ok(42).as_deref_mut(); | ^^^^^^^^^^^^ method cannot be called on `Result<{integer}, _>` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: - `{integer}: DerefMut` `{integer}: Deref` error: aborting due to previous error diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index 343a26c14a9..90983f35a5e 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -661,9 +661,9 @@ fn test_pat() { assert_eq!(stringify_pat!(ref mut _x @ _), "ref mut _x @ _"); // PatKind::Struct - assert_eq!(stringify_pat!(Struct {}), "Struct { }"); // FIXME - assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> { }"); - assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> { }"); + assert_eq!(stringify_pat!(Struct {}), "Struct {}"); + assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> {}"); + assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> {}"); assert_eq!(stringify_pat!(Struct { x }), "Struct { x }"); assert_eq!(stringify_pat!(Struct { x: _x }), "Struct { x: _x }"); assert_eq!(stringify_pat!(Struct { .. }), "Struct { .. }"); @@ -672,7 +672,7 @@ fn test_pat() { #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151 assert_eq!( stringify_pat!(<Struct as Trait>::Type {}), - "<Struct as Trait>::Type { }", + "<Struct as Trait>::Type {}", ); // PatKind::TupleStruct diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs index f85c10d78c5..6303c6e6a5d 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs @@ -3,5 +3,5 @@ struct Foo; fn main() { let a: Result<(), Foo> = Ok(()); a.unwrap(); - //~^ ERROR the method + //~^ ERROR `Foo` doesn't implement `Debug` } diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr index 596b7bfe79c..dc73bcd6e4d 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -1,19 +1,17 @@ -error[E0599]: the method `unwrap` exists for enum `Result<(), Foo>`, but its trait bounds were not satisfied +error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/method-help-unsatisfied-bound.rs:5:7 | -LL | struct Foo; - | ----------- doesn't satisfy `Foo: Debug` -... LL | a.unwrap(); - | ^^^^^^ method cannot be called on `Result<(), Foo>` due to unsatisfied trait bounds + | ^^^^^^ `Foo` cannot be formatted using `{:?}` | - = note: the following trait bounds were not satisfied: - `Foo: Debug` -help: consider annotating `Foo` with `#[derive(Debug)]` - | -LL | #[derive(Debug)] + = help: the trait `Debug` is not implemented for `Foo` + = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` +note: required by a bound in `Result::<T, E>::unwrap` + --> $SRC_DIR/core/src/result.rs:LL:COL | +LL | E: fmt::Debug, + | ^^^^^^^^^^ required by this bound in `Result::<T, E>::unwrap` error: aborting due to previous error -For more information about this error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/panics/panic-short-backtrace-windows-x86_64.rs b/src/test/ui/panics/panic-short-backtrace-windows-x86_64.rs index fd01337296f..39ffe86dd49 100644 --- a/src/test/ui/panics/panic-short-backtrace-windows-x86_64.rs +++ b/src/test/ui/panics/panic-short-backtrace-windows-x86_64.rs @@ -1,3 +1,7 @@ +// This test has been spuriously failing a lot recently (#92000). +// Ignore it until the underlying issue is fixed. +// ignore-test + // Regression test for #87481: short backtrace formatting cut off the entire stack trace. // Codegen-units is specified here so that we can replicate a typical rustc invocation which diff --git a/src/test/ui/suggestions/while-let-typo.rs b/src/test/ui/suggestions/while-let-typo.rs new file mode 100644 index 00000000000..dbbcdee3c19 --- /dev/null +++ b/src/test/ui/suggestions/while-let-typo.rs @@ -0,0 +1,9 @@ +fn main() { + let foo = Some(0); + let bar = None; + while Some(x) = foo {} //~ ERROR cannot find value `x` in this scope + while Some(foo) = bar {} + while 3 = foo {} //~ ERROR mismatched types + while Some(3) = foo {} //~ ERROR invalid left-hand side of assignment + while x = 5 {} //~ ERROR cannot find value `x` in this scope +} diff --git a/src/test/ui/suggestions/while-let-typo.stderr b/src/test/ui/suggestions/while-let-typo.stderr new file mode 100644 index 00000000000..7cc2ed3149b --- /dev/null +++ b/src/test/ui/suggestions/while-let-typo.stderr @@ -0,0 +1,45 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/while-let-typo.rs:4:16 + | +LL | while Some(x) = foo {} + | ^ not found in this scope + | +help: you might have meant to use pattern matching + | +LL | while let Some(x) = foo {} + | +++ + +error[E0425]: cannot find value `x` in this scope + --> $DIR/while-let-typo.rs:8:11 + | +LL | while x = 5 {} + | ^ not found in this scope + | +help: you might have meant to use pattern matching + | +LL | while let x = 5 {} + | +++ + +error[E0308]: mismatched types + --> $DIR/while-let-typo.rs:6:11 + | +LL | while 3 = foo {} + | ^^^^^^^ expected `bool`, found `()` + +error[E0070]: invalid left-hand side of assignment + --> $DIR/while-let-typo.rs:7:19 + | +LL | while Some(3) = foo {} + | - ^ + | | + | cannot assign to this expression + | +help: you might have meant to use pattern destructuring + | +LL | while let Some(3) = foo {} + | +++ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0070, E0308, E0425. +For more information about an error, try `rustc --explain E0070`. diff --git a/src/tools/cargo b/src/tools/cargo -Subproject fcef61230c3b6213b6b0d233a36ba4ebd1649ec +Subproject 358e79fe56fe374649275ca7aebaafd57ade0e8 diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 47c0a84cd46..af36f726700 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -59,6 +59,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx if let ItemKind::Struct(data, _) = &item.kind; if let Some(last_field) = data.fields().last(); if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind; + if let rustc_hir::ArrayLen::Body(length) = length; // Then check if that that array zero-sized let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c1b811c2174..9b06ca4e824 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::{ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; +use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{Ident, Symbol}; @@ -567,7 +567,14 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, value, length); kind!("Repeat({value}, {length})"); self.expr(value); - self.body(field!(length.body)); + match length.value { + ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"), + ArrayLen::Body(anon_const) => { + bind!(self, anon_const); + out!("if let ArrayLen::Body({anon_const}) = {length};"); + self.body(field!(anon_const.body)); + } + } }, ExprKind::Err => kind!("Err"), ExprKind::DropTemps(expr) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index abf4826a069..c96766e5678 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -334,12 +334,17 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}anon_const:", ind); print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); }, - hir::ExprKind::Repeat(val, ref anon_const) => { + hir::ExprKind::Repeat(val, length) => { println!("{}Repeat", ind); println!("{}value:", ind); print_expr(cx, val, indent + 1); println!("{}repeat count:", ind); - print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); + match length { + hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind), + hir::ArrayLen::Body(anon_const) => { + print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1) + } + } }, hir::ExprKind::Err => { println!("{}Err", ind); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index ad50759effa..ac2b1a0259e 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::HirIdMap; use rustc_hir::{ BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt, - StmtKind, Ty, TyKind, TypeBinding, + StmtKind, Ty, TyKind, TypeBinding, ArrayLen }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -170,6 +170,14 @@ impl HirEqInterExpr<'_, '_, '_> { } } + pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool { + match (left, right) { + (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true, + (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body), + (_, _) => false, + } + } + pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool { let cx = self.inner.cx; let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value); @@ -194,8 +202,8 @@ impl HirEqInterExpr<'_, '_, '_> { } let is_eq = match ( - &reduce_exprkind(self.inner.cx, &left.kind), - &reduce_exprkind(self.inner.cx, &right.kind), + reduce_exprkind(self.inner.cx, &left.kind), + reduce_exprkind(self.inner.cx, &right.kind), ) { (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => { lb == rb && l_mut == r_mut && self.eq_expr(le, re) @@ -232,7 +240,7 @@ impl HirEqInterExpr<'_, '_, '_> { }, (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => { - self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r)) + self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r)) }, (&ExprKind::Let(l), &ExprKind::Let(r)) => { self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init) @@ -253,8 +261,8 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => { self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) }, - (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => { - self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body) + (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => { + self.eq_expr(le, re) && self.eq_array_length(ll, rl) }, (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)), (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r), @@ -391,8 +399,8 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { match (&left.kind, &right.kind) { (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), - (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => { - self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body) + (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => { + self.eq_ty(lt, rt) && self.eq_array_length(ll, rl) }, (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => { l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty) @@ -714,9 +722,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::ConstBlock(ref l_id) => { self.hash_body(l_id.body); }, - ExprKind::Repeat(e, ref l_id) => { + ExprKind::Repeat(e, len) => { self.hash_expr(e); - self.hash_body(l_id.body); + self.hash_array_length(len); }, ExprKind::Ret(ref e) => { if let Some(e) = *e { @@ -906,9 +914,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { TyKind::Slice(ty) => { self.hash_ty(ty); }, - TyKind::Array(ty, anon_const) => { + &TyKind::Array(ty, len) => { self.hash_ty(ty); - self.hash_body(anon_const.body); + self.hash_array_length(len); }, TyKind::Ptr(ref mut_ty) => { self.hash_ty(mut_ty.ty); @@ -953,6 +961,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } + pub fn hash_array_length(&mut self, length: ArrayLen) { + match length { + ArrayLen::Infer(..) => {} + ArrayLen::Body(anon_const) => self.hash_body(anon_const.body), + } + } + pub fn hash_body(&mut self, body_id: BodyId) { // swap out TypeckResults when hashing a body let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id)); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 54d470ca738..9179e67c4f4 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -79,7 +79,7 @@ use rustc_hir::{ def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, - TraitItemKind, TraitRef, TyKind, UnOp, + TraitItemKind, TraitRef, TyKind, UnOp, ArrayLen }; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; @@ -703,8 +703,9 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { _ => false, }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), - ExprKind::Repeat(x, y) => if_chain! { - if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind; + ExprKind::Repeat(x, len) => if_chain! { + if let ArrayLen::Body(len) = len; + if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind; if let LitKind::Int(v, _) = const_lit.node; if v <= 32 && is_default_equivalent(cx, x); then { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 1a4da1627b7..836558b07cb 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -193,7 +193,6 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv } }, Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), - Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout index f16350e4b5e..471bbce4f41 100644 --- a/src/tools/clippy/tests/ui/author/repeat.stdout +++ b/src/tools/clippy/tests/ui/author/repeat.stdout @@ -2,7 +2,8 @@ if_chain! { if let ExprKind::Repeat(value, length) = expr.kind; if let ExprKind::Lit(ref lit) = value.kind; if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node; - let expr1 = &cx.tcx.hir().body(length.body).value; + if let ArrayLen::Body(anon_const) = length; + let expr1 = &cx.tcx.hir().body(anon_const.body).value; if let ExprKind::Lit(ref lit1) = expr1.kind; if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node; then { |
