diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index 0065960507179..24f4321389713 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -5,8 +5,6 @@ title: Tracking Issue for XXX labels: C-tracking-issue --- <!-- -NOTE: For library features, please use the "Library Tracking Issue" template instead. - Thank you for creating a tracking issue! 📜 Tracking issues are for tracking a feature from implementation to stabilisation. Make sure to include the relevant RFC for the feature if it has one. Otherwise provide a short summary of the diff --git a/Cargo.lock b/Cargo.lock index 9d726b240da93..b2ae22b6abd9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,7 +427,6 @@ dependencies = [ "remove_dir_all", "serde_json", "tar", - "toml", "url 2.1.1", ] @@ -3551,6 +3550,7 @@ version = "0.0.0" dependencies = [ "rustc_ast", "rustc_span", + "rustc_target", "tracing", ] @@ -3568,6 +3568,7 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", + "version_check", ] [[package]] diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 9ac05f316f034..00354b42ebb7c 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -127,10 +127,14 @@ where } pub trait CreateTokenStream: sync::Send + sync::Sync { + fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream>; fn create_token_stream(&self) -> TokenStream; } impl CreateTokenStream for TokenStream { + fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> { + panic!("Cannot call `add_trailing_semi` on a `TokenStream`!"); + } fn create_token_stream(&self) -> TokenStream { self.clone() } @@ -147,6 +151,13 @@ impl LazyTokenStream { LazyTokenStream(Lrc::new(Box::new(inner))) } + /// Extends the captured stream by one token, + /// which must be a trailing semicolon. This + /// affects the `TokenStream` created by `make_tokenstream`. + pub fn add_trailing_semi(&self) -> LazyTokenStream { + LazyTokenStream(Lrc::new(self.0.add_trailing_semi())) + } + pub fn create_token_stream(&self) -> TokenStream { self.0.create_token_stream() } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4d6afd2fe0d08..1b9ccbd850bee 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -10,9 +10,9 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_session::parse::feature_err; +use rustc_span::hygiene::ForLoopLoc; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP}; use rustc_target::asm; use std::collections::hash_map::Entry; use std::fmt::Write; @@ -102,7 +102,6 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_block(body, false), opt_label, hir::LoopSource::Loop, - DUMMY_SP, ) }), ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body), @@ -454,12 +453,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar); // `[opt_ident]: loop { ... }` - hir::ExprKind::Loop( - self.block_expr(self.arena.alloc(match_expr)), - opt_label, - source, - span.with_hi(cond.span.hi()), - ) + hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source) } /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`, @@ -754,7 +748,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // loop { .. } let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, - kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span), + kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop), span, attrs: ThinVec::new(), }); @@ -776,7 +770,10 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, ) -> hir::ExprKind<'hir> { - let (body_id, generator_option) = self.with_new_scopes(move |this| { + // Lower outside new scope to preserve `is_in_loop_condition`. + let fn_decl = self.lower_fn_decl(decl, None, false, None); + + self.with_new_scopes(move |this| { let prev = this.current_item; this.current_item = Some(fn_decl_span); let mut generator_kind = None; @@ -788,13 +785,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let generator_option = this.generator_movability_for_fn(&decl, fn_decl_span, generator_kind, movability); this.current_item = prev; - (body_id, generator_option) - }); - - // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl(decl, None, false, None); - - hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option) + hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option) + }) } fn generator_movability_for_fn( @@ -840,8 +832,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + // We need to lower the declaration outside the new scope, because we + // have to conserve the state of being inside a loop condition for the + // closure argument types. + let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None); - let body_id = self.with_new_scopes(|this| { + self.with_new_scopes(move |this| { // FIXME(cramertj): allow `async` non-`move` closures with arguments. if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { struct_span_err!( @@ -872,15 +868,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.expr(fn_decl_span, async_body, ThinVec::new()) }); - body_id - }); - - // We need to lower the declaration outside the new scope, because we - // have to conserve the state of being inside a loop condition for the - // closure argument types. - let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None); - - hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None) + hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None) + }) } /// Destructure the LHS of complex assignments. @@ -1720,12 +1709,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // `[opt_ident]: loop { ... }` - let kind = hir::ExprKind::Loop( - loop_block, - opt_label, - hir::LoopSource::ForLoop, - e.span.with_hi(orig_head_span.hi()), - ); + let kind = hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::ForLoop); let loop_expr = self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 6ea942a2f3018..f447bc7f4efba 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -11,3 +11,4 @@ doctest = false tracing = "0.1" rustc_span = { path = "../rustc_span" } rustc_ast = { path = "../rustc_ast" } +rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml index dc0711a5b0f30..5f941a0a650f8 100644 --- a/compiler/rustc_attr/Cargo.toml +++ b/compiler/rustc_attr/Cargo.toml @@ -18,3 +18,4 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_ast = { path = "../rustc_ast" } +version_check = "0.9" diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 494880701844e..ead90f23ce7a1 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -10,6 +10,7 @@ use rustc_session::Session; use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; use std::num::NonZeroU32; +use version_check::Version; pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() @@ -66,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { } } -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Encodable, Decodable)] pub enum InlineAttr { None, Hint, @@ -74,13 +75,13 @@ pub enum InlineAttr { Never, } -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable)] pub enum InstructionSetAttr { ArmA32, ArmT32, } -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable)] pub enum OptimizeAttr { None, Speed, @@ -525,26 +526,6 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F } } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct Version { - major: u16, - minor: u16, - patch: u16, -} - -fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> { - let mut components = s.split('-'); - let d = components.next()?; - if !allow_appendix && components.next().is_some() { - return None; - } - let mut digits = d.splitn(3, '.'); - let major = digits.next()?.parse().ok()?; - let minor = digits.next()?.parse().ok()?; - let patch = digits.next().unwrap_or("0").parse().ok()?; - Some(Version { major, minor, patch }) -} - /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( @@ -574,21 +555,16 @@ pub fn eval_condition( return false; } }; - let min_version = match parse_version(&min_version.as_str(), false) { + let min_version = match Version::parse(&min_version.as_str()) { Some(ver) => ver, None => { - sess.span_diagnostic - .struct_span_warn( - *span, - "unknown version literal format, assuming it refers to a future version", - ) - .emit(); + sess.span_diagnostic.struct_span_err(*span, "invalid version literal").emit(); return false; } }; let channel = env!("CFG_RELEASE_CHANNEL"); let nightly = channel == "nightly" || channel == "dev"; - let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap(); + let rustc_version = Version::parse(env!("CFG_RELEASE")).unwrap(); // See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details if nightly { rustc_version > min_version } else { rustc_version >= min_version } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index f82269c4eee4f..bb6d3f6a0076c 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -12,43 +12,27 @@ use rustc_span::{Span, DUMMY_SP}; pub fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, - span: Span, + sp: Span, tts: TokenStream, ) -> Box<dyn MacResult + 'cx> { - let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { + let Assert { cond_expr, custom_message } = match parse_assert(cx, sp, tts) { Ok(assert) => assert, Err(mut err) => { err.emit(); - return DummyResult::any(span); + return DummyResult::any(sp); } }; // `core::panic` and `std::panic` are different macros, so we use call-site // context to pick up whichever is currently in scope. - let sp = cx.with_call_site_ctxt(span); + let sp = cx.with_call_site_ctxt(sp); let panic_call = if let Some(tokens) = custom_message { - let path = if span.rust_2021() { - // On edition 2021, we always call `$crate::panic!()`. - Path { - span: sp, - segments: cx - .std_path(&[sym::panic]) - .into_iter() - .map(|ident| PathSegment::from_ident(ident)) - .collect(), - tokens: None, - } - } else { - // Before edition 2021, we call `panic!()` unqualified, - // such that it calls either `std::panic!()` or `core::panic!()`. - Path::from_ident(Ident::new(sym::panic, sp)) - }; // Pass the custom message to panic!(). cx.expr( sp, ExprKind::MacCall(MacCall { - path, + path: Path::from_ident(Ident::new(sym::panic, sp)), args: P(MacArgs::Delimited( DelimSpan::from_single(sp), MacDelimiter::Parenthesis, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 28efd483c8670..f76bbd8381940 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -5,8 +5,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_expand::base::{self, *}; use rustc_expand::module::DirectoryOwnership; -use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_parse::{self, new_parser_from_file}; +use rustc_parse::{self, new_parser_from_file, parser::Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::symbol::Symbol; use rustc_span::{self, Pos, Span}; @@ -140,7 +139,7 @@ pub fn expand_include<'cx>( fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> { let mut ret = SmallVec::new(); while self.p.token != token::Eof { - match self.p.parse_item(ForceCollect::No) { + match self.p.parse_item() { Err(mut err) => { err.emit(); break; diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a78d692aaa7fb..700f32e15b952 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -13,7 +13,6 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{OptLevel, SanitizerSet}; use rustc_session::Session; -use rustc_target::spec::StackProbeType; use crate::attributes; use crate::llvm::AttributePlace::Function; @@ -99,6 +98,12 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { } fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { + // Only use stack probes if the target specification indicates that we + // should be using stack probes + if !cx.sess().target.stack_probes { + return; + } + // Currently stack probes seem somewhat incompatible with the address // sanitizer and thread sanitizer. With asan we're already protected from // stack overflow anyway so we don't really need stack probes regardless. @@ -122,31 +127,19 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { return; } - let attr_value = match cx.sess().target.stack_probes { - StackProbeType::None => None, - // Request LLVM to generate the probes inline. If the given LLVM version does not support - // this, no probe is generated at all (even if the attribute is specified). - StackProbeType::Inline => Some(const_cstr!("inline-asm")), - // Flag our internal `__rust_probestack` function as the stack probe symbol. - // This is defined in the `compiler-builtins` crate for each architecture. - StackProbeType::Call => Some(const_cstr!("__rust_probestack")), - // Pick from the two above based on the LLVM version. - StackProbeType::InlineOrCall { min_llvm_version_for_inline } => { - if llvm_util::get_version() < min_llvm_version_for_inline { - Some(const_cstr!("__rust_probestack")) - } else { - Some(const_cstr!("inline-asm")) - } - } - }; - if let Some(attr_value) = attr_value { - llvm::AddFunctionAttrStringValue( - llfn, - llvm::AttributePlace::Function, - const_cstr!("probe-stack"), - attr_value, - ); - } + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + const_cstr!("probe-stack"), + if llvm_util::get_version() < (11, 0, 1) { + // Flag our internal `__rust_probestack` function as the stack probe symbol. + // This is defined in the `compiler-builtins` crate for each architecture. + const_cstr!("__rust_probestack") + } else { + // On LLVM 11+, emit inline asm for stack probes instead of a function call. + const_cstr!("inline-asm") + }, + ); } pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 72e049b6d7469..e51904f308dd4 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -885,22 +885,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke } fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { - fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf { - let session_tlib = - filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple()); - let path = session_tlib.join(&filename); - if path.exists() { - return session_tlib; - } else { - let default_sysroot = filesearch::get_or_default_sysroot(); - let default_tlib = filesearch::make_target_lib_path( - &default_sysroot, - sess.opts.target_triple.triple(), - ); - return default_tlib; - } - } - + let default_sysroot = filesearch::get_or_default_sysroot(); + let default_tlib = + filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple()); let channel = option_env!("CFG_RELEASE_CHANNEL") .map(|channel| format!("-{}", channel)) .unwrap_or_default(); @@ -911,11 +898,10 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { // LLVM will link to `@rpath/*.dylib`, so we need to specify an // rpath to the library as well (the rpath should be absolute, see // PR #41352 for details). - let filename = format!("rustc{}_rt.{}", channel, name); - let path = find_sanitizer_runtime(&sess, &filename); - let rpath = path.to_str().expect("non-utf8 component in path"); + let libname = format!("rustc{}_rt.{}", channel, name); + let rpath = default_tlib.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); - linker.link_dylib(Symbol::intern(&filename)); + linker.link_dylib(Symbol::intern(&libname)); } "aarch64-fuchsia" | "aarch64-unknown-linux-gnu" @@ -923,7 +909,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { | "x86_64-unknown-freebsd" | "x86_64-unknown-linux-gnu" => { let filename = format!("librustc{}_rt.{}.a", channel, name); - let path = find_sanitizer_runtime(&sess, &filename).join(&filename); + let path = default_tlib.join(&filename); linker.link_whole_rlib(&path); } _ => {} diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b205ea9cf6c9d..2ce5fe5ad504b 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -783,7 +783,7 @@ impl CrateInfo { } } -pub fn provide(providers: &mut Providers) { +pub fn provide_both(providers: &mut Providers) { providers.backend_optimization_level = |tcx, cratenum| { let for_speed = match tcx.sess.opts.optimize { // If globally no optimisation is done, #[optimize] has no effect. diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 0307117e1c8b2..e27eac3f69b00 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -160,12 +160,13 @@ pub struct CodegenResults { pub fn provide(providers: &mut Providers) { crate::back::symbol_export::provide(providers); - crate::base::provide(providers); + crate::base::provide_both(providers); crate::target_features::provide(providers); } pub fn provide_extern(providers: &mut Providers) { crate::back::symbol_export::provide_extern(providers); + crate::base::provide_both(providers); } /// Checks if the given filename ends with the `.rcgu.o` extension that `rustc` diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index fd0ff5b66e607..b1e372afc6501 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -119,7 +119,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { ) ); if is_consume { - let base_ty = place_base.ty(self.fx.mir, cx.tcx()); + let base_ty = mir::PlaceRef::ty(&place_base, self.fx.mir, cx.tcx()); let base_ty = self.fx.monomorphize(base_ty); // ZSTs don't require any actual memory access. diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 66d9d1a1e0c49..958e4ebd078b6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -506,7 +506,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); - let place_ty = place_ref.ty(self.mir, tcx); + let place_ty = mir::PlaceRef::ty(&place_ref, self.mir, tcx); self.monomorphize(place_ty.ty) } } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index ad62e3c9fc8f4..1cfbce2355e3a 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -8,6 +8,7 @@ use super::iterate::reverse_post_order; use super::ControlFlowGraph; use rustc_index::vec::{Idx, IndexVec}; +use std::borrow::BorrowMut; use std::cmp::Ordering; #[cfg(test)] @@ -19,17 +20,22 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { dominators_given_rpo(graph, &rpo) } -fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Dominators<G::Node> { - let start_node = graph.start_node(); +fn dominators_given_rpo<G: ControlFlowGraph + BorrowMut<G>>( + mut graph: G, + rpo: &[G::Node], +) -> Dominators<G::Node> { + let start_node = graph.borrow().start_node(); assert_eq!(rpo[0], start_node); // compute the post order index (rank) for each node - let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes()); + let mut post_order_rank: IndexVec<G::Node, usize> = + (0..graph.borrow().num_nodes()).map(|_| 0).collect(); for (index, node) in rpo.iter().rev().cloned().enumerate() { post_order_rank[node] = index; } - let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes()); + let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> = + (0..graph.borrow().num_nodes()).map(|_| None).collect(); immediate_dominators[start_node] = Some(start_node); let mut changed = true; @@ -38,7 +44,7 @@ fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Domin for &node in &rpo[1..] { let mut new_idom = None; - for pred in graph.predecessors(node) { + for pred in graph.borrow_mut().predecessors(node) { if immediate_dominators[pred].is_some() { // (*) dominators for `pred` have been calculated new_idom = Some(if let Some(new_idom) = new_idom { diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 3850c9b74fddc..579eb1cb7da66 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -552,7 +552,6 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>( /// A vector container that makes sure that its items are hashed in a stable /// order. -#[derive(Debug)] pub struct StableVec<T>(Vec<T>); impl<T> StableVec<T> { diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 30f659c2f71bd..7f9e4160fcdde 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -21,7 +21,6 @@ use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; /// -- once the value is stolen -- it will never be read from again. // // FIXME(#41710): what is the best way to model linear queries? -#[derive(Debug)] pub struct Steal<T> { value: RwLock<Option<T>>, } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5d398935ce815..16913dbb1abf8 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -20,7 +20,7 @@ use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{struct_span_err, Applicability, PResult}; use rustc_feature::Features; -use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser}; +use rustc_parse::parser::{AttemptLocalParseRecovery, Parser}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; @@ -913,7 +913,7 @@ pub fn parse_ast_fragment<'a>( Ok(match kind { AstFragmentKind::Items => { let mut items = SmallVec::new(); - while let Some(item) = this.parse_item(ForceCollect::No)? { + while let Some(item) = this.parse_item()? { items.push(item); } AstFragment::Items(items) diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index f4fcaf5c0a452..643305f153ccd 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -8,7 +8,6 @@ use rustc_ast::{self as ast, PatKind}; use rustc_ast_pretty::pprust::item_to_string; use rustc_errors::PResult; use rustc_parse::new_parser_from_source_str; -use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{kw, sym, Symbol}; @@ -30,7 +29,7 @@ fn parse_item_from_source_str( source: String, sess: &ParseSess, ) -> PResult<'_, Option<P<ast::Item>>> { - new_parser_from_source_str(sess, name, source).parse_item(ForceCollect::No) + new_parser_from_source_str(sess, name, source).parse_item() } // Produces a `rustc_span::span`. @@ -45,7 +44,7 @@ fn string_to_expr(source_str: String) -> P<ast::Expr> { /// Parses a string, returns an item. fn string_to_item(source_str: String) -> Option<P<ast::Item>> { - with_error_checking_parse(source_str, &sess(), |p| p.parse_item(ForceCollect::No)) + with_error_checking_parse(source_str, &sess(), |p| p.parse_item()) } #[should_panic] diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 6779734cfc176..02129e9b5e548 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -9,7 +9,6 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability, ErrorReported}; use rustc_lexer::is_ident; use rustc_parse::nt_to_tokenstream; -use rustc_parse::parser::ForceCollect; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -118,7 +117,7 @@ impl MultiItemModifier for ProcMacroDerive { let mut items = vec![]; loop { - match parser.parse_item(ForceCollect::No) { + match parser.parse_item() { Ok(None) => break, Ok(Some(item)) => { if is_stmt { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index cd3c8fded633f..b9d1597c4c65f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -36,7 +36,7 @@ macro_rules! declare_features { ),+]; /// A set of features to be used by later passes. - #[derive(Clone, Default, Debug)] + #[derive(Clone, Default)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 6a1b9bdbb9491..d5ade86593e56 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -419,10 +419,6 @@ impl Definitions { pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) { self.parent_modules_of_macro_defs.insert(expn_id, module); } - - pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ { - self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k) - } } #[derive(Copy, Clone, PartialEq, Debug)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 35170fa7c1d02..3673e5c8bf3a5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1617,9 +1617,7 @@ pub enum ExprKind<'hir> { /// A conditionless loop (can be exited with `break`, `continue`, or `return`). /// /// I.e., `'label: loop { <block> }`. - /// - /// The `Span` is the loop header (`for x in y`/`while let pat = expr`). - Loop(&'hir Block<'hir>, Option<Label>, LoopSource, Span), + Loop(&'hir Block<'hir>, Option<Label>, LoopSource), /// A `match` block, with a source that indicates whether or not it is /// the result of a desugaring, and if so, which kind. Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6c1bee2335a00..8707a84a98fcc 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1151,7 +1151,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(then); walk_list!(visitor, visit_expr, else_opt); } - ExprKind::Loop(ref block, ref opt_label, _, _) => { + ExprKind::Loop(ref block, ref opt_label, _) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 26ce30cb51177..e82ea310b8cc5 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -67,7 +67,7 @@ macro_rules! language_item_table { } } - #[derive(HashStable_Generic, Debug)] + #[derive(HashStable_Generic)] pub struct LanguageItems { /// Mappings from lang items to their possibly found `DefId`s. /// The index corresponds to the order in `LangItem`. diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f1c2a6b7e6e85..a3ab1d96e1dfe 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1396,7 +1396,7 @@ impl<'a> State<'a> { hir::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e)); } - hir::ExprKind::Loop(ref blk, opt_label, _, _) => { + hir::ExprKind::Loop(ref blk, opt_label, _) => { if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7031234e1089d..ead2512d3b2a5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1017,6 +1017,13 @@ pub fn start_codegen<'tcx>( tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx)); tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx)); + // We assume that no queries are run past here. If there are new queries + // after this point, they'll show up as "<unknown>" in self-profiling data. + { + let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings"); + tcx.alloc_self_profile_query_strings(); + } + info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index ac6b6d0311545..9c49f926d417b 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -417,19 +417,9 @@ impl Compiler { let queries = Queries::new(&self); let ret = f(&queries); - // NOTE: intentionally does not compute the global context if it hasn't been built yet, - // since that likely means there was a parse error. - if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() { - // We assume that no queries are run past here. If there are new queries - // after this point, they'll show up as "<unknown>" in self-profiling data. - { - let _prof_timer = - queries.session().prof.generic_activity("self_profile_alloc_query_strings"); - gcx.enter(|tcx| tcx.alloc_self_profile_query_strings()); - } - - if self.session().opts.debugging_opts.query_stats { - gcx.print_stats(); + if self.session().opts.debugging_opts.query_stats { + if let Ok(gcx) = queries.global_ctxt() { + gcx.peek_mut().print_stats(); } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b37660e4a90d3..8cdb33ea3175f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -96,24 +96,18 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr { impl EarlyLintPass for WhileTrue { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ast::ExprKind::While(cond, _, label) = &e.kind { + if let ast::ExprKind::While(cond, ..) = &e.kind { if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { if let ast::LitKind::Bool(true) = lit.kind { if !lit.span.from_expansion() { let msg = "denote infinite loops with `loop { ... }`"; - let condition_span = e.span.with_hi(cond.span.hi()); + let condition_span = cx.sess.source_map().guess_head_span(e.span); cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { lint.build(msg) .span_suggestion_short( condition_span, "use `loop`", - format!( - "{}loop", - label.map_or_else(String::new, |label| format!( - "{}: ", - label.ident, - )) - ), + "loop".to_owned(), Applicability::MachineApplicable, ) .emit(); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b17765998807f..3971a3099823f 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -387,7 +387,7 @@ impl LintStore { Some(new_name.to_owned()), ), Some(&Removed(ref reason)) => CheckLintNameResult::Warning( - format!("lint `{}` has been removed: {}", complete_name, reason), + format!("lint `{}` has been removed: `{}`", complete_name, reason), None, ), None => match self.lint_groups.get(&*complete_name) { diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index e36af2349360f..08c147ec3ac3f 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -379,9 +379,17 @@ pub fn check_ast_crate<T: EarlyLintPass>( // All of the buffered lints should have been emitted at this point. // If not, that means that we somehow buffered a lint for a node id // that was not lint-checked (perhaps it doesn't exist?). This is a bug. - for (_id, lints) in buffered.map { - for early_lint in lints { - sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); + // + // Rustdoc runs everybody-loops before the early lints and removes + // function bodies, so it's totally possible for linted + // node ids to not exist (e.g., macros defined within functions for the + // unused_macro lint) anymore. So we only run this check + // when we're not in rustdoc mode. (see issue #47639) + if !sess.opts.actually_rustdoc { + for (_id, lints) in buffered.map { + for early_lint in lints { + sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); + } } } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 18cd25e5d2aa3..fc8f84461f991 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -311,7 +311,8 @@ impl<'s> LintLevelsBuilder<'s> { |lint| { let msg = format!( "lint name `{}` is deprecated \ - and may not have an effect in the future.", + and may not have an effect in the future. \ + Also `cfg_attr(cargo-clippy)` won't be necessary anymore", name ); lint.build(&msg) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 658372ac336a8..20052ad9bfcbd 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -238,22 +238,41 @@ declare_lint! { /// /// ```rust,compile_fail /// #![allow(unconditional_panic)] - /// const C: i32 = 1/0; + /// let x: &'static i32 = &(1 / 0); /// ``` /// /// {{produces}} /// /// ### Explanation /// - /// This lint detects constants that fail to evaluate. Allowing the lint will accept the - /// constant declaration, but any use of this constant will still lead to a hard error. This is - /// a future incompatibility lint; the plan is to eventually entirely forbid even declaring - /// constants that cannot be evaluated. See [issue #71800] for more details. + /// This lint detects code that is very likely incorrect. If this lint is + /// allowed, then the code will not be evaluated at compile-time, and + /// instead continue to generate code to evaluate at runtime, which may + /// panic during runtime. /// - /// [issue #71800]: https://github.com/rust-lang/rust/issues/71800 + /// Note that this lint may trigger in either inside or outside of a + /// [const context]. Outside of a [const context], the compiler can + /// sometimes evaluate an expression at compile-time in order to generate + /// more efficient code. As the compiler becomes better at doing this, it + /// needs to decide what to do when it encounters code that it knows for + /// certain will panic or is otherwise incorrect. Making this a hard error + /// would prevent existing code that exhibited this behavior from + /// compiling, breaking backwards-compatibility. However, this is almost + /// certainly incorrect code, so this is a deny-by-default lint. For more + /// details, see [RFC 1229] and [issue #28238]. + /// + /// Note that there are several other more specific lints associated with + /// compile-time evaluation, such as [`arithmetic_overflow`], + /// [`unconditional_panic`]. + /// + /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context + /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md + /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238 + /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow + /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic pub CONST_ERR, Deny, - "constant evaluation encountered erroneous expression", + "constant evaluation detected erroneous expression", report_in_external_macro } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e3c3539079857..115569fc60d9f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -618,6 +618,43 @@ impl MetadataBlob { } } +impl EntryKind { + fn def_kind(&self) -> DefKind { + match *self { + EntryKind::AnonConst(..) => DefKind::AnonConst, + EntryKind::Const(..) => DefKind::Const, + EntryKind::AssocConst(..) => DefKind::AssocConst, + EntryKind::ImmStatic + | EntryKind::MutStatic + | EntryKind::ForeignImmStatic + | EntryKind::ForeignMutStatic => DefKind::Static, + EntryKind::Struct(_, _) => DefKind::Struct, + EntryKind::Union(_, _) => DefKind::Union, + EntryKind::Fn(_) | EntryKind::ForeignFn(_) => DefKind::Fn, + EntryKind::AssocFn(_) => DefKind::AssocFn, + EntryKind::Type => DefKind::TyAlias, + EntryKind::TypeParam => DefKind::TyParam, + EntryKind::ConstParam => DefKind::ConstParam, + EntryKind::OpaqueTy => DefKind::OpaqueTy, + EntryKind::AssocType(_) => DefKind::AssocTy, + EntryKind::Mod(_) => DefKind::Mod, + EntryKind::Variant(_) => DefKind::Variant, + EntryKind::Trait(_) => DefKind::Trait, + EntryKind::TraitAlias => DefKind::TraitAlias, + EntryKind::Enum(..) => DefKind::Enum, + EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang), + EntryKind::ProcMacro(kind) => DefKind::Macro(kind), + EntryKind::ForeignType => DefKind::ForeignTy, + EntryKind::Impl(_) => DefKind::Impl, + EntryKind::Closure => DefKind::Closure, + EntryKind::ForeignMod => DefKind::ForeignMod, + EntryKind::GlobalAsm => DefKind::GlobalAsm, + EntryKind::Field => DefKind::Field, + EntryKind::Generator(_) => DefKind::Generator, + } + } +} + impl CrateRoot<'_> { crate fn is_proc_macro_crate(&self) -> bool { self.proc_macro_data.is_some() @@ -648,6 +685,21 @@ impl CrateRoot<'_> { } impl<'a, 'tcx> CrateMetadataRef<'a> { + fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> { + self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) + } + + fn kind(&self, item_id: DefIndex) -> EntryKind { + self.maybe_kind(item_id).unwrap_or_else(|| { + bug!( + "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", + item_id, + self.root.name, + self.cnum, + ) + }) + } + fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. @@ -684,30 +736,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.try_item_ident(item_index, sess).unwrap() } - fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> { - self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) - } - - fn kind(&self, item_id: DefIndex) -> EntryKind { - self.maybe_kind(item_id).unwrap_or_else(|| { - bug!( - "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", - item_id, - self.root.name, - self.cnum, - ) - }) - } - - fn def_kind(&self, item_id: DefIndex) -> DefKind { - self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| { - bug!( - "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}", - item_id, - self.root.name, - self.cnum, - ) - }) + fn def_kind(&self, index: DefIndex) -> DefKind { + self.kind(index).def_kind() } fn get_span(&self, index: DefIndex, sess: &Session) -> Span { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 828c025d38d0b..17ce4a5f9520e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -130,7 +130,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, is_foreign_item => { cdata.is_foreign_item(def_id.index) } static_mutability => { cdata.static_mutability(def_id.index) } generator_kind => { cdata.generator_kind(def_id.index) } - opt_def_kind => { Some(cdata.def_kind(def_id.index)) } + def_kind => { cdata.def_kind(def_id.index) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } def_ident_span => { cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3961adacecae8..5e2674254b295 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,12 +1,13 @@ use crate::rmeta::table::{FixedSizeEncoding, TableBuilder}; use crate::rmeta::*; +use rustc_ast as ast; use rustc_data_structures::fingerprint::{Fingerprint, FingerprintEncoder}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{join, Lrc}; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind}; +use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -436,7 +437,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(&mut self) { let krate = self.tcx.hir().krate(); - self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module); + self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs); // Proc-macro crates only export proc-macro items, which are looked // up using `proc_macro_data` @@ -579,7 +580,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode the items. i = self.position(); - self.encode_def_ids(); self.encode_info_for_items(); let item_bytes = self.position() - i; @@ -715,107 +715,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } -fn should_encode_visibility(def_kind: DefKind) -> bool { - match def_kind { - DefKind::Mod - | DefKind::Struct - | DefKind::Union - | DefKind::Enum - | DefKind::Variant - | DefKind::Trait - | DefKind::TyAlias - | DefKind::ForeignTy - | DefKind::TraitAlias - | DefKind::AssocTy - | DefKind::Fn - | DefKind::Const - | DefKind::Static - | DefKind::Ctor(..) - | DefKind::AssocFn - | DefKind::AssocConst - | DefKind::Macro(..) - | DefKind::Use - | DefKind::ForeignMod - | DefKind::OpaqueTy - | DefKind::Impl - | DefKind::Field => true, - DefKind::TyParam - | DefKind::ConstParam - | DefKind::LifetimeParam - | DefKind::AnonConst - | DefKind::GlobalAsm - | DefKind::Closure - | DefKind::Generator - | DefKind::ExternCrate => false, - } -} - -fn should_encode_stability(def_kind: DefKind) -> bool { - match def_kind { - DefKind::Mod - | DefKind::Ctor(..) - | DefKind::Variant - | DefKind::Field - | DefKind::Struct - | DefKind::AssocTy - | DefKind::AssocFn - | DefKind::AssocConst - | DefKind::TyParam - | DefKind::ConstParam - | DefKind::Static - | DefKind::Const - | DefKind::Fn - | DefKind::ForeignMod - | DefKind::TyAlias - | DefKind::OpaqueTy - | DefKind::Enum - | DefKind::Union - | DefKind::Impl - | DefKind::Trait - | DefKind::TraitAlias - | DefKind::Macro(..) - | DefKind::ForeignTy => true, - DefKind::Use - | DefKind::LifetimeParam - | DefKind::AnonConst - | DefKind::GlobalAsm - | DefKind::Closure - | DefKind::Generator - | DefKind::ExternCrate => false, - } -} - impl EncodeContext<'a, 'tcx> { - fn encode_def_ids(&mut self) { - if self.is_proc_macro { - return; - } - let tcx = self.tcx; - let hir = tcx.hir(); - for local_id in hir.iter_local_def_id() { - let def_id = local_id.to_def_id(); - let def_kind = tcx.opt_def_kind(local_id); - let def_kind = if let Some(def_kind) = def_kind { def_kind } else { continue }; - record!(self.tables.def_kind[def_id] <- match def_kind { - // Replace Ctor by the enclosing object to avoid leaking details in children crates. - DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct, - DefKind::Ctor(CtorOf::Variant, _) => DefKind::Variant, - def_kind => def_kind, - }); - record!(self.tables.span[def_id] <- tcx.def_span(def_id)); - record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id)); - record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id)); - if should_encode_visibility(def_kind) { - record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); - } - if should_encode_stability(def_kind) { - self.encode_stability(def_id); - self.encode_const_stability(def_id); - self.encode_deprecation(def_id); - } - } - } - fn encode_variances_of(&mut self, def_id: DefId) { debug!("EncodeContext::encode_variances_of({:?})", def_id); record!(self.tables.variances[def_id] <- &self.tcx.variances_of(def_id)[..]); @@ -840,11 +740,17 @@ impl EncodeContext<'a, 'tcx> { }; record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); + record!(self.tables.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]); + record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id)); record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })); self.encode_ident_span(def_id, variant.ident); + self.encode_stability(def_id); + self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. @@ -874,6 +780,10 @@ impl EncodeContext<'a, 'tcx> { }; record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); + self.encode_stability(def_id); + self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -889,7 +799,7 @@ impl EncodeContext<'a, 'tcx> { self.encode_mir_for_ctfe(def_id.expect_local()); } - fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>) { + fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>, attrs: &[ast::Attribute]) { let tcx = self.tcx; let local_def_id = tcx.hir().local_def_id(id); let def_id = local_def_id.to_def_id(); @@ -922,6 +832,9 @@ impl EncodeContext<'a, 'tcx> { }; record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data))); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); + record!(self.tables.attributes[def_id] <- attrs); if self.is_proc_macro { record!(self.tables.children[def_id] <- &[]); } else { @@ -929,6 +842,8 @@ impl EncodeContext<'a, 'tcx> { tcx.hir().local_def_id(item_id.id).local_def_index })); } + self.encode_stability(def_id); + self.encode_deprecation(def_id); } fn encode_field( @@ -937,14 +852,24 @@ impl EncodeContext<'a, 'tcx> { variant_index: VariantIdx, field_index: usize, ) { + let tcx = self.tcx; let variant = &adt_def.variants[variant_index]; let field = &variant.fields[field_index]; let def_id = field.did; debug!("EncodeContext::encode_field({:?})", def_id); + let variant_id = tcx.hir().local_def_id_to_hir_id(variant.def_id.expect_local()); + let variant_data = tcx.hir().expect_variant_data(variant_id); + record!(self.tables.kind[def_id] <- EntryKind::Field); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); + record!(self.tables.attributes[def_id] <- variant_data.fields()[field_index].attrs); + record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id)); self.encode_ident_span(def_id, field.ident); + self.encode_stability(def_id); + self.encode_deprecation(def_id); self.encode_item_type(def_id); self.encode_generics(def_id); self.encode_explicit_predicates(def_id); @@ -964,6 +889,11 @@ impl EncodeContext<'a, 'tcx> { }; record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr)); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); + record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id)); + self.encode_stability(def_id); + self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -1025,25 +955,29 @@ impl EncodeContext<'a, 'tcx> { hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"), }; - match trait_item.kind { + record!(self.tables.kind[def_id] <- match trait_item.kind { ty::AssocKind::Const => { let rendered = rustc_hir_pretty::to_string( &(&self.tcx.hir() as &dyn intravisit::Map<'_>), - |s| s.print_trait_item(ast_item), + |s| s.print_trait_item(ast_item) ); let rendered_const = self.lazy(RenderedConst(rendered)); - record!(self.tables.kind[def_id] <- EntryKind::AssocConst( + EntryKind::AssocConst( container, Default::default(), rendered_const, - )); + ) } ty::AssocKind::Fn => { let fn_data = if let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind { let param_names = match *m { - hir::TraitFn::Required(ref names) => self.encode_fn_param_names(names), - hir::TraitFn::Provided(body) => self.encode_fn_param_names_for_body(body), + hir::TraitFn::Required(ref names) => { + self.encode_fn_param_names(names) + } + hir::TraitFn::Provided(body) => { + self.encode_fn_param_names_for_body(body) + } }; FnData { asyncness: m_sig.header.asyncness, @@ -1053,18 +987,24 @@ impl EncodeContext<'a, 'tcx> { } else { bug!() }; - record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData { + EntryKind::AssocFn(self.lazy(AssocFnData { fn_data, container, has_self: trait_item.fn_has_self_parameter, - }))); + })) } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); - record!(self.tables.kind[def_id] <- EntryKind::AssocType(container)); + EntryKind::AssocType(container) } - } + }); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- ast_item.span); + record!(self.tables.attributes[def_id] <- ast_item.attrs); self.encode_ident_span(def_id, ast_item.ident); + self.encode_stability(def_id); + self.encode_const_stability(def_id); + self.encode_deprecation(def_id); match trait_item.kind { ty::AssocKind::Const | ty::AssocKind::Fn => { self.encode_item_type(def_id); @@ -1128,16 +1068,15 @@ impl EncodeContext<'a, 'tcx> { } }; - match impl_item.kind { + record!(self.tables.kind[def_id] <- match impl_item.kind { ty::AssocKind::Const => { if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind { let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id); - record!(self.tables.kind[def_id] <- EntryKind::AssocConst( + EntryKind::AssocConst( container, qualifs, self.encode_rendered_const_for_body(body_id)) - ); } else { bug!() } @@ -1152,17 +1091,21 @@ impl EncodeContext<'a, 'tcx> { } else { bug!() }; - record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData { + EntryKind::AssocFn(self.lazy(AssocFnData { fn_data, container, has_self: impl_item.fn_has_self_parameter, - }))); + })) } - ty::AssocKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::AssocType(container)); - } - } + ty::AssocKind::Type => EntryKind::AssocType(container) + }); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- ast_item.span); + record!(self.tables.attributes[def_id] <- ast_item.attrs); self.encode_ident_span(def_id, impl_item.ident); + self.encode_stability(def_id); + self.encode_const_stability(def_id); + self.encode_deprecation(def_id); self.encode_item_type(def_id); if impl_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -1292,12 +1235,15 @@ impl EncodeContext<'a, 'tcx> { self.encode_ident_span(def_id, item.ident); - let entry_kind = match item.kind { + record!(self.tables.kind[def_id] <- match item.kind { hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic, hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic, hir::ItemKind::Const(_, body_id) => { let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id); - EntryKind::Const(qualifs, self.encode_rendered_const_for_body(body_id)) + EntryKind::Const( + qualifs, + self.encode_rendered_const_for_body(body_id) + ) } hir::ItemKind::Fn(ref sig, .., body) => { let data = FnData { @@ -1309,7 +1255,7 @@ impl EncodeContext<'a, 'tcx> { EntryKind::Fn(self.lazy(data)) } hir::ItemKind::Mod(ref m) => { - return self.encode_info_for_mod(item.hir_id, m); + return self.encode_info_for_mod(item.hir_id, m, &item.attrs); } hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod, hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm, @@ -1326,61 +1272,61 @@ impl EncodeContext<'a, 'tcx> { // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method // needs to know - let ctor = struct_def - .ctor_hir_id() - .map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index); - - EntryKind::Struct( - self.lazy(VariantData { - ctor_kind: variant.ctor_kind, - discr: variant.discr, - ctor, - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }), - adt_def.repr, - ) + let ctor = struct_def.ctor_hir_id().map(|ctor_hir_id| { + self.tcx.hir().local_def_id(ctor_hir_id).local_def_index + }); + + EntryKind::Struct(self.lazy(VariantData { + ctor_kind: variant.ctor_kind, + discr: variant.discr, + ctor, + is_non_exhaustive: variant.is_field_list_non_exhaustive(), + }), adt_def.repr) } hir::ItemKind::Union(..) => { let adt_def = self.tcx.adt_def(def_id); let variant = adt_def.non_enum_variant(); - EntryKind::Union( - self.lazy(VariantData { - ctor_kind: variant.ctor_kind, - discr: variant.discr, - ctor: None, - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }), - adt_def.repr, - ) + EntryKind::Union(self.lazy(VariantData { + ctor_kind: variant.ctor_kind, + discr: variant.discr, + ctor: None, + is_non_exhaustive: variant.is_field_list_non_exhaustive(), + }), adt_def.repr) } hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => { let trait_ref = self.tcx.impl_trait_ref(def_id); let polarity = self.tcx.impl_polarity(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = self.tcx.trait_def(trait_ref.def_id); - trait_def.ancestors(self.tcx, def_id).ok().and_then(|mut an| { - an.nth(1).and_then(|node| match node { - specialization_graph::Node::Impl(parent) => Some(parent), - _ => None, - }) - }) + trait_def.ancestors(self.tcx, def_id).ok() + .and_then(|mut an| an.nth(1).and_then(|node| { + match node { + specialization_graph::Node::Impl(parent) => Some(parent), + _ => None, + } + })) } else { None }; // if this is an impl of `CoerceUnsized`, create its // "unsized info", else just store None - let coerce_unsized_info = trait_ref.and_then(|t| { - if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() { - Some(self.tcx.at(item.span).coerce_unsized_info(def_id)) - } else { - None - } - }); + let coerce_unsized_info = + trait_ref.and_then(|t| { + if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() { + Some(self.tcx.at(item.span).coerce_unsized_info(def_id)) + } else { + None + } + }); - let data = - ImplData { polarity, defaultness, parent_impl: parent, coerce_unsized_info }; + let data = ImplData { + polarity, + defaultness, + parent_impl: parent, + coerce_unsized_info, + }; EntryKind::Impl(self.lazy(data)) } @@ -1397,11 +1343,13 @@ impl EncodeContext<'a, 'tcx> { EntryKind::Trait(self.lazy(data)) } hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias, - hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => { - bug!("cannot encode info for item {:?}", item) - } - }; - record!(self.tables.kind[def_id] <- entry_kind); + hir::ItemKind::ExternCrate(_) | + hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item), + }); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); + record!(self.tables.attributes[def_id] <- item.attrs); + record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id)); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <- @@ -1435,6 +1383,9 @@ impl EncodeContext<'a, 'tcx> { } _ => {} } + self.encode_stability(def_id); + self.encode_const_stability(def_id); + self.encode_deprecation(def_id); match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) @@ -1515,11 +1466,17 @@ impl EncodeContext<'a, 'tcx> { fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) { let def_id = self.tcx.hir().local_def_id(macro_def.hir_id).to_def_id(); record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone()))); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- macro_def.span); + record!(self.tables.attributes[def_id] <- macro_def.attrs); self.encode_ident_span(def_id, macro_def.ident); + self.encode_stability(def_id); + self.encode_deprecation(def_id); } fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) { record!(self.tables.kind[def_id] <- kind); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); if encode_type { self.encode_item_type(def_id); } @@ -1533,18 +1490,18 @@ impl EncodeContext<'a, 'tcx> { let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let ty = self.tcx.typeck(def_id).node_type(hir_id); - match ty.kind() { + record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind() { ty::Generator(..) => { let data = self.tcx.generator_kind(def_id).unwrap(); - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator(data)); + EntryKind::Generator(data) } - ty::Closure(..) => { - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure); - } + ty::Closure(..) => EntryKind::Closure, _ => bug!("closure that is neither generator nor closure"), - } + }); + record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id)); + record!(self.tables.attributes[def_id.to_def_id()] <- &self.tcx.get_attrs(def_id.to_def_id())[..]); self.encode_item_type(def_id.to_def_id()); if let ty::Closure(def_id, substs) = *ty.kind() { record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig()); @@ -1568,6 +1525,7 @@ impl EncodeContext<'a, 'tcx> { let qualifs = self.tcx.mir_const_qualif(def_id); record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data)); + record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id)); self.encode_item_type(def_id.to_def_id()); self.encode_generics(def_id.to_def_id()); self.encode_explicit_predicates(def_id.to_def_id()); @@ -1617,15 +1575,6 @@ impl EncodeContext<'a, 'tcx> { let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied(); let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index)); - record!(self.tables.def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod); - record!(self.tables.span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); - record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id())); - record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id())); - if let Some(stability) = stability { - record!(self.tables.stability[LOCAL_CRATE.as_def_id()] <- stability); - } - self.encode_deprecation(LOCAL_CRATE.as_def_id()); - // Normally, this information is encoded when we walk the items // defined in this crate. However, we skip doing that for proc-macro crates, // so we manually encode just the information that we need @@ -1657,7 +1606,6 @@ impl EncodeContext<'a, 'tcx> { def_key.disambiguated_data.data = DefPathData::MacroNs(name); let def_id = DefId::local(id); - record!(self.tables.def_kind[def_id] <- DefKind::Macro(macro_kind)); record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind)); record!(self.tables.attributes[def_id] <- attrs); record!(self.tables.def_keys[def_id] <- def_key); @@ -1825,7 +1773,7 @@ impl EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id); - match nitem.kind { + record!(self.tables.kind[def_id] <- match nitem.kind { hir::ForeignItemKind::Fn(_, ref names, _) => { let data = FnData { asyncness: hir::IsAsync::NotAsync, @@ -1836,19 +1784,19 @@ impl EncodeContext<'a, 'tcx> { }, param_names: self.encode_fn_param_names(names), }; - record!(self.tables.kind[def_id] <- EntryKind::ForeignFn(self.lazy(data))); + EntryKind::ForeignFn(self.lazy(data)) } - hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignMutStatic); - } - hir::ForeignItemKind::Static(_, hir::Mutability::Not) => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignImmStatic); - } - hir::ForeignItemKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignType); - } - } + hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => EntryKind::ForeignMutStatic, + hir::ForeignItemKind::Static(_, hir::Mutability::Not) => EntryKind::ForeignImmStatic, + hir::ForeignItemKind::Type => EntryKind::ForeignType, + }); + record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + record!(self.tables.span[def_id] <- nitem.span); + record!(self.tables.attributes[def_id] <- nitem.attrs); self.encode_ident_span(def_id, nitem.ident); + self.encode_stability(def_id); + self.encode_const_stability(def_id); + self.encode_deprecation(def_id); self.encode_item_type(def_id); self.encode_inherent_implementations(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { @@ -1914,12 +1862,15 @@ impl EncodeContext<'a, 'tcx> { let def_id = self.tcx.hir().local_def_id(param.hir_id); match param.kind { GenericParamKind::Lifetime { .. } => continue, - GenericParamKind::Type { default, .. } => { + GenericParamKind::Type { ref default, .. } => { self.encode_info_for_generic_param( def_id.to_def_id(), EntryKind::TypeParam, default.is_some(), ); + if default.is_some() { + self.encode_stability(def_id.to_def_id()); + } } GenericParamKind::Const { .. } => { self.encode_info_for_generic_param( diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index b44c3bfcac647..59a8bc7fac1be 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -6,7 +6,7 @@ use rustc_attr as attr; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind}; +use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, DefIndex, DefPathHash}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items; @@ -279,7 +279,6 @@ macro_rules! define_tables { } define_tables! { - def_kind: Table<DefIndex, Lazy<DefKind>>, kind: Table<DefIndex, Lazy<EntryKind>>, visibility: Table<DefIndex, Lazy<ty::Visibility>>, span: Table<DefIndex, Lazy<Span>>, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 1cb75757379c9..62f2874af0493 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -1,17 +1,16 @@ -//! Nodes in the dependency graph. +//! This module defines the `DepNode` type which the compiler uses to represent +//! nodes in the dependency graph. //! -//! A node in the [dependency graph] is represented by a [`DepNode`]. -//! A `DepNode` consists of a [`DepKind`] (which -//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.) -//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which +//! A `DepNode` consists of a `DepKind` (which +//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc) +//! and a `Fingerprint`, a 128-bit hash value the exact meaning of which //! depends on the node's `DepKind`. Together, the kind and the fingerprint //! fully identify a dependency node, even across multiple compilation sessions. //! In other words, the value of the fingerprint does not depend on anything //! that is specific to a given compilation session, like an unpredictable -//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a +//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a //! pointer. The concept behind this could be compared to how git commit hashes -//! uniquely identify a given commit. The fingerprinting approach has -//! a few advantages: +//! uniquely identify a given commit and has a few advantages: //! //! * A `DepNode` can simply be serialized to disk and loaded in another session //! without the need to do any "rebasing" (like we have to do for Spans and @@ -52,8 +51,6 @@ //! than a zeroed out fingerprint. More generally speaking, it relieves the //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -//! -//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html use crate::ty::TyCtxt; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1305b5c9f00ab..06bb1347dc1de 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,6 +1,7 @@ use self::collector::NodeCollector; use crate::hir::{Owner, OwnerNodes}; +use crate::ty::query::Providers; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::svh::Svh; @@ -85,13 +86,11 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool { } } -#[derive(Debug)] pub(super) struct HirOwnerData<'hir> { pub(super) signature: Option<&'hir Owner<'hir>>, pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>, } -#[derive(Debug)] pub struct IndexedHir<'hir> { /// The SVH of the local crate. pub crate_hash: Svh, @@ -184,18 +183,14 @@ impl<'hir> Map<'hir> { self.tcx.definitions.opt_local_def_id_to_hir_id(def_id) } - pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ { - self.tcx.definitions.iter_local_def_id() - } - - pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> { + pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind { // FIXME(eddyb) support `find` on the crate root. if local_def_id.to_def_id().index == CRATE_DEF_INDEX { - return Some(DefKind::Mod); + return DefKind::Mod; } let hir_id = self.local_def_id_to_hir_id(local_def_id); - let def_kind = match self.find(hir_id)? { + match self.get(hir_id) { Node::Item(item) => match item.kind { ItemKind::Static(..) => DefKind::Static, ItemKind::Const(..) => DefKind::Const, @@ -254,7 +249,6 @@ impl<'hir> Map<'hir> { GenericParamKind::Type { .. } => DefKind::TyParam, GenericParamKind::Const { .. } => DefKind::ConstParam, }, - Node::Crate(_) => DefKind::Mod, Node::Stmt(_) | Node::PathSegment(_) | Node::Ty(_) @@ -266,14 +260,9 @@ impl<'hir> Map<'hir> { | Node::Arm(_) | Node::Lifetime(_) | Node::Visibility(_) - | Node::Block(_) => return None, - }; - Some(def_kind) - } - - pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind { - self.opt_def_kind(local_def_id) - .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id)) + | Node::Block(_) + | Node::Crate(_) => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)), + } } fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> { @@ -525,7 +514,9 @@ impl<'hir> Map<'hir> { /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> { - self.find_entry(hir_id).map(|entry| entry.node) + self.find_entry(hir_id).and_then(|entry| { + if let Node::Crate(..) = entry.node { None } else { Some(entry.node) } + }) } /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there @@ -857,55 +848,50 @@ impl<'hir> Map<'hir> { /// Gets the span of the definition of the specified HIR node. /// This is used by `tcx.get_span` pub fn span(&self, hir_id: HirId) -> Span { - self.opt_span(hir_id) - .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id)) - } - - pub fn opt_span(&self, hir_id: HirId) -> Option<Span> { - let span = match self.find_entry(hir_id)?.node { - Node::Param(param) => param.span, - Node::Item(item) => match &item.kind { + match self.find_entry(hir_id).map(|entry| entry.node) { + Some(Node::Param(param)) => param.span, + Some(Node::Item(item)) => match &item.kind { ItemKind::Fn(sig, _, _) => sig.span, _ => item.span, }, - Node::ForeignItem(foreign_item) => foreign_item.span, - Node::TraitItem(trait_item) => match &trait_item.kind { + Some(Node::ForeignItem(foreign_item)) => foreign_item.span, + Some(Node::TraitItem(trait_item)) => match &trait_item.kind { TraitItemKind::Fn(sig, _) => sig.span, _ => trait_item.span, }, - Node::ImplItem(impl_item) => match &impl_item.kind { + Some(Node::ImplItem(impl_item)) => match &impl_item.kind { ImplItemKind::Fn(sig, _) => sig.span, _ => impl_item.span, }, - Node::Variant(variant) => variant.span, - Node::Field(field) => field.span, - Node::AnonConst(constant) => self.body(constant.body).value.span, - Node::Expr(expr) => expr.span, - Node::Stmt(stmt) => stmt.span, - Node::PathSegment(seg) => seg.ident.span, - Node::Ty(ty) => ty.span, - Node::TraitRef(tr) => tr.path.span, - Node::Binding(pat) => pat.span, - Node::Pat(pat) => pat.span, - Node::Arm(arm) => arm.span, - Node::Block(block) => block.span, - Node::Ctor(..) => match self.find(self.get_parent_node(hir_id))? { - Node::Item(item) => item.span, - Node::Variant(variant) => variant.span, + Some(Node::Variant(variant)) => variant.span, + Some(Node::Field(field)) => field.span, + Some(Node::AnonConst(constant)) => self.body(constant.body).value.span, + Some(Node::Expr(expr)) => expr.span, + Some(Node::Stmt(stmt)) => stmt.span, + Some(Node::PathSegment(seg)) => seg.ident.span, + Some(Node::Ty(ty)) => ty.span, + Some(Node::TraitRef(tr)) => tr.path.span, + Some(Node::Binding(pat)) => pat.span, + Some(Node::Pat(pat)) => pat.span, + Some(Node::Arm(arm)) => arm.span, + Some(Node::Block(block)) => block.span, + Some(Node::Ctor(..)) => match self.find(self.get_parent_node(hir_id)) { + Some(Node::Item(item)) => item.span, + Some(Node::Variant(variant)) => variant.span, _ => unreachable!(), }, - Node::Lifetime(lifetime) => lifetime.span, - Node::GenericParam(param) => param.span, - Node::Visibility(&Spanned { + Some(Node::Lifetime(lifetime)) => lifetime.span, + Some(Node::GenericParam(param)) => param.span, + Some(Node::Visibility(&Spanned { node: VisibilityKind::Restricted { ref path, .. }, .. - }) => path.span, - Node::Visibility(v) => bug!("unexpected Visibility {:?}", v), - Node::Local(local) => local.span, - Node::MacroDef(macro_def) => macro_def.span, - Node::Crate(item) => item.span, - }; - Some(span) + })) => path.span, + Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v), + Some(Node::Local(local)) => local.span, + Some(Node::MacroDef(macro_def)) => macro_def.span, + Some(Node::Crate(item)) => item.span, + None => bug!("hir::map::Map::span: id not in map: {:?}", hir_id), + } } /// Like `hir.span()`, but includes the body of function items @@ -921,7 +907,7 @@ impl<'hir> Map<'hir> { } pub fn span_if_local(&self, id: DefId) -> Option<Span> { - id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id))) + id.as_local().map(|id| self.span(self.local_def_id_to_hir_id(id))) } pub fn res_span(&self, res: Res) -> Option<Span> { @@ -1115,3 +1101,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { None => format!("unknown node{}", id_str), } } + +pub fn provide(providers: &mut Providers) { + providers.def_kind = |tcx, def_id| tcx.hir().def_kind(def_id.expect_local()); +} diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 6934e06d4c2e3..ae3b30217cc4a 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -15,9 +15,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_hir::*; use rustc_index::vec::IndexVec; -use rustc_span::DUMMY_SP; -#[derive(Debug)] pub struct Owner<'tcx> { parent: HirId, node: Node<'tcx>, @@ -33,13 +31,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ParentedNode<'tcx> { parent: ItemLocalId, node: Node<'tcx>, } -#[derive(Debug)] pub struct OwnerNodes<'tcx> { hash: Fingerprint, nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, @@ -80,7 +77,6 @@ pub fn provide(providers: &mut Providers) { }; providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature; providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref(); - providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); let hir_id = hir.local_def_id_to_hir_id(id.expect_local()); @@ -96,5 +92,5 @@ pub fn provide(providers: &mut Providers) { span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id); } }; - providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local()); + map::provide(providers); } diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index 51b650e5adef8..addcb7a14e3a6 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -17,7 +17,6 @@ use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData}; use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX}; use smallvec::SmallVec; use std::cmp::Ord; -use std::thread::LocalKey; fn compute_ignored_attr_names() -> FxHashSet<Symbol> { debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty()); @@ -243,13 +242,6 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { hcx.def_path_hash(def_id).hash_stable(hcx, hasher); } - fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> { - thread_local! { - static CACHE: rustc_span::ExpnIdCache = Default::default(); - } - &CACHE - } - fn byte_pos_to_line_and_col( &mut self, byte: BytePos, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 0bdccf7b5f073..80c87dddd5614 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -12,7 +12,7 @@ use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. -#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, HashStable)] pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. @@ -48,13 +48,11 @@ impl LintLevelSource { /// A tuple of a lint level and its source. pub type LevelAndSource = (Level, LintLevelSource); -#[derive(Debug)] pub struct LintLevelSets { pub list: Vec<LintSet>, pub lint_cap: Level, } -#[derive(Debug)] pub enum LintSet { CommandLine { // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which @@ -141,7 +139,6 @@ impl LintLevelSets { } } -#[derive(Debug)] pub struct LintLevelMap { pub sets: LintLevelSets, pub id_to_set: FxHashMap<HirId, u32>, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 5f2ffda642cee..a4363bb580a2f 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -3,7 +3,7 @@ use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_session::config::SanitizerSet; use rustc_span::symbol::Symbol; -#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable)] pub struct CodegenFnAttrs { pub flags: CodegenFnAttrFlags, /// Parsed representation of the `#[inline]` attribute diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 4f1ca968c3018..6d2c43874bc0f 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -96,7 +96,7 @@ pub struct NativeLib { pub wasm_import_module: Option<Symbol>, } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable)] pub struct ForeignModule { pub foreign_items: Vec<DefId>, pub def_id: DefId, diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index a369e85306b36..9bc9ca6707afe 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -7,7 +7,7 @@ pub mod lib_features { use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_span::symbol::Symbol; - #[derive(HashStable, Debug)] + #[derive(HashStable)] pub struct LibFeatures { // A map from feature to stabilisation version. pub stable: FxHashMap<Symbol, Symbol>, diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 1b7d0e620a4c5..3d0144e9c8a99 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -68,7 +68,7 @@ pub type ObjectLifetimeDefault = Set1<Region>; /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. -#[derive(Default, HashStable, Debug)] +#[derive(Default, HashStable)] pub struct ResolveLifetimes { /// Maps from every use of a named (not anonymous) lifetime to a /// `Region` describing how that region is bound diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 89ca8eed39a9b..4f08057a7e323 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -36,7 +36,7 @@ impl StabilityLevel { } /// An entry in the `depr_map`. -#[derive(Clone, HashStable, Debug)] +#[derive(Clone, HashStable)] pub struct DeprecationEntry { /// The metadata of the attribute associated with this entry. pub attr: Deprecation, @@ -63,7 +63,7 @@ impl DeprecationEntry { } /// A stability index, giving the stability level for items and methods. -#[derive(HashStable, Debug)] +#[derive(HashStable)] pub struct Index<'tcx> { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index cf931ece712b0..397d2ffd565b1 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -127,8 +127,6 @@ pub enum InvalidProgramInfo<'tcx> { Layout(layout::LayoutError<'tcx>), /// An invalid transmute happened. TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), - /// SizeOf of unsized type was requested. - SizeOfUnsizedType(Ty<'tcx>), } impl fmt::Display for InvalidProgramInfo<'_> { @@ -146,7 +144,6 @@ impl fmt::Display for InvalidProgramInfo<'_> { "transmuting `{}` to `{}` is not possible, because these types do not have the same size", from_ty, to_ty ), - SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty), } } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index f288ad8d1d4a3..5e97862ecf2b6 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -13,7 +13,7 @@ use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. -#[derive(Clone, HashStable, TyEncodable, TyDecodable, Debug)] +#[derive(Clone, HashStable, TyEncodable, TyDecodable)] pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cd2bea86ea1a7..fab2f2c97e4ae 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -54,7 +54,7 @@ mod type_foldable; pub mod visit; /// Types for locals -pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; +type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; pub trait HasLocalDecls<'tcx> { fn local_decls(&self) -> &LocalDecls<'tcx>; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index eb13c89544c13..6d5d408f86c15 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -216,7 +216,6 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> { } } -#[derive(Debug)] pub struct CodegenUnit<'tcx> { /// A name for this CGU. Incremental compilation requires that /// name be unique amongst **all** crates. Therefore, it should diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index c293fbe4ef8ca..a7b847fc5e0ee 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -17,7 +17,7 @@ use std::fmt::{self, Debug}; use super::{Field, SourceInfo}; -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)] pub enum UnsafetyViolationKind { /// Only permitted in regular `fn`s, prohibited in `const fn`s. General, @@ -36,7 +36,7 @@ pub enum UnsafetyViolationKind { UnsafeFnBorrowPacked, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)] pub enum UnsafetyViolationDetails { CallToUnsafeFunction, UseOfInlineAssembly, @@ -121,7 +121,7 @@ impl UnsafetyViolationDetails { } } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)] pub struct UnsafetyViolation { pub source_info: SourceInfo, pub lint_root: hir::HirId, @@ -129,7 +129,7 @@ pub struct UnsafetyViolation { pub details: UnsafetyViolationDetails, } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable)] pub struct UnsafetyCheckResult { /// Violations that are propagated *upwards* from this function. pub violations: Lrc<[UnsafetyViolation]>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d89e3ab4352bb..00ee7b8ec7709 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -782,27 +782,6 @@ rustc_queries! { } Other { - /// Check whether the function has any recursion that could cause the inliner to trigger - /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the - /// current function, just all intermediate functions. - query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { - fatal_cycle - desc { |tcx| - "computing if `{}` (transitively) calls `{}`", - key.0, - tcx.def_path_str(key.1.to_def_id()), - } - } - - /// Obtain all the calls into other local functions - query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] { - fatal_cycle - desc { |tcx| - "computing all local function calls in `{}`", - tcx.def_path_str(key.def_id()), - } - } - /// Evaluates a constant and returns the computed allocation. /// /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. @@ -899,7 +878,7 @@ rustc_queries! { cache_on_disk_if { true } } - query opt_def_kind(def_id: DefId) -> Option<DefKind> { + query def_kind(def_id: DefId) -> DefKind { desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index cb60bfa4c5408..ec6010e6eecf4 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -23,7 +23,7 @@ use rustc_span::symbol::Ident; /// parents of a given specializing impl, which is needed for extracting /// default items amongst other things. In the simple "chain" rule, every impl /// has at most one parent. -#[derive(TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(TyEncodable, TyDecodable, HashStable)] pub struct Graph { /// All impls have a parent; the "root" impls have as their parent the `def_id` /// of the trait. @@ -50,7 +50,7 @@ impl Graph { /// Children of a given impl, grouped into blanket/non-blanket varieties as is /// done in `TraitDef`. -#[derive(Default, TyEncodable, TyDecodable, Debug)] +#[derive(Default, TyEncodable, TyDecodable)] pub struct Children { // Impls of a trait (or specializations of a given impl). To allow for // quicker lookup, the impls are indexed by a simplified version of their diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs index 275384e227a90..03c8963b0907e 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs @@ -18,7 +18,7 @@ use DefIdForest::*; /// We store the minimal set of `DefId`s required to represent the whole set. If A and B are /// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is /// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored. -#[derive(Clone, HashStable, Debug)] +#[derive(Clone, HashStable)] pub enum DefIdForest { Empty, Single(DefId), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index ef467ed651454..195e840866aec 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2514,7 +2514,7 @@ where extra_args: &[Ty<'tcx>], caller_location: Option<Ty<'tcx>>, codegen_fn_attr_flags: CodegenFnAttrFlags, - make_self_ptr_thin: bool, + mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>, ) -> Self; fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); } @@ -2574,7 +2574,9 @@ where // Assume that fn pointers may always unwind let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND; - call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false) + call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, |ty, _| { + ArgAbi::new(cx.layout_of(ty)) + }) } fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { @@ -2588,14 +2590,55 @@ where let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; - call::FnAbi::new_internal( - cx, - sig, - extra_args, - caller_location, - attrs, - matches!(instance.def, ty::InstanceDef::Virtual(..)), - ) + call::FnAbi::new_internal(cx, sig, extra_args, caller_location, attrs, |ty, arg_idx| { + let mut layout = cx.layout_of(ty); + // Don't pass the vtable, it's not an argument of the virtual fn. + // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` + // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen + if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) { + let fat_pointer_ty = if layout.is_unsized() { + // unsized `self` is passed as a pointer to `self` + // FIXME (mikeyhew) change this to use &own if it is ever added to the language + cx.tcx().mk_mut_ptr(layout.ty) + } else { + match layout.abi { + Abi::ScalarPair(..) => (), + _ => bug!("receiver type has unsupported layout: {:?}", layout), + } + + // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self> + // with a Scalar (not ScalarPair) ABI. This is a hack that is understood + // elsewhere in the compiler as a method on a `dyn Trait`. + // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we + // get a built-in pointer type + let mut fat_pointer_layout = layout; + 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() + && !fat_pointer_layout.ty.is_region_ptr() + { + for i in 0..fat_pointer_layout.fields.count() { + let field_layout = fat_pointer_layout.field(cx, i); + + if !field_layout.is_zst() { + fat_pointer_layout = field_layout; + continue 'descend_newtypes; + } + } + + bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); + } + + fat_pointer_layout.ty + }; + + // we now have a type like `*mut RcBox<dyn Trait>` + // change its layout to that of `*mut ()`, a thin pointer, but keep the same type + // this is understood as a special case elsewhere in the compiler + let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit()); + layout = cx.layout_of(unit_pointer_ty); + layout.ty = fat_pointer_ty; + } + ArgAbi::new(layout) + }) } fn new_internal( @@ -2604,7 +2647,7 @@ where extra_args: &[Ty<'tcx>], caller_location: Option<Ty<'tcx>>, codegen_fn_attr_flags: CodegenFnAttrFlags, - force_thin_self_ptr: bool, + mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>, ) -> Self { debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); @@ -2735,23 +2778,7 @@ where let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| { let is_return = arg_idx.is_none(); - - let layout = cx.layout_of(ty); - let layout = if force_thin_self_ptr && arg_idx == Some(0) { - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - make_thin_self_ptr(cx, layout) - } else { - layout - }; - - let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { - let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return); - attrs - }); - + let mut arg = mk_arg_type(ty, arg_idx); if arg.layout.is_zst() { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. @@ -2767,6 +2794,30 @@ where } } + // FIXME(eddyb) other ABIs don't have logic for scalar pairs. + if !is_return && rust_abi { + if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi { + let mut a_attrs = ArgAttributes::new(); + let mut b_attrs = ArgAttributes::new(); + adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false); + adjust_for_rust_scalar( + &mut b_attrs, + b, + arg.layout, + a.value.size(cx).align_to(b.value.align(cx).abi), + false, + ); + arg.mode = PassMode::Pair(a_attrs, b_attrs); + return arg; + } + } + + if let Abi::Scalar(ref scalar) = arg.layout.abi { + if let PassMode::Direct(ref mut attrs) = arg.mode { + adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return); + } + } + arg }; @@ -2843,10 +2894,9 @@ where let max_by_val_size = Pointer.size(cx) * 2; let size = arg.layout.size; - let is_indirect_not_on_stack = - matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); - assert!(is_indirect_not_on_stack, "{:?}", arg); - if !arg.layout.is_unsized() && size <= max_by_val_size { + if arg.layout.is_unsized() || size > max_by_val_size { + arg.make_indirect(); + } else { // We want to pass small aggregates as immediates, but using // a LLVM aggregate type for this leads to bad optimizations, // so we pick an appropriately sized integer type instead. @@ -2865,52 +2915,3 @@ where } } } - -fn make_thin_self_ptr<'tcx, C>(cx: &C, mut layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx> -where - C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, -{ - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - cx.tcx().mk_mut_ptr(layout.ty) - } else { - match layout.abi { - Abi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout), - } - - // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self> - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes; - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox<dyn Trait>` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit()); - layout = cx.layout_of(unit_pointer_ty); - layout.ty = fat_pointer_ty; - layout -} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c4d867161386d..c6970df01785e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -185,7 +185,7 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec<Predicate<'tcx>>, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)] pub enum ImplPolarity { /// `impl Trait for Type` Positive, @@ -435,7 +435,7 @@ pub enum Variance { /// HIR of every item in the local crate. Instead, use /// `tcx.variances_of()` to get the variance for a *particular* /// item. -#[derive(HashStable, Debug)] +#[derive(HashStable)] pub struct CrateVariancesMap<'tcx> { /// For each item with generics, maps to a vector of the variance /// of its generics. If an item has no generics, it will have no @@ -1174,7 +1174,7 @@ pub enum PredicateKind<'tcx> { /// HIR of every item in the local crate. Instead, use /// `tcx.inferred_outlives_of()` to get the outlives for a *particular* /// item. -#[derive(HashStable, Debug)] +#[derive(HashStable)] pub struct CratePredicatesMap<'tcx> { /// For each struct with outlive bounds, maps to a vector of the /// predicate of its outlive bounds. If an item has no outlives @@ -3107,7 +3107,7 @@ impl<'tcx> TyCtxt<'tcx> { } } -#[derive(Clone, HashStable, Debug)] +#[derive(Clone, HashStable)] pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]); /// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition. diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index bfa1581aaae29..a005990264cf1 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -127,17 +127,6 @@ impl Key for (DefId, DefId) { } } -impl Key for (ty::Instance<'tcx>, LocalDefId) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.query_crate() - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.0.default_span(tcx) - } -} - impl Key for (DefId, LocalDefId) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index f580cb14dc988..acfa58e511ed1 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -130,19 +130,3 @@ mod sealed { } use sealed::IntoQueryParam; - -impl TyCtxt<'tcx> { - pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind { - let def_id = def_id.into_query_param(); - self.opt_def_kind(def_id) - .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) - } -} - -impl TyCtxtAt<'tcx> { - pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind { - let def_id = def_id.into_query_param(); - self.opt_def_kind(def_id) - .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) - } -} diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index f4d7eac0ae2f8..86476dffc0312 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -63,7 +63,7 @@ pub enum TraitSpecializationKind { AlwaysApplicable, } -#[derive(Default, Debug)] +#[derive(Default)] pub struct TraitImpls { blanket_impls: Vec<DefId>, /// Impls indexed by their simplified self type, for fast lookup. diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index cd16a88e5fc3c..8f41bfae2fdf5 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -289,7 +289,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - let ty = used_place.ty(self.body, self.infcx.tcx).ty; + let ty = PlaceRef::ty(&used_place, self.body, self.infcx.tcx).ty; let needs_note = match ty.kind() { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck(id.expect_local()); @@ -728,8 +728,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Define a small closure that we can use to check if the type of a place // is a union. let union_ty = |place_base| { - // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`; - // using a type annotation in the closure argument instead leads to a lifetime error. let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty; ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) }; diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 7c7edfdb5fbaf..006e05072a7a9 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -1743,7 +1743,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = place_span.0.last_projection() { - let place_ty = place_base.ty(self.body(), self.infcx.tcx); + let place_ty = PlaceRef::ty(&place_base, self.body(), self.infcx.tcx); if let ty::Array(..) = place_ty.ty.kind() { self.check_if_subslice_element_is_moved( location, @@ -1854,7 +1854,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - let base_ty = place_base.ty(self.body(), tcx).ty; + let base_ty = PlaceRef::ty(&place_base, self.body(), tcx).ty; match base_ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( @@ -1951,7 +1951,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() { + if let ty::Adt(def, _) = PlaceRef::ty(&base, this.body(), tcx).ty.kind() { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) @@ -2173,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some((place_base, elem)) => { match elem { ProjectionElem::Deref => { - let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty; + let base_ty = PlaceRef::ty(&place_base, self.body(), self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.kind() { diff --git a/compiler/rustc_mir/src/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs index bdf2becb71126..cf04c55eb68c5 100644 --- a/compiler/rustc_mir/src/borrow_check/prefixes.rs +++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs @@ -117,7 +117,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = cursor_base.ty(self.body, self.tcx).ty; + let ty = PlaceRef::ty(&cursor_base, self.body, self.tcx).ty; match ty.kind() { ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { // don't continue traversing over derefs of raw pointers or shared diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs index fbc72ad8adc96..95738db1f553c 100644 --- a/compiler/rustc_mir/src/interpret/step.rs +++ b/compiler/rustc_mir/src/interpret/step.rs @@ -264,14 +264,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { NullaryOp(mir::NullOp::SizeOf, ty) => { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty); let layout = self.layout_of(ty)?; - if layout.is_unsized() { - // FIXME: This should be a span_bug (#80742) - self.tcx.sess.delay_span_bug( - self.frame().current_span(), - &format!("SizeOf nullary MIR operator called for unsized type {}", ty), - ); - throw_inval!(SizeOfUnsizedType(ty)); - } + assert!( + !layout.is_unsized(), + "SizeOf nullary MIR operator called for unsized type" + ); self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?; } diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 8b3881ef9de10..e6d822086f521 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -57,8 +57,6 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable; - providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees; providers.destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 6f98760a7b0ad..99ffb0edce9e1 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -268,20 +268,16 @@ impl NonConstOp for CellBorrow { } #[derive(Debug)] -/// This op is for `&mut` borrows in the trailing expression of a constant -/// which uses the "enclosing scopes rule" to leak its locals into anonymous -/// static or const items. pub struct MutBorrow(pub hir::BorrowKind); impl NonConstOp for MutBorrow { - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { - Status::Forbidden - } - - fn importance(&self) -> DiagnosticImportance { - // If there were primary errors (like non-const function calls), do not emit further - // errors about mutable references. - DiagnosticImportance::Secondary + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { @@ -290,15 +286,25 @@ impl NonConstOp for MutBorrow { hir::BorrowKind::Ref => "", }; - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "{}mutable references are not allowed in the final value of {}s", - raw, - ccx.const_kind(), - ); - + let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()), + ) + } else { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0764, + "{}mutable references are not allowed in {}s", + raw, + ccx.const_kind(), + ); + err.span_label(span, format!("`&{}mut` is only allowed in `const fn`", raw)); + err + }; if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "References in statics and constants may only refer \ @@ -315,29 +321,6 @@ impl NonConstOp for MutBorrow { } } -#[derive(Debug)] -pub struct TransientMutBorrow(pub hir::BorrowKind); - -impl NonConstOp for TransientMutBorrow { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()), - ) - } -} - #[derive(Debug)] pub struct MutDeref; impl NonConstOp for MutDeref { @@ -346,7 +329,7 @@ impl NonConstOp for MutDeref { } fn importance(&self) -> DiagnosticImportance { - // Usually a side-effect of a `TransientMutBorrow` somewhere. + // Usually a side-effect of a `MutBorrow` somewhere. DiagnosticImportance::Secondary } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index a92997dddac6a..08d969b27bea5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -466,29 +466,6 @@ impl Validator<'mir, 'tcx> { } } } - - fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientMutBorrow/MutBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), - _ => { - // Locals with StorageDead do not live beyond the evaluation and can - // thus safely be borrowed without being able to be leaked to the final - // value of the constant. - if self.local_has_storage_dead(local) { - self.check_op(ops::TransientMutBorrow(kind)); - } else { - self.check_op(ops::MutBorrow(kind)); - } - } - } - } } impl Visitor<'tcx> for Validator<'mir, 'tcx> { @@ -585,15 +562,15 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if !is_allowed { if let BorrowKind::Mut { .. } = kind { - self.check_mut_borrow(place.local, hir::BorrowKind::Ref) + self.check_op(ops::MutBorrow(hir::BorrowKind::Ref)); } else { self.check_op(ops::CellBorrow); } } } - Rvalue::AddressOf(Mutability::Mut, ref place) => { - self.check_mut_borrow(place.local, hir::BorrowKind::Raw) + Rvalue::AddressOf(Mutability::Mut, _) => { + self.check_op(ops::MutBorrow(hir::BorrowKind::Raw)) } Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place) diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index fd5c2236902a2..354d213689ec2 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -440,15 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> { - let mut data = &self.source_scopes[source_info.scope]; - // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it - // does not work as I thought it would. Needs more investigation and documentation. - while data.inlined.is_some() { - trace!(?data); - data = &self.source_scopes[data.parent_scope.unwrap()]; - } - trace!(?data); - match &data.local_data { + match &self.source_scopes[source_info.scope].local_data { ClearCrossCrate::Set(data) => Some(data.lint_root), ClearCrossCrate::Clear => None, } diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir/src/transform/coverage/counters.rs index 272a7bf961799..b5921aac56143 100644 --- a/compiler/rustc_mir/src/transform/coverage/counters.rs +++ b/compiler/rustc_mir/src/transform/coverage/counters.rs @@ -32,7 +32,7 @@ impl CoverageCounters { } /// Activate the `DebugCounters` data structures, to provide additional debug formatting - /// features when formatting `CoverageKind` (counter) values. + /// features when formating `CoverageKind` (counter) values. pub fn enable_debug(&mut self) { self.debug_counters.enable(); } diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index dd9a514466d4c..07e637b88f9c0 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -17,8 +17,6 @@ use crate::transform::MirPass; use std::iter; use std::ops::{Range, RangeFrom}; -crate mod cycle; - const INSTR_COST: usize = 5; const CALL_PENALTY: usize = 25; const LANDINGPAD_PENALTY: usize = 50; @@ -39,9 +37,6 @@ struct CallSite<'tcx> { impl<'tcx> MirPass<'tcx> for Inline { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // If you change this optimization level, also change the level in - // `mir_drops_elaborated_and_const_checked` for the call to `mir_inliner_callees`. - // Otherwise you will get an ICE about stolen MIR. if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } @@ -55,8 +50,6 @@ impl<'tcx> MirPass<'tcx> for Inline { return; } - let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id())); - let _guard = span.enter(); if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); @@ -97,8 +90,8 @@ struct Inliner<'tcx> { codegen_fn_attrs: &'tcx CodegenFnAttrs, /// Caller HirID. hir_id: hir::HirId, - /// Stack of inlined Instances. - history: Vec<ty::Instance<'tcx>>, + /// Stack of inlined instances. + history: Vec<Instance<'tcx>>, /// Indicates that the caller body has been modified. changed: bool, } @@ -110,28 +103,13 @@ impl Inliner<'tcx> { None => continue, Some(it) => it, }; - let span = trace_span!("process_blocks", %callsite.callee, ?bb); - let _guard = span.enter(); - - trace!( - "checking for self recursion ({:?} vs body_source: {:?})", - callsite.callee.def_id(), - caller_body.source.def_id() - ); - if callsite.callee.def_id() == caller_body.source.def_id() { - debug!("Not inlining a function into itself"); - continue; - } - if !self.is_mir_available(callsite.callee, caller_body) { + if !self.is_mir_available(&callsite.callee, caller_body) { debug!("MIR unavailable {}", callsite.callee); continue; } - let span = trace_span!("instance_mir", %callsite.callee); - let instance_mir_guard = span.enter(); let callee_body = self.tcx.instance_mir(callsite.callee.def); - drop(instance_mir_guard); if !self.should_inline(callsite, callee_body) { continue; } @@ -159,61 +137,28 @@ impl Inliner<'tcx> { } } - #[instrument(skip(self, caller_body))] - fn is_mir_available(&self, callee: Instance<'tcx>, caller_body: &Body<'tcx>) -> bool { - match callee.def { - InstanceDef::Item(_) => { - // If there is no MIR available (either because it was not in metadata or - // because it has no MIR because it's an extern function), then the inliner - // won't cause cycles on this. - if !self.tcx.is_mir_available(callee.def_id()) { - return false; - } + fn is_mir_available(&self, callee: &Instance<'tcx>, caller_body: &Body<'tcx>) -> bool { + if let InstanceDef::Item(_) = callee.def { + if !self.tcx.is_mir_available(callee.def_id()) { + return false; } - // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => return false, - // This cannot result in an immediate cycle since the callee MIR is a shim, which does - // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we - // do not need to catch this here, we can wait until the inliner decides to continue - // inlining a second time. - InstanceDef::VtableShim(_) - | InstanceDef::ReifyShim(_) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => return true, - } - - if self.tcx.is_constructor(callee.def_id()) { - trace!("constructors always have MIR"); - // Constructor functions cannot cause a query cycle. - return true; } if let Some(callee_def_id) = callee.def_id().as_local() { let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id); - // Avoid inlining into generators, + // Avoid a cycle here by only using `instance_mir` only if we have + // a lower `HirId` than the callee. This ensures that the callee will + // not inline us. This trick only works without incremental compilation. + // So don't do it if that is enabled. Also avoid inlining into generators, // since their `optimized_mir` is used for layout computation, which can // create a cycle, even when no attempt is made to inline the function // in the other direction. - caller_body.generator_kind.is_none() - && ( - // Avoid a cycle here by only using `instance_mir` only if we have - // a lower `HirId` than the callee. This ensures that the callee will - // not inline us. This trick only works without incremental compilation. - // So don't do it if that is enabled. - !self.tcx.dep_graph.is_fully_enabled() + !self.tcx.dep_graph.is_fully_enabled() && self.hir_id < callee_hir_id - // If we know for sure that the function we're calling will itself try to - // call us, then we avoid inlining that function. - || !self.tcx.mir_callgraph_reachable((callee, caller_body.source.def_id().expect_local())) - ) + && caller_body.generator_kind.is_none() } else { - // This cannot result in an immediate cycle since the callee MIR is from another crate - // and is already optimized. Any subsequent inlining may cause cycles, but we do - // not need to catch this here, we can wait until the inliner decides to continue - // inlining a second time. - trace!("functions from other crates always have MIR"); + // This cannot result in a cycle since the callee MIR is from another crate + // and is already optimized. true } } @@ -258,8 +203,8 @@ impl Inliner<'tcx> { None } - #[instrument(skip(self, callee_body))] fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> bool { + debug!("should_inline({:?})", callsite); let tcx = self.tcx; if callsite.fn_sig.c_variadic() { @@ -388,9 +333,7 @@ impl Inliner<'tcx> { if let Ok(Some(instance)) = Instance::resolve(self.tcx, self.param_env, def_id, substs) { - if callsite.callee.def_id() == instance.def_id() - || self.history.contains(&instance) - { + if callsite.callee == instance || self.history.contains(&instance) { debug!("`callee is recursive - not inlining"); return false; } diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs deleted file mode 100644 index e4d403fbf60c0..0000000000000 --- a/compiler/rustc_mir/src/transform/inline/cycle.rs +++ /dev/null @@ -1,157 +0,0 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir::TerminatorKind; -use rustc_middle::ty::TypeFoldable; -use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt}; - -// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking -// this query riddiculously often. -#[instrument(skip(tcx, root, target))] -crate fn mir_callgraph_reachable( - tcx: TyCtxt<'tcx>, - (root, target): (ty::Instance<'tcx>, LocalDefId), -) -> bool { - trace!(%root, target = %tcx.def_path_str(target.to_def_id())); - let param_env = tcx.param_env_reveal_all_normalized(target); - assert_ne!( - root.def_id().expect_local(), - target, - "you should not call `mir_callgraph_reachable` on immediate self recursion" - ); - assert!( - matches!(root.def, InstanceDef::Item(_)), - "you should not call `mir_callgraph_reachable` on shims" - ); - assert!( - !tcx.is_constructor(root.def_id()), - "you should not call `mir_callgraph_reachable` on enum/struct constructor functions" - ); - #[instrument(skip(tcx, param_env, target, stack, seen, recursion_limiter, caller))] - fn process( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - caller: ty::Instance<'tcx>, - target: LocalDefId, - stack: &mut Vec<ty::Instance<'tcx>>, - seen: &mut FxHashSet<ty::Instance<'tcx>>, - recursion_limiter: &mut FxHashMap<DefId, usize>, - ) -> bool { - trace!(%caller); - for &(callee, substs) in tcx.mir_inliner_callees(caller.def) { - let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs); - let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() { - Some(callee) => callee, - None => { - trace!(?callee, "cannot resolve, skipping"); - continue; - } - }; - - // Found a path. - if callee.def_id() == target.to_def_id() { - return true; - } - - if tcx.is_constructor(callee.def_id()) { - trace!("constructors always have MIR"); - // Constructor functions cannot cause a query cycle. - continue; - } - - match callee.def { - InstanceDef::Item(_) => { - // If there is no MIR available (either because it was not in metadata or - // because it has no MIR because it's an extern function), then the inliner - // won't cause cycles on this. - if !tcx.is_mir_available(callee.def_id()) { - trace!(?callee, "no mir available, skipping"); - continue; - } - } - // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue, - // These have MIR and if that MIR is inlined, substituted and then inlining is run - // again, a function item can end up getting inlined. Thus we'll be able to cause - // a cycle that way - InstanceDef::VtableShim(_) - | InstanceDef::ReifyShim(_) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::CloneShim(..) => {} - InstanceDef::DropGlue(..) => { - // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to - // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this - // needs some more analysis. - if callee.needs_subst() { - continue; - } - } - } - - if seen.insert(callee) { - let recursion = recursion_limiter.entry(callee.def_id()).or_default(); - trace!(?callee, recursion = *recursion); - if tcx.sess.recursion_limit().value_within_limit(*recursion) { - *recursion += 1; - stack.push(callee); - let found_recursion = ensure_sufficient_stack(|| { - process(tcx, param_env, callee, target, stack, seen, recursion_limiter) - }); - if found_recursion { - return true; - } - stack.pop(); - } else { - // Pessimistically assume that there could be recursion. - return true; - } - } - } - false - } - process( - tcx, - param_env, - root, - target, - &mut Vec::new(), - &mut FxHashSet::default(), - &mut FxHashMap::default(), - ) -} - -crate fn mir_inliner_callees<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, -) -> &'tcx [(DefId, SubstsRef<'tcx>)] { - let steal; - let guard; - let body = match (instance, instance.def_id().as_local()) { - (InstanceDef::Item(_), Some(def_id)) => { - let def = ty::WithOptConstParam::unknown(def_id); - steal = tcx.mir_promoted(def).0; - guard = steal.borrow(); - &*guard - } - // Functions from other crates and MIR shims - _ => tcx.instance_mir(instance), - }; - let mut calls = Vec::new(); - for bb_data in body.basic_blocks() { - let terminator = bb_data.terminator(); - if let TerminatorKind::Call { func, .. } = &terminator.kind { - let ty = func.ty(&body.local_decls, tcx); - let call = match ty.kind() { - ty::FnDef(def_id, substs) => (*def_id, *substs), - _ => continue, - }; - // We've seen this before - if calls.contains(&call) { - continue; - } - calls.push(call); - } - } - tcx.arena.alloc_slice(&calls) -} diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index 74dadb2572565..b0c70372b161a 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -1,122 +1,329 @@ //! Performs various peephole optimizations. use crate::transform::MirPass; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; +use rustc_index::vec::Idx; use rustc_middle::mir::{ - BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - StatementKind, + visit::PlaceContext, + visit::{MutVisitor, Visitor}, + Statement, +}; +use rustc_middle::mir::{ + BinOp, Body, BorrowKind, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, + Rvalue, }; use rustc_middle::ty::{self, TyCtxt}; +use std::mem; pub struct InstCombine; impl<'tcx> MirPass<'tcx> for InstCombine { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let ctx = InstCombineContext { tcx, local_decls }; - for block in basic_blocks.iter_mut() { - for statement in block.statements.iter_mut() { - match statement.kind { - StatementKind::Assign(box (_place, ref mut rvalue)) => { - ctx.combine_bool_cmp(&statement.source_info, rvalue); - ctx.combine_ref_deref(&statement.source_info, rvalue); - ctx.combine_len(&statement.source_info, rvalue); - } - _ => {} - } - } + // First, find optimization opportunities. This is done in a pre-pass to keep the MIR + // read-only so that we can do global analyses on the MIR in the process (e.g. + // `Place::ty()`). + let optimizations = { + let mut optimization_finder = OptimizationFinder::new(body, tcx); + optimization_finder.visit_body(body); + optimization_finder.optimizations + }; + + if !optimizations.is_empty() { + // Then carry out those optimizations. + MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); } } } -struct InstCombineContext<'tcx, 'a> { +pub struct InstCombineVisitor<'tcx> { + optimizations: OptimizationList<'tcx>, tcx: TyCtxt<'tcx>, - local_decls: &'a LocalDecls<'tcx>, } -impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { - fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool { +impl<'tcx> InstCombineVisitor<'tcx> { + fn should_combine(&self, rvalue: &Rvalue<'tcx>, location: Location) -> bool { self.tcx.consider_optimizing(|| { - format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info) + format!("InstCombine - Rvalue: {:?} Location: {:?}", rvalue, location) }) } +} + +impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } - /// Transform boolean comparisons into logical operations. - fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { - match rvalue { - Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), a, b) => { - let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) { - // Transform "Eq(a, true)" ==> "a" - (BinOp::Eq, _, Some(true)) => Some(a.clone()), - - // Transform "Ne(a, false)" ==> "a" - (BinOp::Ne, _, Some(false)) => Some(a.clone()), - - // Transform "Eq(true, b)" ==> "b" - (BinOp::Eq, Some(true), _) => Some(b.clone()), - - // Transform "Ne(false, b)" ==> "b" - (BinOp::Ne, Some(false), _) => Some(b.clone()), - - // FIXME: Consider combining remaining comparisons into logical operations: - // Transform "Eq(false, b)" ==> "Not(b)" - // Transform "Ne(true, b)" ==> "Not(b)" - // Transform "Eq(a, false)" ==> "Not(a)" - // Transform "Ne(a, true)" ==> "Not(a)" - _ => None, - }; - - if let Some(new) = new { - if self.should_combine(source_info, rvalue) { - *rvalue = Rvalue::Use(new); + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + if self.optimizations.and_stars.remove(&location) && self.should_combine(rvalue, location) { + debug!("replacing `&*`: {:?}", rvalue); + let new_place = match rvalue { + Rvalue::Ref(_, _, place) => { + if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { + place.projection = self.tcx().intern_place_elems(&[proj_r]); + + Place { + // Replace with dummy + local: mem::replace(&mut place.local, Local::new(0)), + projection: self.tcx().intern_place_elems(proj_l), + } + } else { + unreachable!(); } } + _ => bug!("Detected `&*` but didn't find `&*`!"), + }; + *rvalue = Rvalue::Use(Operand::Copy(new_place)) + } + + if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { + if self.should_combine(rvalue, location) { + debug!("replacing `Len([_; N])`: {:?}", rvalue); + *rvalue = Rvalue::Use(Operand::Constant(box constant)); + } + } + + if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) { + if self.should_combine(rvalue, location) { + debug!("replacing {:?} with {:?}", rvalue, operand); + *rvalue = Rvalue::Use(operand); + } + } + + if let Some(place) = self.optimizations.unneeded_deref.remove(&location) { + if self.should_combine(rvalue, location) { + debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place); + *rvalue = Rvalue::Use(Operand::Copy(place)); } + } + + // We do not call super_rvalue as we are not interested in any other parts of the tree + } +} + +struct MutatingUseVisitor { + has_mutating_use: bool, + local_to_look_for: Local, +} + +impl MutatingUseVisitor { + fn has_mutating_use_in_stmt(local: Local, stmt: &Statement<'tcx>, location: Location) -> bool { + let mut _self = Self { has_mutating_use: false, local_to_look_for: local }; + _self.visit_statement(stmt, location); + _self.has_mutating_use + } +} - _ => {} +impl<'tcx> Visitor<'tcx> for MutatingUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, _: Location) { + if *local == self.local_to_look_for { + self.has_mutating_use |= context.is_mutating_use(); } } +} + +/// Finds optimization opportunities on the MIR. +struct OptimizationFinder<'b, 'tcx> { + body: &'b Body<'tcx>, + tcx: TyCtxt<'tcx>, + optimizations: OptimizationList<'tcx>, +} - fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> { - let a = a.constant()?; - if a.literal.ty.is_bool() { a.literal.val.try_to_bool() } else { None } +impl OptimizationFinder<'b, 'tcx> { + fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> { + OptimizationFinder { body, tcx, optimizations: OptimizationList::default() } } - /// Transform "&(*a)" ==> "a". - fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::Ref(_, _, place) = rvalue { - if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() { - if let ty::Ref(_, _, Mutability::Not) = - base.ty(self.local_decls, self.tcx).ty.kind() - { - // The dereferenced place must have type `&_`, so that we don't copy `&mut _`. - } else { - return; - } + fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { + // FIXME(#78192): This optimization can result in unsoundness. + if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts { + return None; + } + + // Look for the sequence + // + // _2 = &_1; + // ... + // _5 = (*_2); + // + // which we can replace the last statement with `_5 = _1;` to avoid the load of `_2`. + if let Rvalue::Use(op) = rvalue { + let local_being_derefed = match op.place()?.as_ref() { + PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), + _ => None, + }?; - if !self.should_combine(source_info, rvalue) { - return; + let mut dead_locals_seen = vec![]; + + let stmt_index = location.statement_index; + // Look behind for statement that assigns the local from a address of operator. + // 6 is chosen as a heuristic determined by seeing the number of times + // the optimization kicked in compiling rust std. + let lower_index = stmt_index.saturating_sub(6); + let statements_to_look_in = self.body.basic_blocks()[location.block].statements + [lower_index..stmt_index] + .iter() + .rev(); + for stmt in statements_to_look_in { + match &stmt.kind { + // Exhaustive match on statements to detect conditions that warrant we bail out of the optimization. + rustc_middle::mir::StatementKind::Assign(box (l, r)) + if l.local == local_being_derefed => + { + match r { + // Looking for immutable reference e.g _local_being_deref = &_1; + Rvalue::Ref( + _, + // Only apply the optimization if it is an immutable borrow. + BorrowKind::Shared, + place_taken_address_of, + ) => { + // Make sure that the place has not been marked dead + if dead_locals_seen.contains(&place_taken_address_of.local) { + return None; + } + + self.optimizations + .unneeded_deref + .insert(location, *place_taken_address_of); + return Some(()); + } + + // We found an assignment of `local_being_deref` that is not an immutable ref, e.g the following sequence + // _2 = &_1; + // _3 = &5 + // _2 = _3; <-- this means it is no longer valid to replace the last statement with `_5 = _1;` + // _5 = (*_2); + _ => return None, + } + } + + // Inline asm can do anything, so bail out of the optimization. + rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None, + + // Remember `StorageDead`s, as the local being marked dead could be the + // place RHS we are looking for, in which case we need to abort to avoid UB + // using an uninitialized place + rustc_middle::mir::StatementKind::StorageDead(dead) => { + dead_locals_seen.push(*dead) + } + + // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization. + rustc_middle::mir::StatementKind::Assign(box (_, _)) + | rustc_middle::mir::StatementKind::Coverage(_) + | rustc_middle::mir::StatementKind::Nop + | rustc_middle::mir::StatementKind::FakeRead(_, _) + | rustc_middle::mir::StatementKind::StorageLive(_) + | rustc_middle::mir::StatementKind::Retag(_, _) + | rustc_middle::mir::StatementKind::AscribeUserType(_, _) + | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => { + if MutatingUseVisitor::has_mutating_use_in_stmt( + local_being_derefed, + stmt, + location, + ) { + return None; + } + } } + } + } + Some(()) + } - *rvalue = Rvalue::Use(Operand::Copy(Place { - local: base.local, - projection: self.tcx.intern_place_elems(base.projection), - })); + fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + // find Ne(_place, false) or Ne(false, _place) + // or Eq(_place, true) or Eq(true, _place) + if let Rvalue::BinaryOp(op, l, r) = rvalue { + let const_to_find = if *op == BinOp::Ne { + false + } else if *op == BinOp::Eq { + true + } else { + return; + }; + // (const, _place) + if let Some(o) = self.find_operand_in_equality_comparison_pattern(l, r, const_to_find) { + self.optimizations.unneeded_equality_comparison.insert(location, o.clone()); + } + // (_place, const) + else if let Some(o) = + self.find_operand_in_equality_comparison_pattern(r, l, const_to_find) + { + self.optimizations.unneeded_equality_comparison.insert(location, o.clone()); } } } - /// Transform "Len([_; N])" ==> "N". - fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { + fn find_operand_in_equality_comparison_pattern( + &self, + l: &Operand<'tcx>, + r: &'a Operand<'tcx>, + const_to_find: bool, + ) -> Option<&'a Operand<'tcx>> { + let const_ = l.constant()?; + if const_.literal.ty == self.tcx.types.bool + && const_.literal.val.try_to_bool() == Some(const_to_find) + { + if r.place().is_some() { + return Some(r); + } + } + + None + } +} + +impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Ref(_, _, place) = rvalue { + if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() { + // The dereferenced place must have type `&_`. + let ty = place_base.ty(self.body, self.tcx).ty; + if let ty::Ref(_, _, Mutability::Not) = ty.kind() { + self.optimizations.and_stars.insert(location); + } + } + } + if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(self.local_decls, self.tcx).ty; + let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; if let ty::Array(_, len) = place_ty.kind() { - if !self.should_combine(source_info, rvalue) { - return; - } + let span = self.body.source_info(location).span; + let constant = Constant { span, literal: len, user_ty: None }; + self.optimizations.arrays_lengths.insert(location, constant); + } + } - let constant = Constant { span: source_info.span, literal: len, user_ty: None }; - *rvalue = Rvalue::Use(Operand::Constant(box constant)); + let _ = self.find_deref_of_address(rvalue, location); + + self.find_unneeded_equality_comparison(rvalue, location); + + // We do not call super_rvalue as we are not interested in any other parts of the tree + } +} + +#[derive(Default)] +struct OptimizationList<'tcx> { + and_stars: FxHashSet<Location>, + arrays_lengths: FxHashMap<Location, Constant<'tcx>>, + unneeded_equality_comparison: FxHashMap<Location, Operand<'tcx>>, + unneeded_deref: FxHashMap<Location, Place<'tcx>>, +} + +impl<'tcx> OptimizationList<'tcx> { + fn is_empty(&self) -> bool { + match self { + OptimizationList { + and_stars, + arrays_lengths, + unneeded_equality_comparison, + unneeded_deref, + } => { + and_stars.is_empty() + && arrays_lengths.is_empty() + && unneeded_equality_comparison.is_empty() + && unneeded_deref.is_empty() } } } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 2786127513d38..e509c35de40b8 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -419,20 +419,6 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( tcx.ensure().mir_borrowck(def.did); } - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - use rustc_middle::hir::map::blocks::FnLikeNode; - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); - if is_fn_like { - let did = def.did.to_def_id(); - let def = ty::WithOptConstParam::unknown(did); - - // Do not compute the mir call graph without said call graph actually being used. - // Keep this in sync with the mir inliner's optimization level. - if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { - let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def)); - } - } - let (body, _) = tcx.mir_promoted(def); let mut body = body.steal(); diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index d8758e045443c..cac5abb1059a8 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -415,11 +415,10 @@ impl<'tcx> Validator<'_, 'tcx> { // FIXME(eddyb) maybe cache this? fn validate_local(&self, local: Local) -> Result<(), Unpromotable> { if let TempState::Defined { location: loc, .. } = self.temps[local] { - let block = &self.body[loc.block]; - let num_stmts = block.statements.len(); + let num_stmts = self.body[loc.block].statements.len(); if loc.statement_index < num_stmts { - let statement = &block.statements[loc.statement_index]; + let statement = &self.body[loc.block].statements[loc.statement_index]; match &statement.kind { StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), _ => { @@ -431,7 +430,7 @@ impl<'tcx> Validator<'_, 'tcx> { } } } else { - let terminator = block.terminator(); + let terminator = self.body[loc.block].terminator(); match &terminator.kind { TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), TerminatorKind::Yield { .. } => Err(Unpromotable), @@ -453,15 +452,22 @@ impl<'tcx> Validator<'_, 'tcx> { match elem { ProjectionElem::Deref => { let mut promotable = false; - // We need to make sure this is a `Deref` of a local with no further projections. + // The `is_empty` predicate is introduced to exclude the case + // where the projection operations are [ .field, * ]. + // The reason is because promotion will be illegal if field + // accesses precede the dereferencing. // Discussion can be found at // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 - if let Some(local) = place_base.as_local() { + // There may be opportunity for generalization, but this needs to be + // accounted for. + if place_base.projection.is_empty() { // This is a special treatment for cases like *&STATIC where STATIC is a // global static variable. // This pattern is generated only when global static variables are directly // accessed and is qualified for promotion safely. - if let TempState::Defined { location, .. } = self.temps[local] { + if let TempState::Defined { location, .. } = + self.temps[place_base.local] + { let def_stmt = self.body[location.block] .statements .get(location.statement_index); @@ -499,50 +505,6 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} ProjectionElem::Index(local) => { - if !self.explicit { - let mut promotable = false; - // Only accept if we can predict the index and are indexing an array. - let val = if let TempState::Defined { location: loc, .. } = - self.temps[local] - { - let block = &self.body[loc.block]; - if loc.statement_index < block.statements.len() { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )) => c.literal.try_eval_usize(self.tcx, self.param_env), - _ => None, - } - } else { - None - } - } else { - None - }; - if let Some(idx) = val { - // Determine the type of the thing we are indexing. - let ty = place_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::Array(_, len) => { - // It's an array; determine its length. - if let Some(len) = - len.try_eval_usize(self.tcx, self.param_env) - { - // If the index is in-bounds, go ahead. - if idx < len { - promotable = true; - } - } - } - _ => {} - } - } - if !promotable { - return Err(Unpromotable); - } - } self.validate_local(local)?; } @@ -627,7 +589,9 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match rvalue { - Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { + Rvalue::Use(operand) + | Rvalue::Repeat(operand, _) + | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => { self.validate_operand(operand)?; } @@ -652,26 +616,10 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } - Rvalue::NullaryOp(op, _) => match op { - NullOp::Box => return Err(Unpromotable), - NullOp::SizeOf => {} - }, - - Rvalue::UnaryOp(op, operand) => { - match op { - // These operations can never fail. - UnOp::Neg | UnOp::Not => {} - } - - self.validate_operand(operand)?; - } - Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => { let op = *op; - let lhs_ty = lhs.ty(self.body, self.tcx); - - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { - // Raw and fn pointer operations are not allowed inside consts and thus not promotable. + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { + // raw pointer operations are not allowed inside consts and thus not promotable assert!(matches!( op, BinOp::Eq @@ -686,22 +634,7 @@ impl<'tcx> Validator<'_, 'tcx> { } match op { - BinOp::Div | BinOp::Rem => { - if !self.explicit && lhs_ty.is_integral() { - // Integer division: the RHS must be a non-zero const. - let const_val = match rhs { - Operand::Constant(c) => { - c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty) - } - _ => None, - }; - match const_val { - Some(x) if x != 0 => {} // okay - _ => return Err(Unpromotable), // value not known or 0 -- not okay - } - } - } - // The remaining operations can never fail. + // FIXME: reject operations that can fail -- namely, division and modulo. BinOp::Eq | BinOp::Ne | BinOp::Le @@ -712,6 +645,8 @@ impl<'tcx> Validator<'_, 'tcx> { | BinOp::Add | BinOp::Sub | BinOp::Mul + | BinOp::Div + | BinOp::Rem | BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr @@ -723,6 +658,11 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(rhs)?; } + Rvalue::NullaryOp(op, _) => match op { + NullOp::Box => return Err(Unpromotable), + NullOp::SizeOf => {} + }, + Rvalue::AddressOf(_, place) => { // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is // no problem, only using it is. diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 5144d48750de7..221114eebaa45 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -1,8 +1,9 @@ //! This pass replaces a drop of a type that does not need dropping, with a goto use crate::transform::MirPass; +use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ParamEnv, TyCtxt}; use super::simplify::simplify_cfg; @@ -11,26 +12,24 @@ pub struct RemoveUnneededDrops; impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemoveUnneededDrops on {:?}", body.source); - - let did = body.source.def_id(); - let param_env = tcx.param_env(did); - let mut should_simplify = false; - - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { - let terminator = block.terminator_mut(); - if let TerminatorKind::Drop { place, target, .. } = terminator.kind { - let ty = place.ty(local_decls, tcx); - if ty.ty.needs_drop(tcx, param_env) { - continue; - } - if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) { - continue; - } - debug!("SUCCESS: replacing `drop` with goto({:?})", target); - terminator.kind = TerminatorKind::Goto { target }; - should_simplify = true; + let mut opt_finder = RemoveUnneededDropsOptimizationFinder { + tcx, + body, + param_env: tcx.param_env(body.source.def_id()), + optimizations: vec![], + }; + opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); + for (loc, target) in opt_finder.optimizations { + if !tcx + .consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", body.source.def_id())) + { + break; } + + let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; } // if we applied optimizations, we potentially have some cfg to cleanup to @@ -40,3 +39,25 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { } } } + +impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + let ty = place.ty(self.body, self.tcx); + let needs_drop = ty.ty.needs_drop(self.tcx, self.param_env); + if !needs_drop { + self.optimizations.push((location, target)); + } + } + _ => {} + } + self.super_terminator(terminator, location); + } +} +pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + optimizations: Vec<(Location, BasicBlock)>, + param_env: ParamEnv<'tcx>, +} diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 2962cbe8157f6..595458702e9c9 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -546,7 +546,9 @@ fn make_mirror_unadjusted<'a, 'tcx>( scrutinee: discr.to_ref(), arms: arms.iter().map(|a| convert_arm(cx, a)).collect(), }, - hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) }, + hir::ExprKind::Loop(ref body, _, _) => { + ExprKind::Loop { body: block::to_expr_ref(cx, body) } + } hir::ExprKind::Field(ref source, ..) => ExprKind::Field { lhs: source.to_ref(), name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index c365acac625a4..62fd6936d210d 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -292,7 +292,7 @@ pub fn nt_to_tokenstream( } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) { return fake_token_stream(sess, nt); } else { - panic!("Missing tokens for nt at {:?}: {:?}", nt.span(), pprust::nonterminal_to_string(nt)); + panic!("Missing tokens for nt {:?}", pprust::nonterminal_to_string(nt)); } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f2fcce5c22662..35435baea7019 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2,13 +2,14 @@ use super::ty::AllowPlus; use super::TokenType; use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType}; -use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Lit, LitKind, TokenKind}; use rustc_ast::util::parser::AssocOp; -use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec}; -use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item}; -use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind}; +use rustc_ast::{ + self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, + Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat, + PatKind, Path, PathSegment, QSelf, Ty, TyKind, +}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err}; @@ -219,7 +220,6 @@ impl<'a> Parser<'a> { edible: &[TokenKind], inedible: &[TokenKind], ) -> PResult<'a, bool /* recovered */> { - debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible); fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); // This might be a sign we need a connect method on `Iterator`. @@ -245,7 +245,6 @@ impl<'a> Parser<'a> { .collect::<Vec<_>>(); expected.sort_by_cached_key(|x| x.to_string()); expected.dedup(); - let expect = tokens_to_string(&expected[..]); let actual = super::token_descr(&self.token); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { @@ -271,16 +270,6 @@ impl<'a> Parser<'a> { }; self.last_unexpected_token_span = Some(self.token.span); let mut err = self.struct_span_err(self.token.span, &msg_exp); - - // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens - // there are unclosed angle brackets - if self.unmatched_angle_bracket_count > 0 - && self.token.kind == TokenKind::Eq - && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt))) - { - err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket"); - } - let sp = if self.token == token::Eof { // This is EOF; don't want to point at the following char, but rather the last token. self.prev_token.span diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cfd7ad48222a2..6db415ead415c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -472,11 +472,7 @@ impl<'a> Parser<'a> { /// Parses a prefix-unary-operator expr. fn parse_prefix_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> { let attrs = self.parse_or_use_outer_attributes(attrs)?; - // FIXME: Use super::attr::maybe_needs_tokens(&attrs) once we come up - // with a good way of passing `force_tokens` through from `parse_nonterminal`. - // Checking !attrs.is_empty() is correct, but will cause us to unnecessarily - // capture tokens in some circumstances. - let needs_tokens = !attrs.is_empty(); + let needs_tokens = super::attr::maybe_needs_tokens(&attrs); let do_parse = |this: &mut Parser<'a>| { let lo = this.token.span; // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() @@ -585,7 +581,7 @@ impl<'a> Parser<'a> { lhs_span: Span, expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind, ) -> PResult<'a, P<Expr>> { - let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| { + let mk_expr = |this: &mut Self, rhs: P<Ty>| { this.mk_expr( this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs), @@ -597,49 +593,13 @@ impl<'a> Parser<'a> { // LessThan comparison after this cast. let parser_snapshot_before_type = self.clone(); let cast_expr = match self.parse_ty_no_plus() { - Ok(rhs) => mk_expr(self, lhs, rhs), + Ok(rhs) => mk_expr(self, rhs), Err(mut type_err) => { // Rewind to before attempting to parse the type with generics, to recover // from situations like `x as usize < y` in which we first tried to parse // `usize < y` as a type with generic arguments. let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type); - // Check for typo of `'a: loop { break 'a }` with a missing `'`. - match (&lhs.kind, &self.token.kind) { - ( - // `foo: ` - ExprKind::Path(None, ast::Path { segments, .. }), - TokenKind::Ident(kw::For | kw::Loop | kw::While, false), - ) if segments.len() == 1 => { - let snapshot = self.clone(); - let label = Label { - ident: Ident::from_str_and_span( - &format!("'{}", segments[0].ident), - segments[0].ident.span, - ), - }; - match self.parse_labeled_expr(label, AttrVec::new(), false) { - Ok(expr) => { - type_err.cancel(); - self.struct_span_err(label.ident.span, "malformed loop label") - .span_suggestion( - label.ident.span, - "use the correct loop label format", - label.ident.to_string(), - Applicability::MachineApplicable, - ) - .emit(); - return Ok(expr); - } - Err(mut err) => { - err.cancel(); - *self = snapshot; - } - } - } - _ => {} - } - match self.parse_path(PathStyle::Expr) { Ok(path) => { let (op_noun, op_verb) = match self.token.kind { @@ -666,8 +626,7 @@ impl<'a> Parser<'a> { op_noun, ); let span_after_type = parser_snapshot_after_type.token.span; - let expr = - mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path))); + let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path))); let expr_str = self .span_to_snippet(expr.span) @@ -1104,7 +1063,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::While) { self.parse_while_expr(None, self.prev_token.span, attrs) } else if let Some(label) = self.eat_label() { - self.parse_labeled_expr(label, attrs, true) + self.parse_labeled_expr(label, attrs) } else if self.eat_keyword(kw::Loop) { self.parse_loop_expr(None, self.prev_token.span, attrs) } else if self.eat_keyword(kw::Continue) { @@ -1265,12 +1224,7 @@ impl<'a> Parser<'a> { } /// Parse `'label: $expr`. The label is already parsed. - fn parse_labeled_expr( - &mut self, - label: Label, - attrs: AttrVec, - consume_colon: bool, - ) -> PResult<'a, P<Expr>> { + fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> { let lo = label.ident.span; let label = Some(label); let ate_colon = self.eat(&token::Colon); @@ -1289,7 +1243,7 @@ impl<'a> Parser<'a> { self.parse_expr() }?; - if !ate_colon && consume_colon { + if !ate_colon { self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span); } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1ed4d39cd0539..810ae61307c19 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,8 +1,8 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; -use super::{FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; +use super::{FollowedByType, Parser, PathStyle}; -use crate::{maybe_collect_tokens, maybe_whole}; +use crate::maybe_whole; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; @@ -69,7 +69,7 @@ impl<'a> Parser<'a> { unsafety: Unsafe, ) -> PResult<'a, Mod> { let mut items = vec![]; - while let Some(item) = self.parse_item(ForceCollect::No)? { + while let Some(item) = self.parse_item()? { items.push(item); self.maybe_consume_incorrect_semicolon(&items); } @@ -93,17 +93,13 @@ impl<'a> Parser<'a> { pub(super) type ItemInfo = (Ident, ItemKind); impl<'a> Parser<'a> { - pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> { - self.parse_item_(|_| true, force_collect).map(|i| i.map(P)) + pub fn parse_item(&mut self) -> PResult<'a, Option<P<Item>>> { + self.parse_item_(|_| true).map(|i| i.map(P)) } - fn parse_item_( - &mut self, - req_name: ReqName, - force_collect: ForceCollect, - ) -> PResult<'a, Option<Item>> { + fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option<Item>> { let attrs = self.parse_outer_attributes()?; - self.parse_item_common(attrs, true, false, req_name, force_collect) + self.parse_item_common(attrs, true, false, req_name) } pub(super) fn parse_item_common( @@ -112,7 +108,6 @@ impl<'a> Parser<'a> { mac_allowed: bool, attrs_allowed: bool, req_name: ReqName, - force_collect: ForceCollect, ) -> PResult<'a, Option<Item>> { maybe_whole!(self, NtItem, |item| { let mut item = item; @@ -121,12 +116,16 @@ impl<'a> Parser<'a> { Some(item.into_inner()) }); + let needs_tokens = super::attr::maybe_needs_tokens(&attrs); + let mut unclosed_delims = vec![]; - let item = maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Self| { + let parse_item = |this: &mut Self| { let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name); unclosed_delims.append(&mut this.unclosed_delims); - Ok((item?, TrailingToken::None)) - })?; + item + }; + + let item = if needs_tokens { self.collect_tokens(parse_item) } else { parse_item(self) }?; self.unclosed_delims.append(&mut unclosed_delims); Ok(item) @@ -732,22 +731,20 @@ impl<'a> Parser<'a> { /// Parses associated items. fn parse_assoc_item(&mut self, req_name: ReqName) -> PResult<'a, Option<Option<P<AssocItem>>>> { - Ok(self.parse_item_(req_name, ForceCollect::No)?.map( - |Item { attrs, id, span, vis, ident, kind, tokens }| { - let kind = match AssocItemKind::try_from(kind) { - Ok(kind) => kind, - Err(kind) => match kind { - ItemKind::Static(a, _, b) => { - self.struct_span_err(span, "associated `static` items are not allowed") - .emit(); - AssocItemKind::Const(Defaultness::Final, a, b) - } - _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), - }, - }; - Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) - }, - )) + Ok(self.parse_item_(req_name)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| { + let kind = match AssocItemKind::try_from(kind) { + Ok(kind) => kind, + Err(kind) => match kind { + ItemKind::Static(a, _, b) => { + self.struct_span_err(span, "associated `static` items are not allowed") + .emit(); + AssocItemKind::Const(Defaultness::Final, a, b) + } + _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), + }, + }; + Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) + })) } /// Parses a `type` alias with the following grammar: @@ -924,21 +921,19 @@ impl<'a> Parser<'a> { /// Parses a foreign item (one in an `extern { ... }` block). pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<Option<P<ForeignItem>>>> { - Ok(self.parse_item_(|_| true, ForceCollect::No)?.map( - |Item { attrs, id, span, vis, ident, kind, tokens }| { - let kind = match ForeignItemKind::try_from(kind) { - Ok(kind) => kind, - Err(kind) => match kind { - ItemKind::Const(_, a, b) => { - self.error_on_foreign_const(span, ident); - ForeignItemKind::Static(a, Mutability::Not, b) - } - _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), - }, - }; - Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) - }, - )) + Ok(self.parse_item_(|_| true)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| { + let kind = match ForeignItemKind::try_from(kind) { + Ok(kind) => kind, + Err(kind) => match kind { + ItemKind::Const(_, a, b) => { + self.error_on_foreign_const(span, ident); + ForeignItemKind::Static(a, Mutability::Not, b) + } + _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), + }, + }; + Some(P(Item { attrs, id, span, vis, ident, kind, tokens })) + })) } fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> { @@ -1520,7 +1515,7 @@ impl<'a> Parser<'a> { { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); - let item = self.parse_item(ForceCollect::No)?; + let item = self.parse_item()?; self.struct_span_err( kw_token.span, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c575c8219641c..5d7ea5b8d578e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -54,18 +54,6 @@ enum BlockMode { Ignore, } -/// Whether or not we should force collection of tokens for an AST node, -/// regardless of whether or not it has attributes -pub enum ForceCollect { - Yes, - No, -} - -pub enum TrailingToken { - None, - Semi, -} - /// Like `maybe_whole_expr`, but for things other than expressions. #[macro_export] macro_rules! maybe_whole { @@ -277,7 +265,7 @@ impl TokenCursor { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Clone, PartialEq)] enum TokenType { Token(TokenKind), Keyword(Symbol), @@ -980,8 +968,12 @@ impl<'a> Parser<'a> { } } - // Collect tokens because they are used during lowering to HIR. - let expr = self.collect_tokens(|this| this.parse_expr())?; + // The value here is never passed to macros as tokens by itself (not as a part + // of the whole attribute), so we don't collect tokens here. If this changes, + // then token will need to be collected. One catch here is that we are using + // a nonterminal for keeping the expression, but this nonterminal should not + // be wrapped into a group when converting to token stream. + let expr = self.parse_expr()?; let span = expr.span; match &expr.kind { @@ -1226,13 +1218,6 @@ impl<'a> Parser<'a> { } } - pub fn collect_tokens<R: HasTokens>( - &mut self, - f: impl FnOnce(&mut Self) -> PResult<'a, R>, - ) -> PResult<'a, R> { - self.collect_tokens_trailing_token(|this| Ok((f(this)?, TrailingToken::None))) - } - /// Records all tokens consumed by the provided callback, /// including the current token. These tokens are collected /// into a `LazyTokenStream`, and returned along with the result @@ -1249,9 +1234,9 @@ impl<'a> Parser<'a> { /// This restriction shouldn't be an issue in practice, /// since this function is used to record the tokens for /// a parsed AST item, which always has matching delimiters. - pub fn collect_tokens_trailing_token<R: HasTokens>( + pub fn collect_tokens<R: HasTokens>( &mut self, - f: impl FnOnce(&mut Self) -> PResult<'a, (R, TrailingToken)>, + f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, R> { let start_token = (self.token.clone(), self.token_spacing); let cursor_snapshot = TokenCursor { @@ -1264,7 +1249,7 @@ impl<'a> Parser<'a> { append_unglued_token: self.token_cursor.append_unglued_token.clone(), }; - let (mut ret, trailing_token) = f(self)?; + let mut ret = f(self)?; // Produces a `TokenStream` on-demand. Using `cursor_snapshot` // and `num_calls`, we can reconstruct the `TokenStream` seen @@ -1283,10 +1268,15 @@ impl<'a> Parser<'a> { cursor_snapshot: TokenCursor, num_calls: usize, desugar_doc_comments: bool, + trailing_semi: bool, append_unglued_token: Option<TreeAndSpacing>, } impl CreateTokenStream for LazyTokenStreamImpl { fn create_token_stream(&self) -> TokenStream { + let mut num_calls = self.num_calls; + if self.trailing_semi { + num_calls += 1; + } // The token produced by the final call to `next` or `next_desugared` // was not actually consumed by the callback. The combination // of chaining the initial token and using `take` produces the desired @@ -1294,33 +1284,39 @@ impl<'a> Parser<'a> { // and omit the final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); let tokens = std::iter::once(self.start_token.clone()) - .chain((0..self.num_calls).map(|_| { + .chain((0..num_calls).map(|_| { if self.desugar_doc_comments { cursor_snapshot.next_desugared() } else { cursor_snapshot.next() } })) - .take(self.num_calls); + .take(num_calls); make_token_stream(tokens, self.append_unglued_token.clone()) } - } - - let mut num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls; - match trailing_token { - TrailingToken::None => {} - TrailingToken::Semi => { - assert_eq!(self.token.kind, token::Semi); - num_calls += 1; + fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> { + if self.trailing_semi { + panic!("Called `add_trailing_semi` twice!"); + } + if self.append_unglued_token.is_some() { + panic!( + "Cannot call `add_trailing_semi` when we have an unglued token {:?}", + self.append_unglued_token + ); + } + let mut new = self.clone(); + new.trailing_semi = true; + Box::new(new) } } let lazy_impl = LazyTokenStreamImpl { start_token, - num_calls, + num_calls: self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls, cursor_snapshot, desugar_doc_comments: self.desugar_doc_comments, + trailing_semi: false, append_unglued_token: self.token_cursor.append_unglued_token.clone(), }; ret.finalize_tokens(LazyTokenStream::new(lazy_impl)); @@ -1417,16 +1413,3 @@ fn make_token_stream( assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack); TokenStream::new(final_buf.inner) } - -#[macro_export] -macro_rules! maybe_collect_tokens { - ($self:ident, $force_collect:expr, $attrs:expr, $f:expr) => { - if matches!($force_collect, ForceCollect::Yes) - || $crate::parser::attr::maybe_needs_tokens($attrs) - { - $self.collect_tokens_trailing_token($f) - } else { - Ok($f($self)?.0) - } - }; -} diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 012b76d3d1887..97d0c0d874583 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -5,7 +5,7 @@ use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; use crate::parser::pat::{GateOr, RecoverComma}; -use crate::parser::{FollowedByType, ForceCollect, Parser, PathStyle}; +use crate::parser::{FollowedByType, Parser, PathStyle}; impl<'a> Parser<'a> { /// Checks whether a non-terminal may begin with a particular token. @@ -98,7 +98,7 @@ impl<'a> Parser<'a> { // in advance whether or not a proc-macro will be (transitively) invoked, // we always capture tokens for any `Nonterminal` which needs them. Ok(match kind { - NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { + NonterminalKind::Item => match self.collect_tokens(|this| this.parse_item())? { Some(item) => token::NtItem(item), None => { return Err(self.struct_span_err(self.token.span, "expected an item keyword")); @@ -107,7 +107,7 @@ impl<'a> Parser<'a> { NonterminalKind::Block => { token::NtBlock(self.collect_tokens(|this| this.parse_block())?) } - NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { + NonterminalKind::Stmt => match self.collect_tokens(|this| this.parse_stmt())? { Some(s) => token::NtStmt(s), None => { return Err(self.struct_span_err(self.token.span, "expected a statement")); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4234740b2b15f..dd36122f6a10e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -185,6 +185,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; + let is_args_start = |token: &Token| { matches!( token.kind, @@ -419,10 +420,7 @@ impl<'a> Parser<'a> { match arg { Some(arg) => { if self.check(&token::Colon) | self.check(&token::Eq) { - let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) { - Ok(ident_gen_args) => ident_gen_args, - Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))), - }; + let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?; let kind = if self.eat(&token::Colon) { // Parse associated type constraint bound. @@ -563,15 +561,50 @@ impl<'a> Parser<'a> { fn get_ident_from_generic_arg( &self, gen_arg: GenericArg, - ) -> Result<(Ident, Option<GenericArgs>), GenericArg> { - if let GenericArg::Type(ty) = &gen_arg { - if let ast::TyKind::Path(qself, path) = &ty.kind { - if qself.is_none() && path.segments.len() == 1 { - let seg = &path.segments[0]; - return Ok((seg.ident, seg.args.as_deref().cloned())); + lo: Span, + ) -> PResult<'a, (Ident, Option<GenericArgs>)> { + let gen_arg_span = gen_arg.span(); + match gen_arg { + GenericArg::Type(t) => match t.into_inner().kind { + ast::TyKind::Path(qself, mut path) => { + if let Some(qself) = qself { + let mut err = self.struct_span_err( + gen_arg_span, + "qualified paths cannot be used in associated type constraints", + ); + err.span_label( + qself.path_span, + "not allowed in associated type constraints", + ); + return Err(err); + } + if path.segments.len() == 1 { + let path_seg = path.segments.remove(0); + let ident = path_seg.ident; + let gen_args = path_seg.args.map(|args| args.into_inner()); + return Ok((ident, gen_args)); + } + let err = self.struct_span_err( + path.span, + "paths with multiple segments cannot be used in associated type constraints", + ); + return Err(err); + } + _ => { + let span = lo.to(self.prev_token.span); + let err = self.struct_span_err( + span, + "only path types can be used in associated type constraints", + ); + return Err(err); } + }, + _ => { + let span = lo.to(self.prev_token.span); + let err = self + .struct_span_err(span, "only types can be used in associated type constraints"); + return Err(err); } } - Err(gen_arg) } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 8373f6acd7e01..641b29227db98 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -3,13 +3,14 @@ use super::diagnostics::{AttemptLocalParseRecovery, Error}; use super::expr::LhsExpr; use super::pat::{GateOr, RecoverComma}; use super::path::PathStyle; -use super::{BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode, TrailingToken}; -use crate::{maybe_collect_tokens, maybe_whole}; +use super::{BlockMode, Parser, Restrictions, SemiColonMode}; +use crate::maybe_whole; use rustc_ast as ast; use rustc_ast::attr::HasAttrs; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; +use rustc_ast::tokenstream::LazyTokenStream; use rustc_ast::util::classify; use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; @@ -23,22 +24,17 @@ impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. // Public for rustfmt usage. - pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { - Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|mut e| { + pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> { + Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None })) } - /// If `force_capture` is true, forces collection of tokens regardless of whether - /// or not we have attributes - fn parse_stmt_without_recovery( - &mut self, - capture_semi: bool, - force_collect: ForceCollect, - ) -> PResult<'a, Option<Stmt>> { + fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> { let mut attrs = self.parse_outer_attributes()?; + let has_attrs = !attrs.is_empty(); let lo = self.token.span; maybe_whole!(self, NtStmt, |stmt| { @@ -50,77 +46,75 @@ impl<'a> Parser<'a> { Some(stmt) }); - Ok(Some(if self.token.is_keyword(kw::Let) { - self.parse_local_mk(lo, attrs.into(), capture_semi, force_collect)? - } else if self.is_kw_followed_by_ident(kw::Mut) { - self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")? - } else if self.is_kw_followed_by_ident(kw::Auto) { - self.bump(); // `auto` - let msg = "write `let` instead of `auto` to introduce a new variable"; - self.recover_stmt_local(lo, attrs.into(), msg, "let")? - } else if self.is_kw_followed_by_ident(sym::var) { - self.bump(); // `var` - let msg = "write `let` instead of `var` to introduce a new variable"; - self.recover_stmt_local(lo, attrs.into(), msg, "let")? - } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { - // We have avoided contextual keywords like `union`, items with `crate` visibility, - // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something - // that starts like a path (1 token), but it fact not a path. - // Also, we avoid stealing syntax from `parse_item_`. - self.parse_stmt_path_start(lo, attrs, force_collect)? - } else if let Some(item) = - self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)? - { - // FIXME: Bad copy of attrs - self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) - } else if self.eat(&token::Semi) { - // Do not attempt to parse an expression if we're done here. - self.error_outer_attrs(&attrs); - self.mk_stmt(lo, StmtKind::Empty) - } else if self.token != token::CloseDelim(token::Brace) { - // Remainder are line-expr stmts. - let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; - self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) + let parse_stmt_inner = |this: &mut Self| { + let stmt = if this.eat_keyword(kw::Let) { + this.parse_local_mk(lo, attrs.into())? + } else if this.is_kw_followed_by_ident(kw::Mut) { + this.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")? + } else if this.is_kw_followed_by_ident(kw::Auto) { + this.bump(); // `auto` + let msg = "write `let` instead of `auto` to introduce a new variable"; + this.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if this.is_kw_followed_by_ident(sym::var) { + this.bump(); // `var` + let msg = "write `let` instead of `var` to introduce a new variable"; + this.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if this.check_path() + && !this.token.is_qpath_start() + && !this.is_path_start_item() + { + // We have avoided contextual keywords like `union`, items with `crate` visibility, + // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something + // that starts like a path (1 token), but it fact not a path. + // Also, we avoid stealing syntax from `parse_item_`. + this.parse_stmt_path_start(lo, attrs)? + } else if let Some(item) = + this.parse_item_common(attrs.clone(), false, true, |_| true)? + { + // FIXME: Bad copy of attrs + this.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) + } else if this.eat(&token::Semi) { + // Do not attempt to parse an expression if we're done here. + this.error_outer_attrs(&attrs); + this.mk_stmt(lo, StmtKind::Empty) + } else if this.token != token::CloseDelim(token::Brace) { + // Remainder are line-expr stmts. + let e = this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; + this.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) + } else { + this.error_outer_attrs(&attrs); + return Ok(None); + }; + Ok(Some(stmt)) + }; + + let stmt = if has_attrs { + self.collect_tokens(parse_stmt_inner)? } else { - self.error_outer_attrs(&attrs); - return Ok(None); - })) + parse_stmt_inner(self)? + }; + Ok(stmt) } - fn parse_stmt_path_start( - &mut self, - lo: Span, - attrs: Vec<Attribute>, - force_collect: ForceCollect, - ) -> PResult<'a, Stmt> { - maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| { - let path = this.parse_path(PathStyle::Expr)?; + fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Stmt> { + let path = self.parse_path(PathStyle::Expr)?; - if this.eat(&token::Not) { - let stmt_mac = this.parse_stmt_mac(lo, attrs.into(), path)?; - if this.token == token::Semi { - return Ok((stmt_mac, TrailingToken::Semi)); - } else { - return Ok((stmt_mac, TrailingToken::None)); - } - } + if self.eat(&token::Not) { + return self.parse_stmt_mac(lo, attrs.into(), path); + } - let expr = if this.eat(&token::OpenDelim(token::Brace)) { - this.parse_struct_expr(path, AttrVec::new(), true)? - } else { - let hi = this.prev_token.span; - this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) - }; + let expr = if self.eat(&token::OpenDelim(token::Brace)) { + self.parse_struct_expr(path, AttrVec::new(), true)? + } else { + let hi = self.prev_token.span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) + }; - let expr = this.with_res(Restrictions::STMT_EXPR, |this| { - let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) - })?; - Ok(( - this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Expr(expr)), - TrailingToken::None, - )) - }) + let expr = self.with_res(Restrictions::STMT_EXPR, |this| { + let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + })?; + Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) } /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. @@ -168,34 +162,15 @@ impl<'a> Parser<'a> { msg: &str, sugg: &str, ) -> PResult<'a, Stmt> { - let stmt = self.recover_local_after_let(lo, attrs)?; + let stmt = self.parse_local_mk(lo, attrs)?; self.struct_span_err(lo, "invalid variable declaration") .span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable) .emit(); Ok(stmt) } - fn parse_local_mk( - &mut self, - lo: Span, - attrs: AttrVec, - capture_semi: bool, - force_collect: ForceCollect, - ) -> PResult<'a, Stmt> { - maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| { - this.expect_keyword(kw::Let)?; - let local = this.parse_local(attrs.into())?; - let trailing = if capture_semi && this.token.kind == token::Semi { - TrailingToken::Semi - } else { - TrailingToken::None - }; - Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), trailing)) - }) - } - - fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> { - let local = self.parse_local(attrs.into())?; + fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> { + let local = self.parse_local(attrs)?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local))) } @@ -317,7 +292,7 @@ impl<'a> Parser<'a> { // bar; // // which is valid in other languages, but not Rust. - match self.parse_stmt_without_recovery(false, ForceCollect::No) { + match self.parse_stmt_without_recovery() { // If the next token is an open brace (e.g., `if a b {`), the place- // inside-a-block suggestion would be more likely wrong than right. Ok(Some(_)) @@ -420,11 +395,17 @@ impl<'a> Parser<'a> { // Skip looking for a trailing semicolon when we have an interpolated statement. maybe_whole!(self, NtStmt, |x| Some(x)); - let mut stmt = match self.parse_stmt_without_recovery(true, ForceCollect::No)? { + let mut stmt = match self.parse_stmt_without_recovery()? { Some(stmt) => stmt, None => return Ok(None), }; + let add_semi_token = |tokens: Option<&mut LazyTokenStream>| { + if let Some(tokens) = tokens { + *tokens = tokens.add_trailing_semi(); + } + }; + let mut eat_semi = true; match stmt.kind { // Expression without semicolon. @@ -480,12 +461,18 @@ impl<'a> Parser<'a> { } } eat_semi = false; + // We just checked that there's a semicolon in the tokenstream, + // so capture it + add_semi_token(local.tokens.as_mut()); } StmtKind::Empty | StmtKind::Item(_) | StmtKind::Semi(_) => eat_semi = false, } if eat_semi && self.eat(&token::Semi) { stmt = stmt.add_trailing_semicolon(); + // We just checked that we have a semicolon in the tokenstream, + // so capture it + add_semi_token(stmt.tokens_mut()); } stmt.span = stmt.span.to(self.prev_token.span); Ok(Some(stmt)) diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 8950f9b33b6da..c887a860303b5 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -199,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { // Skip the following checks if we are not currently in a const context. _ if self.const_kind.is_none() => {} - hir::ExprKind::Loop(_, _, source, _) => { + hir::ExprKind::Loop(_, _, source) => { self.const_check_violated(NonConstExpr::Loop(*source), e.span); } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3b1b53553d5e4..80a24c90421e7 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -290,7 +290,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { } fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { - self.in_pat = true; match pat.kind { PatKind::Struct(ref path, ref fields, _) => { let res = self.typeck_results().qpath_res(path, pat.hir_id); @@ -303,6 +302,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { _ => (), } + self.in_pat = true; intravisit::walk_pat(self, pat); self.in_pat = false; } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index c11dc231d482c..6202cc312fc0e 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -844,7 +844,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Note that labels have been resolved, so we don't need to look // at the label ident - hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ), + hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ), hir::ExprKind::If(ref cond, ref then, ref else_opt) => { // diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 4bfac1b72983e..9b4da71e5e961 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { match e.kind { - hir::ExprKind::Loop(ref b, _, source, _) => { + hir::ExprKind::Loop(ref b, _, source) => { self.with_context(Loop(source), |v| v.visit_block(&b)); } hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => { @@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Block(ref b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(&b)); } - hir::ExprKind::Break(break_label, ref opt_expr) => { + hir::ExprKind::Break(label, ref opt_expr) => { if let Some(e) = opt_expr { self.visit_expr(e); } - if self.require_label_in_labeled_block(e.span, &break_label, "break") { + if self.require_label_in_labeled_block(e.span, &label, "break") { // If we emitted an error about an unlabeled break in a labeled // block, we don't need any further checking for this break any more return; } - let loop_id = match break_label.target_id { + let loop_id = match label.target_id { Ok(loop_id) => Some(loop_id), Err(hir::LoopIdError::OutsideLoopScope) => None, Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { @@ -89,89 +89,49 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { Err(hir::LoopIdError::UnresolvedLabel) => None, }; - if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) { - return; + if let Some(loop_id) = loop_id { + if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() { + return; + } } - if let Some(break_expr) = opt_expr { - let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id { - match self.hir_map.expect_expr(loop_id).kind { - hir::ExprKind::Loop(_, label, source, sp) => { - (Some(sp), label, Some(source)) - } + if opt_expr.is_some() { + let loop_kind = if let Some(loop_id) = loop_id { + Some(match self.hir_map.expect_expr(loop_id).kind { + hir::ExprKind::Loop(_, _, source) => source, ref r => { span_bug!(e.span, "break label resolved to a non-loop: {:?}", r) } - } + }) } else { - (None, None, None) + None }; match loop_kind { None | Some(hir::LoopSource::Loop) => (), Some(kind) => { - let mut err = struct_span_err!( + struct_span_err!( self.sess, e.span, E0571, "`break` with value from a `{}` loop", kind.name() - ); - err.span_label( + ) + .span_label( e.span, - "can only break with a value inside `loop` or breakable block", - ); - if let Some(head) = head { - err.span_label( - head, - &format!( - "you can't `break` with a value in a `{}` loop", - kind.name() - ), - ); - } - err.span_suggestion( + "can only break with a value inside \ + `loop` or breakable block", + ) + .span_suggestion( e.span, &format!( - "use `break` on its own without a value inside this `{}` loop", - kind.name(), - ), - format!( - "break{}", - break_label - .label - .map_or_else(String::new, |l| format!(" {}", l.ident)) + "instead, use `break` on its own \ + without a value inside this `{}` loop", + kind.name() ), + "break".to_string(), Applicability::MaybeIncorrect, - ); - if let (Some(label), None) = (loop_label, break_label.label) { - match break_expr.kind { - hir::ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: [segment], - res: hir::def::Res::Err, - .. - }, - )) if label.ident.to_string() - == format!("'{}", segment.ident) => - { - // This error is redundant, we will have already emitted a - // suggestion to use the label when `segment` wasn't found - // (hence the `Res::Err` check). - err.delay_as_bug(); - } - _ => { - err.span_suggestion( - break_expr.span, - "alternatively, you might have meant to use the \ - available loop label", - label.ident.to_string(), - Applicability::MaybeIncorrect, - ); - } - } - } - err.emit(); + ) + .emit(); } } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index eb24c51c54c35..b237671f8e208 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -307,7 +307,6 @@ impl<'tcx> ReachableContext<'tcx> { | Node::Ctor(..) | Node::Field(_) | Node::Ty(_) - | Node::Crate(_) | Node::MacroDef(_) => {} _ => { bug!( diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index 64356f73f6c65..91421d7f5f22b 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -252,7 +252,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h terminating(then.hir_id.local_id); } - hir::ExprKind::Loop(ref body, _, _, _) => { + hir::ExprKind::Loop(ref body, _, _) => { terminating(body.hir_id.local_id); } diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 1d2bc1a99a596..7bc6ae1d1c6c3 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -15,7 +15,7 @@ pub trait CacheSelector<K, V> { } pub trait QueryStorage: Default { - type Value: Debug; + type Value; type Stored: Clone; /// Store a value without putting it in the cache. @@ -75,7 +75,7 @@ impl<K, V> Default for DefaultCache<K, V> { } } -impl<K: Eq + Hash, V: Clone + Debug> QueryStorage for DefaultCache<K, V> { +impl<K: Eq + Hash, V: Clone> QueryStorage for DefaultCache<K, V> { type Value = V; type Stored = V; @@ -89,7 +89,7 @@ impl<K: Eq + Hash, V: Clone + Debug> QueryStorage for DefaultCache<K, V> { impl<K, V> QueryCache for DefaultCache<K, V> where K: Eq + Hash + Clone + Debug, - V: Clone + Debug, + V: Clone, { type Key = K; type Sharded = FxHashMap<K, (V, DepNodeIndex)>; @@ -156,7 +156,7 @@ impl<'tcx, K, V> Default for ArenaCache<'tcx, K, V> { } } -impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V> { +impl<'tcx, K: Eq + Hash, V: 'tcx> QueryStorage for ArenaCache<'tcx, K, V> { type Value = V; type Stored = &'tcx V; @@ -171,7 +171,6 @@ impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> where K: Eq + Hash + Clone + Debug, - V: Debug, { type Key = K; type Sharded = FxHashMap<K, &'tcx (V, DepNodeIndex)>; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 36532135f016d..d17af6120c7b8 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -20,7 +20,6 @@ use rustc_errors::{Diagnostic, FatalError}; use rustc_span::source_map::DUMMY_SP; use rustc_span::Span; use std::collections::hash_map::Entry; -use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::mem; use std::num::NonZeroU32; @@ -479,7 +478,7 @@ where result } -fn load_from_disk_and_cache_in_memory<CTX, K, V: Debug>( +fn load_from_disk_and_cache_in_memory<CTX, K, V>( tcx: CTX, key: K, prev_dep_node_index: SerializedDepNodeIndex, @@ -540,7 +539,7 @@ where #[inline(never)] #[cold] -fn incremental_verify_ich<CTX, K, V: Debug>( +fn incremental_verify_ich<CTX, K, V>( tcx: CTX, result: &V, dep_node: &DepNode<CTX::DepKind>, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index eaeb28388d4f0..fff14747e5729 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2266,12 +2266,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { visit::walk_expr(self, expr); } - ExprKind::Break(None, Some(ref e)) => { - // We use this instead of `visit::walk_expr` to keep the parent expr around for - // better diagnostics. - self.resolve_expr(e, Some(&expr)); - } - ExprKind::Let(ref pat, ref scrutinee) => { self.visit_expr(scrutinee); self.resolve_pattern_top(pat, PatternSource::Let); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index bed7a350ea86d..3945afb4724a8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -545,23 +545,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if let Some(err_code) = &err.code { if err_code == &rustc_errors::error_code!(E0425) { for label_rib in &self.label_ribs { - for (label_ident, node_id) in &label_rib.bindings { + for (label_ident, _) in &label_rib.bindings { if format!("'{}", ident) == label_ident.to_string() { - err.span_label(label_ident.span, "a label with a similar name exists"); - if let PathSource::Expr(Some(Expr { - kind: ExprKind::Break(None, Some(_)), - .. - })) = source - { - err.span_suggestion( - span, - "use the similarly named label", - label_ident.name.to_string(), - Applicability::MaybeIncorrect, - ); - // Do not lint against unused label when we suggest them. - self.diagnostic_metadata.unused_labels.remove(node_id); - } + let msg = "a label with a similar name exists"; + // FIXME: consider only emitting this suggestion if a label would be valid here + // which is pretty much only the case for `break` expressions. + err.span_suggestion( + span, + &msg, + label_ident.name.to_string(), + Applicability::MaybeIncorrect, + ); } } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 95ac2a31dd321..64cc113dffe7e 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1173,7 +1173,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { } fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> { - if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None } + if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None } } fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2b4a1d9e3fa0a..d293899dc0c6f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1465,14 +1465,16 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { - self.session.time("resolve_crate", || { - self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports()); - self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); - self.session.time("late_resolve_crate", || self.late_resolve_crate(krate)); - self.session.time("resolve_check_unused", || self.check_unused(krate)); - self.session.time("resolve_report_errors", || self.report_errors(krate)); - self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate)); - }); + let _prof_timer = self.session.prof.generic_activity("resolve_crate"); + + ImportResolver { r: self }.finalize_imports(); + self.finalize_macro_resolutions(); + + self.late_resolve_crate(krate); + + self.check_unused(krate); + self.report_errors(krate); + self.crate_loader.postprocess(krate); } pub fn traits_in_scope( diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 6e269e9e1264c..49833601c9e91 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -361,7 +361,7 @@ impl Default for TrimmedDefPaths { /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break /// dependency tracking for command-line arguments. -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash)] pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>); impl_stable_hash_via_hash!(OutputTypes); @@ -552,7 +552,7 @@ impl Input { } } -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash)] pub struct OutputFilenames { pub out_directory: PathBuf, filestem: String, diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 9f265f37f35f6..1fb5642912f43 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -27,18 +27,14 @@ use crate::edition::Edition; use crate::symbol::{kw, sym, Symbol}; use crate::SESSION_GLOBALS; -use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP}; +use crate::{Span, DUMMY_SP}; use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; -use std::hash::Hash; -use std::thread::LocalKey; use tracing::*; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". @@ -84,12 +80,7 @@ pub enum Transparency { impl ExpnId { pub fn fresh(expn_data: Option<ExpnData>) -> Self { - let has_data = expn_data.is_some(); - let expn_id = HygieneData::with(|data| data.fresh_expn(expn_data)); - if has_data { - update_disambiguator(expn_id); - } - expn_id + HygieneData::with(|data| data.fresh_expn(expn_data)) } /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. @@ -120,8 +111,7 @@ impl ExpnId { assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); expn_data.orig_id.replace(self.as_u32()).expect_none("orig_id should be None"); *old_expn_data = Some(expn_data); - }); - update_disambiguator(self) + }) } pub fn is_descendant_of(self, ancestor: ExpnId) -> bool { @@ -162,12 +152,6 @@ pub struct HygieneData { expn_data: Vec<Option<ExpnData>>, syntax_context_data: Vec<SyntaxContextData>, syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, - /// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value. - /// This is used by `update_disambiguator` to keep track of which `ExpnData`s - /// would have collisions without a disambiguator. - /// The keys of this map are always computed with `ExpnData.disambiguator` - /// set to 0. - expn_data_disambiguators: FxHashMap<Fingerprint, u32>, } impl HygieneData { @@ -191,7 +175,6 @@ impl HygieneData { dollar_crate_name: kw::DollarCrate, }], syntax_context_map: FxHashMap::default(), - expn_data_disambiguators: FxHashMap::default(), } } @@ -666,8 +649,8 @@ impl Span { expn_data: ExpnData, transparency: Transparency, ) -> Span { - let expn_id = ExpnId::fresh(Some(expn_data)); HygieneData::with(|data| { + let expn_id = data.fresh_expn(Some(expn_data)); self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency)) }) } @@ -743,23 +726,10 @@ pub struct ExpnData { // be considered equivalent. #[stable_hasher(ignore)] orig_id: Option<u32>, - - /// Used to force two `ExpnData`s to have different `Fingerprint`s. - /// Due to macro expansion, it's possible to end up with two `ExpnId`s - /// that have identical `ExpnData`s. This violates the constract of `HashStable` - /// - the two `ExpnId`s are not equal, but their `Fingerprint`s are equal - /// (since the numerical `ExpnId` value is not considered by the `HashStable` - /// implementation). - /// - /// The `disambiguator` field is set by `update_disambiguator` when two distinct - /// `ExpnId`s would end up with the same `Fingerprint`. Since `ExpnData` includes - /// a `krate` field, this value only needs to be unique within a single crate. - disambiguator: u32, } -// These would require special handling of `orig_id`. +// This would require special handling of `orig_id` and `parent` impl !PartialEq for ExpnData {} -impl !Hash for ExpnData {} impl ExpnData { pub fn new( @@ -785,7 +755,6 @@ impl ExpnData { macro_def_id, krate: LOCAL_CRATE, orig_id: None, - disambiguator: 0, } } @@ -808,7 +777,6 @@ impl ExpnData { macro_def_id, krate: LOCAL_CRATE, orig_id: None, - disambiguator: 0, } } @@ -1308,118 +1276,3 @@ impl<D: Decoder> Decodable<D> for SyntaxContext { panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>()); } } - -/// Updates the `disambiguator` field of the corresponding `ExpnData` -/// such that the `Fingerprint` of the `ExpnData` does not collide with -/// any other `ExpnIds`. -/// -/// This method is called only when an `ExpnData` is first associated -/// with an `ExpnId` (when the `ExpnId` is initially constructed, or via -/// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized -/// from another crate's metadata - since `ExpnData` includes a `krate` field, -/// collisions are only possible between `ExpnId`s within the same crate. -fn update_disambiguator(expn_id: ExpnId) { - /// A `HashStableContext` which hashes the raw id values for `DefId` - /// and `CrateNum`, rather than using their computed stable hash. - /// - /// This allows us to use the `HashStable` implementation on `ExpnId` - /// early on in compilation, before we've constructed a `TyCtxt`. - /// The `Fingerprint`s created by this context are not 'stable', since - /// the raw `CrateNum` and `DefId` values for an item may change between - /// sessions due to unrelated changes (e.g. adding/removing an different item). - /// - /// However, this is fine for our purposes - we only need to detect - /// when two `ExpnData`s have the same `Fingerprint`. Since the hashes produced - /// by this context still obey the properties of `HashStable`, we have - /// that - /// `hash_stable(expn1, DummyHashStableContext) == hash_stable(expn2, DummyHashStableContext)` - /// iff `hash_stable(expn1, StableHashingContext) == hash_stable(expn2, StableHasingContext)`. - /// - /// This is sufficient for determining when we need to update the disambiguator. - struct DummyHashStableContext<'a> { - caching_source_map: CachingSourceMapView<'a>, - } - - impl<'a> crate::HashStableContext for DummyHashStableContext<'a> { - fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) { - def_id.krate.as_u32().hash_stable(self, hasher); - def_id.index.as_u32().hash_stable(self, hasher); - } - - fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> { - // This cache is only used by `DummyHashStableContext`, - // so we won't pollute the cache values of the normal `StableHashingContext` - thread_local! { - static CACHE: ExpnIdCache = Default::default(); - } - - &CACHE - } - - fn hash_crate_num(&mut self, krate: CrateNum, hasher: &mut StableHasher) { - krate.as_u32().hash_stable(self, hasher); - } - fn hash_spans(&self) -> bool { - true - } - fn byte_pos_to_line_and_col( - &mut self, - byte: BytePos, - ) -> Option<(Lrc<SourceFile>, usize, BytePos)> { - self.caching_source_map.byte_pos_to_line_and_col(byte) - } - fn span_data_to_lines_and_cols( - &mut self, - span: &crate::SpanData, - ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> { - self.caching_source_map.span_data_to_lines_and_cols(span) - } - } - - let source_map = SESSION_GLOBALS - .with(|session_globals| session_globals.source_map.borrow().as_ref().unwrap().clone()); - - let mut ctx = - DummyHashStableContext { caching_source_map: CachingSourceMapView::new(&source_map) }; - - let mut hasher = StableHasher::new(); - - let expn_data = expn_id.expn_data(); - // This disambiguator should not have been set yet. - assert_eq!( - expn_data.disambiguator, 0, - "Already set disambiguator for ExpnData: {:?}", - expn_data - ); - expn_data.hash_stable(&mut ctx, &mut hasher); - let first_hash = hasher.finish(); - - let modified = HygieneData::with(|data| { - // If this is the first ExpnData with a given hash, then keep our - // disambiguator at 0 (the default u32 value) - let disambig = data.expn_data_disambiguators.entry(first_hash).or_default(); - data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = *disambig; - *disambig += 1; - - *disambig != 1 - }); - - if modified { - info!("Set disambiguator for {:?} (hash {:?})", expn_id, first_hash); - info!("expn_data = {:?}", expn_id.expn_data()); - - // Verify that the new disambiguator makes the hash unique - #[cfg(debug_assertions)] - { - hasher = StableHasher::new(); - expn_id.expn_data().hash_stable(&mut ctx, &mut hasher); - let new_hash: Fingerprint = hasher.finish(); - - HygieneData::with(|data| { - data.expn_data_disambiguators - .get(&new_hash) - .expect_none("Hash collision after disambiguator update!"); - }); - }; - } -} diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f3d876a5770a8..50cb15554864f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -65,7 +65,6 @@ use std::hash::Hash; use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::thread::LocalKey; use md5::Md5; use sha1::Digest; @@ -1866,11 +1865,6 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize { /// instead of implementing everything in rustc_middle. pub trait HashStableContext { fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher); - /// Obtains a cache for storing the `Fingerprint` of an `ExpnId`. - /// This method allows us to have multiple `HashStableContext` implementations - /// that hash things in a different way, without the results of one polluting - /// the cache of the other. - fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>; fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher); fn hash_spans(&self) -> bool; fn byte_pos_to_line_and_col( @@ -1967,10 +1961,15 @@ impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext { } } -pub type ExpnIdCache = RefCell<Vec<Option<Fingerprint>>>; - impl<CTX: HashStableContext> HashStable<CTX> for ExpnId { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + // Since the same expansion context is usually referenced many + // times, we cache a stable hash of it and hash that instead of + // recursing every time. + thread_local! { + static CACHE: RefCell<Vec<Option<Fingerprint>>> = Default::default(); + } + const TAG_ROOT: u8 = 0; const TAG_NOT_ROOT: u8 = 1; @@ -1979,11 +1978,8 @@ impl<CTX: HashStableContext> HashStable<CTX> for ExpnId { return; } - // Since the same expansion context is usually referenced many - // times, we cache a stable hash of it and hash that instead of - // recursing every time. let index = self.as_u32() as usize; - let res = CTX::expn_id_cache().with(|cache| cache.borrow().get(index).copied().flatten()); + let res = CACHE.with(|cache| cache.borrow().get(index).copied().flatten()); if let Some(res) = res { res.hash_stable(ctx, hasher); @@ -1995,7 +1991,7 @@ impl<CTX: HashStableContext> HashStable<CTX> for ExpnId { self.expn_data().hash_stable(ctx, &mut sub_hasher); let sub_hash: Fingerprint = sub_hasher.finish(); - CTX::expn_id_cache().with(|cache| { + CACHE.with(|cache| { let mut cache = cache.borrow_mut(); if cache.len() < new_len { cache.resize(new_len, None); diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 2cbd52bf3e9a7..a9e595d11e759 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -27,16 +27,10 @@ mod x86_win64; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum PassMode { /// Ignore the argument. - /// - /// The argument is either uninhabited or a ZST. Ignore, /// Pass the argument directly. - /// - /// The argument has a layout abi of `Scalar` or `Vector`. Direct(ArgAttributes), /// Pass a pair's elements directly in two arguments. - /// - /// The argument has a layout abi of `ScalarPair`. Pair(ArgAttributes, ArgAttributes), /// Pass the argument after casting it, to either /// a single uniform or a pair of registers. @@ -440,49 +434,28 @@ pub struct ArgAbi<'a, Ty> { } impl<'a, Ty> ArgAbi<'a, Ty> { - pub fn new( - cx: &impl HasDataLayout, - layout: TyAndLayout<'a, Ty>, - scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, &abi::Scalar, Size) -> ArgAttributes, - ) -> Self { - let mode = match &layout.abi { - Abi::Uninhabited => PassMode::Ignore, - Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)), - Abi::ScalarPair(a, b) => PassMode::Pair( - scalar_attrs(&layout, a, Size::ZERO), - scalar_attrs(&layout, b, a.value.size(cx).align_to(b.value.align(cx).abi)), - ), - Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), - Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout), - }; - ArgAbi { layout, pad: None, mode } + pub fn new(layout: TyAndLayout<'a, Ty>) -> Self { + ArgAbi { layout, pad: None, mode: PassMode::Direct(ArgAttributes::new()) } } - fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode { + pub fn make_indirect(&mut self) { + assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); + + // Start with fresh attributes for the pointer. let mut attrs = ArgAttributes::new(); // For non-immediate arguments the callee gets its own copy of // the value on the stack, so there are no aliases. It's also // program-invisible so can't possibly capture attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull); - attrs.pointee_size = layout.size; + attrs.pointee_size = self.layout.size; // FIXME(eddyb) We should be doing this, but at least on // i686-pc-windows-msvc, it results in wrong stack offsets. - // attrs.pointee_align = Some(layout.align.abi); - - let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new()); + // attrs.pointee_align = Some(self.layout.align.abi); - PassMode::Indirect { attrs, extra_attrs, on_stack: false } - } - - pub fn make_indirect(&mut self) { - match self.mode { - PassMode::Direct(_) | PassMode::Pair(_, _) => {} - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return, - _ => panic!("Tried to make {:?} indirect", self.mode), - } + let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new()); - self.mode = Self::indirect_pass_mode(&self.layout); + self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false }; } pub fn make_indirect_byval(&mut self) { @@ -513,6 +486,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { + assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); self.mode = PassMode::Cast(target.into()); } diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs index cfaf020175b7f..302306ee57990 100644 --- a/compiler/rustc_target/src/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -1,5 +1,5 @@ use super::apple_sdk_base::{opts, Arch}; -use crate::spec::{StackProbeType, Target, TargetOptions}; +use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let base = opts("ios", Arch::I386); @@ -10,10 +10,6 @@ pub fn target() -> Target { f64:32:64-f80:128-n8:16:32-S128" .to_string(), arch: "x86".to_string(), - options: TargetOptions { - max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, - ..base - }, + options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base }, } } diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 2d3310c7582ef..0ab40340928cc 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); @@ -6,7 +6,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; base.eliminate_frame_pointer = false; // Clang automatically chooses a more specific target based on diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs index 18cd8847abd39..52059b930d134 100644 --- a/compiler/rustc_target/src/spec/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/i686_linux_android.rs @@ -1,4 +1,4 @@ -use crate::spec::{StackProbeType, Target}; +use crate::spec::Target; // See https://developer.android.com/ndk/guides/abis.html#x86 // for target ABI requirements. @@ -11,7 +11,7 @@ pub fn target() -> Target { // http://developer.android.com/ndk/guides/abis.html#x86 base.cpu = "pentiumpro".to_string(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string(); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-linux-android".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index fc425babb6948..fc1c8607d654c 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); @@ -7,7 +7,7 @@ pub fn target() -> Target { let pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); pre_link_args.push("-m32".to_string()); pre_link_args.push("-Wl,-znotext".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-unknown-freebsd".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index 5fba4e3f14a25..22c8ba5475315 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-unknown-haiku".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index fe1e6a4299dab..083c115d084b4 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-unknown-linux-gnu".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index 623fd1b9ae801..1673b2a180245 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); @@ -6,7 +6,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index c4d11bfb13ece..c22139b5875d6 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-unknown-netbsdelf".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index fdaaf6c741e89..87642efdee8f7 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::openbsd_base::opts(); @@ -6,7 +6,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-unknown-openbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index ec8a2493b4e42..c0825358cabbc 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "i686-unknown-linux-gnu".to_string(), diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs index 5220156895367..a5fc1649e7ffd 100644 --- a/compiler/rustc_target/src/spec/linux_kernel_base.rs +++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs @@ -1,6 +1,4 @@ -use crate::spec::{ - LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions, -}; +use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { let mut pre_link_args = LinkArgs::new(); @@ -13,7 +11,7 @@ pub fn opts() -> TargetOptions { env: "gnu".to_string(), disable_redzone: true, panic_strategy: PanicStrategy::Abort, - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, + stack_probes: true, eliminate_frame_pointer: false, linker_is_gnu: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 90d35efaa25bd..d283c2548864f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -40,7 +40,6 @@ use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_serialize::json::{Json, ToJson}; use rustc_span::symbol::{sym, Symbol}; use std::collections::BTreeMap; -use std::convert::TryFrom; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -480,83 +479,6 @@ macro_rules! supported_targets { }; } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum StackProbeType { - /// Don't emit any stack probes. - None, - /// It is harmless to use this option even on targets that do not have backend support for - /// stack probes as the failure mode is the same as if no stack-probe option was specified in - /// the first place. - Inline, - /// Call `__rust_probestack` whenever stack needs to be probed. - Call, - /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline` - /// and call `__rust_probestack` otherwise. - InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) }, -} - -impl StackProbeType { - fn from_json(json: &Json) -> Result<Self, String> { - let object = json.as_object().ok_or_else(|| "expected a JSON object")?; - let kind = object - .get("kind") - .and_then(|o| o.as_string()) - .ok_or_else(|| "expected `kind` to be a string")?; - match kind { - "none" => Ok(StackProbeType::None), - "inline" => Ok(StackProbeType::Inline), - "call" => Ok(StackProbeType::Call), - "inline-or-call" => { - let min_version = object - .get("min-llvm-version-for-inline") - .and_then(|o| o.as_array()) - .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?; - let mut iter = min_version.into_iter().map(|v| { - let int = v.as_u64().ok_or_else( - || "expected `min-llvm-version-for-inline` values to be integers", - )?; - u32::try_from(int) - .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32") - }); - let min_llvm_version_for_inline = ( - iter.next().unwrap_or(Ok(11))?, - iter.next().unwrap_or(Ok(0))?, - iter.next().unwrap_or(Ok(0))?, - ); - Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline }) - } - _ => Err(String::from( - "`kind` expected to be one of `inline-or-none`, `call` or `inline-or-call`", - )), - } - } -} - -impl ToJson for StackProbeType { - fn to_json(&self) -> Json { - Json::Object(match self { - StackProbeType::None => { - vec![(String::from("kind"), "none".to_json())].into_iter().collect() - } - StackProbeType::Inline => { - vec![(String::from("kind"), "inline".to_json())].into_iter().collect() - } - StackProbeType::Call => { - vec![(String::from("kind"), "call".to_json())].into_iter().collect() - } - StackProbeType::InlineOrCall { min_llvm_version_for_inline } => vec![ - (String::from("kind"), "inline-or-call".to_json()), - ( - String::from("min-llvm-version-for-inline"), - min_llvm_version_for_inline.to_json(), - ), - ] - .into_iter() - .collect(), - }) - } -} - supported_targets! { ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu), ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32), @@ -1004,8 +926,8 @@ pub struct TargetOptions { /// Whether or not crt-static is respected by the compiler (or is a no-op). pub crt_static_respected: bool, - /// The implementation of stack probes to use. - pub stack_probes: StackProbeType, + /// Whether or not stack probes (__rust_probestack) are enabled + pub stack_probes: bool, /// The minimum alignment for global symbols. pub min_global_align: Option<u64>, @@ -1163,7 +1085,7 @@ impl Default for TargetOptions { crt_static_allows_dylibs: false, crt_static_default: false, crt_static_respected: false, - stack_probes: StackProbeType::None, + stack_probes: false, min_global_align: None, default_codegen_units: None, trap_unreachable: true, @@ -1439,18 +1361,6 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); - ($key_name:ident, StackProbeType) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.find(&name[..]).and_then(|o| match StackProbeType::from_json(o) { - Ok(v) => { - base.$key_name = v; - Some(Ok(())) - }, - Err(s) => Some(Err( - format!("`{:?}` is not a valid value for `{}`: {}", o, name, s) - )), - }).unwrap_or(Ok(())) - } ); ($key_name:ident, crt_objects_fallback) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { @@ -1606,7 +1516,7 @@ impl Target { key!(crt_static_allows_dylibs, bool); key!(crt_static_default, bool); key!(crt_static_respected, bool); - key!(stack_probes, StackProbeType)?; + key!(stack_probes, bool); key!(min_global_align, Option<u64>); key!(default_codegen_units, Option<u64>); key!(trap_unreachable, bool); diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs index b9ff16bd19ff4..322b6f530e9fd 100644 --- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs +++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs @@ -9,7 +9,7 @@ // the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all // code runs in the same environment, no process separation is supported. -use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, TargetOptions}; +use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions}; pub fn opts() -> TargetOptions { let mut base = super::msvc_base::opts(); @@ -43,9 +43,7 @@ pub fn opts() -> TargetOptions { exe_suffix: ".efi".to_string(), allows_weak_linkage: false, panic_strategy: PanicStrategy::Abort, - // LLVM does not emit inline assembly because the LLVM target does not get considered as… - // "Windows". - stack_probes: StackProbeType::Call, + stack_probes: true, singlethread: true, linker: Some("rust-lld".to_string()), ..base diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index 8c40baccda84a..edb33fe6e2b13 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); @@ -10,7 +10,7 @@ pub fn target() -> Target { vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()], ); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; // Clang automatically chooses a more specific target based on // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs index 6feeeac451b27..c9c7eeb723198 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -1,5 +1,5 @@ use super::apple_sdk_base::{opts, Arch}; -use crate::spec::{StackProbeType, Target, TargetOptions}; +use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let base = opts("ios", Arch::X86_64); @@ -9,10 +9,6 @@ pub fn target() -> Target { data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), arch: "x86_64".to_string(), - options: TargetOptions { - max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, - ..base - }, + options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base }, } } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index a6e066213e7f9..6b360e5495be7 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -1,5 +1,5 @@ use super::apple_sdk_base::{opts, Arch}; -use crate::spec::{StackProbeType, Target, TargetOptions}; +use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let base = opts("ios", Arch::X86_64_macabi); @@ -9,10 +9,6 @@ pub fn target() -> Target { data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), arch: "x86_64".to_string(), - options: TargetOptions { - max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, - ..base - }, + options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base }, } } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index f8c47168da87f..5b2a62a23fd8c 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -1,5 +1,5 @@ use super::apple_sdk_base::{opts, Arch}; -use crate::spec::{StackProbeType, Target, TargetOptions}; +use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let base = opts("tvos", Arch::X86_64); @@ -8,10 +8,6 @@ pub fn target() -> Target { pointer_width: 64, data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(), arch: "x86_64".to_string(), - options: TargetOptions { - max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, - ..base - }, + options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base }, } } diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs index a39e7f8c34105..6c049c2635c79 100644 --- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -1,10 +1,10 @@ -use crate::spec::{StackProbeType, Target}; +use crate::spec::Target; pub fn target() -> Target { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-fuchsia".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index d436242e62b30..27327160178a0 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::android_base::opts(); @@ -7,7 +7,7 @@ pub fn target() -> Target { base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-linux-android".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs index d84a63562c70a..095c6f15c77ad 100644 --- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); @@ -12,7 +12,7 @@ pub fn target() -> Target { base.has_rpath = false; base.position_independent_executables = false; base.disable_redzone = true; - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-rumprun-netbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index 0fe462ec83cbc..6ccf78402e149 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-pc-solaris".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index d86b0d67acd15..30aa2909873a3 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index c7d3b3feed50e..ee904d762421f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-freebsd".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index 963d4fdb12f2d..ea7e068e516a9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; // This option is required to build executables on Haiku x86_64 base.position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index 31164f8408dcb..4005aaf58b133 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -1,11 +1,11 @@ -use crate::spec::{StackProbeType, Target}; +use crate::spec::Target; pub fn target() -> Target { let mut base = super::hermit_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.features = "+rdrnd,+rdseed".to_string(); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-hermit".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs index 9fcfe4e6c14bf..b72d529363afb 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs @@ -1,4 +1,4 @@ -use crate::spec::{StackProbeType, Target}; +use crate::spec::Target; pub fn target() -> Target { let mut base = super::hermit_kernel_base::opts(); @@ -7,7 +7,7 @@ pub fn target() -> Target { base.features = "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" .to_string(); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-hermit".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 99906764dfc6e..f127dd49bc4b7 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 4b2bce37470cc..0cae57528483f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; base.has_elf_tls = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index fa9fdf5aa0992..3669c10981e19 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; base.static_position_independent_executables = true; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 6d19dec00b411..7e91a6ddbe296 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-netbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index ac5939bcb3c43..0fe01f09c2e85 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-openbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index ddabe95ab8394..cdd445b2614b2 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::redox_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; Target { llvm_target: "x86_64-unknown-redox".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 1b35e813fcd8f..163af6fd8e175 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -1,11 +1,11 @@ -use crate::spec::{LinkerFlavor, StackProbeType, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = true; base.disable_redzone = true; Target { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 77aa441340912..bd1d9cc895fb0 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -218,6 +218,10 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssociatedItems<'_> { ty::AssociatedItems::new(items) } +fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { + tcx.hir().span_if_local(def_id).unwrap() +} + fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { tcx.hir().get_if_local(def_id).and_then(|node| node.ident()).map(|ident| ident.span) } @@ -491,6 +495,7 @@ pub fn provide(providers: &mut ty::query::Providers) { associated_item_def_ids, associated_items, adt_sized_constraint, + def_span, def_ident_span, param_env, param_env_reveal_all_normalized, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 47361092a5c50..8e339eb26b26c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -66,7 +66,7 @@ pub(super) fn check_fn<'a, 'tcx>( // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); - fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id)); + *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); let tcx = fcx.tcx; let sess = tcx.sess; @@ -846,13 +846,21 @@ pub(super) fn check_specialization_validity<'tcx>( Ok(ancestors) => ancestors, Err(_) => return, }; - let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| { - if parent.is_from_trait() { - None - } else { - Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) - } - }); + let mut ancestor_impls = ancestors + .skip(1) + .filter_map(|parent| { + if parent.is_from_trait() { + None + } else { + Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) + } + }) + .peekable(); + + if ancestor_impls.peek().is_none() { + // No parent, nothing to specialize. + return; + } let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { match parent_item { @@ -894,6 +902,8 @@ pub(super) fn check_impl_items_against_trait<'tcx>( impl_trait_ref: ty::TraitRef<'tcx>, impl_item_refs: &[hir::ImplItemRef<'_>], ) { + let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); + // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` // isn't populated for such impls. @@ -921,75 +931,111 @@ pub(super) fn check_impl_items_against_trait<'tcx>( // Locate trait definition and items let trait_def = tcx.trait_def(impl_trait_ref.def_id); - let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); - let associated_items = tcx.associated_items(impl_trait_ref.def_id); + + let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); // Check existing impl methods to see if they are both present in trait // and compatible with trait signature - for impl_item in impl_items { + for impl_item in impl_items() { + let namespace = impl_item.kind.namespace(); let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); - - let mut items = - associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id); - - let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() { - let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) { - (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true, - (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true, - (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true, - _ => false, - }; - - // If we don't have a compatible item, we'll use the first one whose name matches - // to report an error. - let mut compatible_kind = is_compatible(&ty_trait_item); - let mut trait_item = ty_trait_item; - - if !compatible_kind { - if let Some(ty_trait_item) = items.find(is_compatible) { - compatible_kind = true; - trait_item = ty_trait_item; - } - } - - (compatible_kind, trait_item) - } else { - continue; - }; - - if compatible_kind { + let ty_trait_item = tcx + .associated_items(impl_trait_ref.def_id) + .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) + .or_else(|| { + // Not compatible, but needed for the error message + tcx.associated_items(impl_trait_ref.def_id) + .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) + .next() + }); + + // Check that impl definition matches trait definition + if let Some(ty_trait_item) = ty_trait_item { match impl_item.kind { hir::ImplItemKind::Const(..) => { // Find associated const definition. - compare_const_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - ); + if ty_trait_item.kind == ty::AssocKind::Const { + compare_const_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0323, + "item `{}` is an associated const, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + // We can only get the spans from local trait definition + // Same for E0324 and E0325 + if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } } hir::ImplItemKind::Fn(..) => { let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - compare_impl_method( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); + if ty_trait_item.kind == ty::AssocKind::Fn { + compare_impl_method( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0324, + "item `{}` is an associated method, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } } hir::ImplItemKind::TyAlias(_) => { let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - compare_ty_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); + if ty_trait_item.kind == ty::AssocKind::Type { + compare_ty_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0325, + "item `{}` is an associated type, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } } } @@ -1000,22 +1046,12 @@ pub(super) fn check_impl_items_against_trait<'tcx>( impl_id.to_def_id(), impl_item, ); - } else { - report_mismatch_error( - tcx, - ty_trait_item.def_id, - impl_trait_ref, - impl_item, - &ty_impl_item, - ); } } + // Check for missing items from trait + let mut missing_items = Vec::new(); if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); - - // Check for missing items from trait - let mut missing_items = Vec::new(); for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { let is_implemented = ancestors .leaf_def(tcx, trait_item.ident, trait_item.kind) @@ -1028,63 +1064,11 @@ pub(super) fn check_impl_items_against_trait<'tcx>( } } } - - if !missing_items.is_empty() { - missing_items_err(tcx, impl_span, &missing_items, full_impl_span); - } } -} - -#[inline(never)] -#[cold] -fn report_mismatch_error<'tcx>( - tcx: TyCtxt<'tcx>, - trait_item_def_id: DefId, - impl_trait_ref: ty::TraitRef<'tcx>, - impl_item: &hir::ImplItem<'_>, - ty_impl_item: &ty::AssocItem, -) { - let mut err = match impl_item.kind { - hir::ImplItemKind::Const(..) => { - // Find associated const definition. - struct_span_err!( - tcx.sess, - impl_item.span, - E0323, - "item `{}` is an associated const, which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ) - } - - hir::ImplItemKind::Fn(..) => { - struct_span_err!( - tcx.sess, - impl_item.span, - E0324, - "item `{}` is an associated method, which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ) - } - hir::ImplItemKind::TyAlias(_) => { - struct_span_err!( - tcx.sess, - impl_item.span, - E0325, - "item `{}` is an associated type, which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ) - } - }; - - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) { - err.span_label(trait_span, "item in trait"); + if !missing_items.is_empty() { + missing_items_err(tcx, impl_span, &missing_items, full_impl_span); } - err.emit(); } /// Checks whether a type can be represented in memory. In particular, it diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index b2395b7bb2502..34ad8ec08984e 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1472,22 +1472,22 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn_output = Some(&fn_decl.output); // `impl Trait` return type } } - if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) { - self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output); + if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) { + self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output); } - if let Some(sp) = fcx.ret_coercion_span.get() { + if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() { // If the closure has an explicit return type annotation, // then a type error may occur at the first return expression we // see in the closure (if it conflicts with the declared // return type). Skip adding a note in this case, since it // would be incorrect. - if !err.span.primary_spans().iter().any(|&span| span == sp) { + if !err.span.primary_spans().iter().any(|span| span == sp) { let hir = fcx.tcx.hir(); let body_owner = hir.body_owned_by(hir.enclosing_body_owner(fcx.body_id)); if fcx.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) { err.span_note( - sp, + *sp, &format!( "return type inferred to be `{}` here", fcx.resolve_vars_if_possible(expected) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e37b4ff742bc6..8aa6c6d924a53 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -266,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), - ExprKind::Loop(ref body, _, source, _) => { + ExprKind::Loop(ref body, _, source) => { self.check_expr_loop(body, source, expected, expr) } ExprKind::Match(ref discrim, ref arms, match_src) => { @@ -680,14 +680,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.ret_coercion.is_none() { self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span }); } else if let Some(ref e) = expr_opt { - if self.ret_coercion_span.get().is_none() { - self.ret_coercion_span.set(Some(e.span)); + if self.ret_coercion_span.borrow().is_none() { + *self.ret_coercion_span.borrow_mut() = Some(e.span); } self.check_return_expr(e); } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); - if self.ret_coercion_span.get().is_none() { - self.ret_coercion_span.set(Some(expr.span)); + if self.ret_coercion_span.borrow().is_none() { + *self.ret_coercion_span.borrow_mut() = Some(expr.span); } let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index fb6f9c03352b4..6df9e3ab7dbe8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -23,6 +23,7 @@ use rustc_span::{self, MultiSpan, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression}; use crate::structured_errors::StructuredDiagnostic; +use std::mem::replace; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -588,7 +589,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk: &'tcx hir::Block<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let prev = self.ps.replace(self.ps.get().recurse(blk)); + let prev = { + let mut fcx_ps = self.ps.borrow_mut(); + let unsafety_state = fcx_ps.recurse(blk); + replace(&mut *fcx_ps, unsafety_state) + }; // In some cases, blocks have just one exit, but other blocks // can be targeted by multiple breaks. This can happen both @@ -704,7 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_ty(blk.hir_id, ty); - self.ps.set(prev); + *self.ps.borrow_mut() = prev; ty } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index e9223f700dcc7..6d09043bd5033 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -66,11 +66,11 @@ pub struct FnCtxt<'a, 'tcx> { pub(super) in_tail_expr: bool, /// First span of a return site that we find. Used in error messages. - pub(super) ret_coercion_span: Cell<Option<Span>>, + pub(super) ret_coercion_span: RefCell<Option<Span>>, pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - pub(super) ps: Cell<UnsafetyState>, + pub(super) ps: RefCell<UnsafetyState>, /// Whether the last checked node generates a divergence (e.g., /// `return` will set this to `Always`). In general, when entering @@ -127,9 +127,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_coercion_impl_trait: None, ret_type_span: None, in_tail_expr: false, - ret_coercion_span: Cell::new(None), + ret_coercion_span: RefCell::new(None), resume_yield_tys: None, - ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), + ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), diverges: Cell::new(Diverges::Maybe), has_errors: Cell::new(false), enclosing_breakables: RefCell::new(EnclosingBreakables { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index c8c6fa12fae08..52276ed4beeaa 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -184,14 +184,14 @@ impl UnsafetyState { UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true } } - pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState { + pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState { use hir::BlockCheckMode; match self.unsafety { // If this unsafe, then if the outer function was already marked as // unsafe we shouldn't attribute the unsafe'ness to the block. This // way the block can be warned about instead of ignoring this // extraneous block (functions are never warned about). - hir::Unsafety::Unsafe if self.from_fn => self, + hir::Unsafety::Unsafe if self.from_fn => *self, unsafety => { let (unsafety, def, count) = match blk.rules { diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 24364c6954e49..01519e4c8f7c4 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -289,7 +289,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err => {} - hir::ExprKind::Loop(ref blk, ..) => { + hir::ExprKind::Loop(ref blk, _, _) => { self.walk_block(blk); } diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index 339eb5f9afc74..a8fbdfb7c6514 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -207,13 +207,27 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - #[instrument(skip(self, current))] + fn add_constraints_from_trait_ref( + &mut self, + current: &CurrentItem, + trait_ref: ty::TraitRef<'tcx>, + variance: VarianceTermPtr<'a>, + ) { + debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}", trait_ref, variance); + self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance); + } + fn add_constraints_from_invariant_substs( &mut self, current: &CurrentItem, substs: SubstsRef<'tcx>, variance: VarianceTermPtr<'a>, ) { + debug!( + "add_constraints_from_invariant_substs: substs={:?} variance={:?}", + substs, variance + ); + // Trait are always invariant so we can take advantage of that. let variance_i = self.invariant(variance); @@ -286,7 +300,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Projection(ref data) => { - self.add_constraints_from_invariant_substs(current, data.substs, variance); + let tcx = self.tcx(); + self.add_constraints_from_trait_ref(current, data.trait_ref(tcx), variance); } ty::Opaque(_, substs) => { diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index dacf6f8d83004..0aa52b35ced45 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -178,10 +178,8 @@ impl<T> Box<T> { /// ``` /// let five = Box::new(5); /// ``` - #[inline(always)] - #[doc(alias = "alloc")] - #[doc(alias = "malloc")] #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] pub fn new(x: T) -> Self { box x } @@ -228,9 +226,8 @@ impl<T> Box<T> { /// ``` /// /// [zeroed]: mem::MaybeUninit::zeroed - #[inline] - #[doc(alias = "calloc")] #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> { Self::new_zeroed_in(Global) } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 57fad4217b6c6..8ab3f58c1adba 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -238,12 +238,13 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> { /// such restrictions: /// - For each type parameter, we can only define a method either generically /// or for one particular type. For example, we cannot define a method like -/// `into_kv` generically for all `BorrowType`, or once for all types that -/// carry a lifetime, because we want it to return `&'a` references. +/// `key_at` generically for all `BorrowType`, because we want it to return +/// `&'a K` for most choices of `BorrowType`, but plain `K` for `Owned`. +/// We cannot define `key_at` once for all types that carry a lifetime. /// Therefore, we define it only for the least powerful type `Immut<'a>`. /// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`. /// Therefore, we have to explicitly call `reborrow` on a more powerfull -/// `NodeRef` in order to reach a method like `into_kv`. +/// `NodeRef` in order to reach a method like `key_at`. /// /// All methods on `NodeRef` that return some kind of reference, either: /// - Take `self` by value, and return the lifetime carried by `BorrowType`. @@ -343,6 +344,26 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { } } +impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> { + /// Exposes one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_at(self, idx: usize) -> &'a K { + debug_assert!(idx < self.len()); + unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() } + } + + /// Exposes one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn val_at(self, idx: usize) -> &'a V { + debug_assert!(idx < self.len()); + unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() } + } +} + impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { /// Finds the parent of the current node. Returns `Ok(handle)` if the current /// node actually has a parent, where `handle` points to the edge of the parent @@ -400,14 +421,6 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> { // SAFETY: there can be no mutable references into this tree borrowed as `Immut`. unsafe { &*ptr } } - - /// Borrows a view into the keys stored in the node. - pub fn keys(&self) -> &[K] { - let leaf = self.into_leaf(); - unsafe { - MaybeUninit::slice_assume_init_ref(leaf.keys.get_unchecked(..usize::from(leaf.len))) - } - } } impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> { @@ -974,11 +987,7 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Immut<'a>, K, V, NodeType>, marker::KV> { pub fn into_kv(self) -> (&'a K, &'a V) { - debug_assert!(self.idx < self.node.len()); - let leaf = self.node.into_leaf(); - let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() }; - let v = unsafe { leaf.vals.get_unchecked(self.idx).assume_init_ref() }; - (k, v) + (unsafe { self.node.key_at(self.idx) }, unsafe { self.node.val_at(self.idx) }) } } @@ -988,7 +997,6 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType> } pub fn into_val_mut(self) -> &'a mut V { - debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } @@ -1002,7 +1010,6 @@ impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, mar impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> { pub fn kv_mut(&mut self) -> (&mut K, &mut V) { - debug_assert!(self.idx < self.node.len()); // We cannot call separate key and value methods, because calling the second one // invalidates the reference returned by the first. unsafe { diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 11433cd845bee..48ce9f2bd89c8 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -29,7 +29,17 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> navigate::Position::Leaf(leaf) => { let depth = self.height(); let indent = " ".repeat(depth); - result += &format!("\n{}{:?}", indent, leaf.keys()); + result += &format!("\n{}", indent); + if leaf.len() == 0 { + result += "(empty node)"; + } else { + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); + } + } } navigate::Position::Internal(_) => {} navigate::Position::InternalKV(kv) => { diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index d8bebed758f1a..f62eae3f4d5a2 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -71,15 +71,18 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { Q: Ord, K: Borrow<Q>, { - let node = self.reborrow(); - let keys = node.keys(); - for (i, k) in keys.iter().enumerate() { + // This function is defined over all borrow types (immutable, mutable, owned). + // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return + // is an index -- not a reference. + let len = self.len(); + for i in 0..len { + let k = unsafe { self.reborrow().key_at(i) }; match key.cmp(k.borrow()) { Ordering::Greater => {} Ordering::Equal => return IndexResult::KV(i), Ordering::Less => return IndexResult::Edge(i), } } - IndexResult::Edge(keys.len()) + IndexResult::Edge(len) } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 6f9133e2811bf..5b61e8911a59a 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2646,13 +2646,9 @@ impl<A: Ord> Ord for VecDeque<A> { impl<A: Hash> Hash for VecDeque<A> { fn hash<H: Hasher>(&self, state: &mut H) { self.len().hash(state); - // It's not possible to use Hash::hash_slice on slices - // returned by as_slices method as their length can vary - // in otherwise identical deques. - // - // Hasher only guarantees equivalence for the exact same - // set of calls to its methods. - self.iter().for_each(|elem| elem.hash(state)); + let (a, b) = self.as_slices(); + Hash::hash_slice(a, state); + Hash::hash_slice(b, state); } } diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index 87e06fa394d38..27dc59ae64411 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -599,43 +599,3 @@ fn issue_53529() { assert_eq!(*a, 2); } } - -#[test] -fn issue_80303() { - use core::iter; - use core::num::Wrapping; - - // This is a valid, albeit rather bad hash function implementation. - struct SimpleHasher(Wrapping<u64>); - - impl Hasher for SimpleHasher { - fn finish(&self) -> u64 { - self.0.0 - } - - fn write(&mut self, bytes: &[u8]) { - // This particular implementation hashes value 24 in addition to bytes. - // Such an implementation is valid as Hasher only guarantees equivalence - // for the exact same set of calls to its methods. - for &v in iter::once(&24).chain(bytes) { - self.0 = Wrapping(31) * self.0 + Wrapping(u64::from(v)); - } - } - } - - fn hash_code(value: impl Hash) -> u64 { - let mut hasher = SimpleHasher(Wrapping(1)); - value.hash(&mut hasher); - hasher.finish() - } - - // This creates two deques for which values returned by as_slices - // method differ. - let vda: VecDeque<u8> = (0..10).collect(); - let mut vdb = VecDeque::with_capacity(10); - vdb.extend(5..10); - (0..5).rev().for_each(|elem| vdb.push_front(elem)); - assert_ne!(vda.as_slices(), vdb.as_slices()); - assert_eq!(vda, vdb); - assert_eq!(hash_code(vda), hash_code(vdb)); -} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index d7ae353282e79..8d721ed7487ae 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -189,4 +189,11 @@ pub mod vec; #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] pub mod __export { pub use core::format_args; + + /// Force AST node to an expression to improve diagnostics in pattern position. + #[rustc_macro_transparency = "semitransparent"] + #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] + pub macro force_expr($e:expr) { + $e + } } diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index a64a8b32ad77f..3a46763c3f608 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -35,20 +35,18 @@ /// /// [`Vec`]: crate::vec::Vec #[cfg(not(test))] -#[doc(alias = "alloc")] -#[doc(alias = "malloc")] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(box_syntax, liballoc_internals)] macro_rules! vec { () => ( - $crate::__rust_force_expr!($crate::vec::Vec::new()) + $crate::__export::force_expr!($crate::vec::Vec::new()) ); ($elem:expr; $n:expr) => ( - $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n)) + $crate::__export::force_expr!($crate::vec::from_elem($elem, $n)) ); ($($x:expr),+ $(,)?) => ( - $crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+])) + $crate::__export::force_expr!(<[_]>::into_vec(box [$($x),+])) ); } @@ -113,13 +111,3 @@ macro_rules! format { res }} } - -/// Force AST node to an expression to improve diagnostics in pattern position. -#[doc(hidden)] -#[macro_export] -#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] -macro_rules! __rust_force_expr { - ($e:expr) => { - $e - }; -} diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 56f4ebe57f8af..36b7efc33a874 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -114,19 +114,6 @@ impl<T> RawVec<T, Global> { } impl<T, A: Allocator> RawVec<T, A> { - // Tiny Vecs are dumb. Skip to: - // - 8 if the element size is 1, because any heap allocators is likely - // to round up a request of less than 8 bytes to at least 8 bytes. - // - 4 if elements are moderate-sized (<= 1 KiB). - // - 1 otherwise, to avoid wasting too much space for very short Vecs. - const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 { - 8 - } else if mem::size_of::<T>() <= 1024 { - 4 - } else { - 1 - }; - /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[rustc_allow_const_fn_unstable(const_fn)] @@ -232,7 +219,6 @@ impl<T, A: Allocator> RawVec<T, A> { /// Gets a raw pointer to the start of the allocation. Note that this is /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. - #[inline] pub fn ptr(&self) -> *mut T { self.ptr.as_ptr() } @@ -413,7 +399,22 @@ impl<T, A: Allocator> RawVec<T, A> { // This guarantees exponential growth. The doubling cannot overflow // because `cap <= isize::MAX` and the type of `cap` is `usize`. let cap = cmp::max(self.cap * 2, required_cap); - let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap); + + // Tiny Vecs are dumb. Skip to: + // - 8 if the element size is 1, because any heap allocators is likely + // to round up a request of less than 8 bytes to at least 8 bytes. + // - 4 if elements are moderate-sized (<= 1 KiB). + // - 1 otherwise, to avoid wasting too much space for very short Vecs. + // Note that `min_non_zero_cap` is computed statically. + let elem_size = mem::size_of::<T>(); + let min_non_zero_cap = if elem_size == 1 { + 8 + } else if elem_size <= 1024 { + 4 + } else { + 1 + }; + let cap = cmp::max(min_non_zero_cap, cap); let new_layout = Layout::array::<T>(cap); diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index b1f860d6b64a8..6f2a497598dd7 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -403,8 +403,6 @@ impl String { /// s.push('a'); /// ``` #[inline] - #[doc(alias = "alloc")] - #[doc(alias = "malloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> String { String { vec: Vec::with_capacity(capacity) } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b533ce794207a..0f5feb4ab8dc4 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -433,7 +433,6 @@ impl<T> Vec<T> { /// assert!(vec.capacity() >= 11); /// ``` #[inline] - #[doc(alias = "malloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) @@ -767,7 +766,6 @@ impl<T, A: Allocator> Vec<T, A> { /// vec.reserve(10); /// assert!(vec.capacity() >= 11); /// ``` - #[doc(alias = "realloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); @@ -793,7 +791,6 @@ impl<T, A: Allocator> Vec<T, A> { /// vec.reserve_exact(10); /// assert!(vec.capacity() >= 11); /// ``` - #[doc(alias = "realloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.buf.reserve_exact(self.len, additional); @@ -831,7 +828,6 @@ impl<T, A: Allocator> Vec<T, A> { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[doc(alias = "realloc")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve(self.len, additional) @@ -873,7 +869,6 @@ impl<T, A: Allocator> Vec<T, A> { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[doc(alias = "realloc")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve_exact(self.len, additional) @@ -893,7 +888,6 @@ impl<T, A: Allocator> Vec<T, A> { /// vec.shrink_to_fit(); /// assert!(vec.capacity() >= 3); /// ``` - #[doc(alias = "realloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { // The capacity is never less than the length, and there's nothing to do when @@ -926,7 +920,6 @@ impl<T, A: Allocator> Vec<T, A> { /// vec.shrink_to(0); /// assert!(vec.capacity() >= 3); /// ``` - #[doc(alias = "realloc")] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs index ec390c62165a5..6abd4ff2a3f0a 100644 --- a/library/alloc/src/vec/spec_from_iter_nested.rs +++ b/library/alloc/src/vec/spec_from_iter_nested.rs @@ -5,7 +5,7 @@ use super::{SpecExtend, Vec}; /// Another specialization trait for Vec::from_iter /// necessary to manually prioritize overlapping specializations -/// see [`SpecFromIter`](super::SpecFromIter) for details. +/// see [`SpecFromIter`] for details. pub(super) trait SpecFromIterNested<T, I> { fn from_iter(iter: I) -> Self; } diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index f2169914ac9da..fb6b4b7837941 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -276,29 +276,7 @@ bench_sums! { bench_sums! { bench_cycle_take_sum, bench_cycle_take_ref_sum, - (0..10000).cycle().take(1000000) -} - -bench_sums! { - bench_cycle_skip_take_sum, - bench_cycle_skip_take_ref_sum, - (0..100000).cycle().skip(1000000).take(1000000) -} - -bench_sums! { - bench_cycle_take_skip_sum, - bench_cycle_take_skip_ref_sum, - (0..100000).cycle().take(1000000).skip(100000) -} - -bench_sums! { - bench_skip_cycle_skip_zip_add_sum, - bench_skip_cycle_skip_zip_add_ref_sum, - (0..100000).skip(100).cycle().skip(100) - .zip((0..100000).cycle().skip(10)) - .map(|(a,b)| a+b) - .skip(100000) - .take(1000000) + (0i64..10000).cycle().take(1000000) } // Checks whether Skip<Zip<A,B>> is as fast as Zip<Skip<A>, Skip<B>>, from diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 139863bbe7f81..041f40f2cbcf5 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -460,6 +460,7 @@ pub trait TryInto<T>: Sized { /// assert!(try_successful_smaller_number.is_ok()); /// ``` /// +/// [`i32::MAX`]: crate::i32::MAX /// [`try_from`]: TryFrom::try_from /// [`!`]: ../../std/primitive.never.html #[stable(feature = "try_from", since = "1.34.0")] diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index ce5e9936bbd7f..9753e1b43ba95 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -1,5 +1,5 @@ use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen}; -use crate::ops::Try; +use crate::{ops::Try, usize}; /// An iterator that links two iterators together, in a chain. /// diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index d8bbd424cf258..1d01e9b5fb7dc 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -151,14 +151,16 @@ where { let (lo, hi) = iter.size_hint(); let next_is_elem = !needs_sep; - ( - lo.saturating_sub(next_is_elem as usize).saturating_add(lo), - hi.and_then(|hi| hi.saturating_sub(next_is_elem as usize).checked_add(hi)), - ) + let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo); + let hi = match hi { + Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi), + None => None, + }; + (lo, hi) } fn intersperse_fold<I, B, F, G>( - mut iter: I, + mut iter: Peekable<I>, init: B, mut f: F, mut separator: G, @@ -171,11 +173,10 @@ where { let mut accum = init; - if !needs_sep { + // Use `peek()` first to avoid calling `next()` on an empty iterator. + if !needs_sep || iter.peek().is_some() { if let Some(x) = iter.next() { accum = f(accum, x); - } else { - return accum; } } diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index e55c7a6bf5df1..dd5325660c342 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -1,4 +1,3 @@ -use crate::intrinsics::unlikely; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::ops::{ControlFlow, Try}; @@ -32,10 +31,13 @@ where #[inline] fn next(&mut self) -> Option<I::Item> { - if unlikely(self.n > 0) { - self.iter.nth(crate::mem::take(&mut self.n) - 1); + if self.n == 0 { + self.iter.next() + } else { + let old_n = self.n; + self.n = 0; + self.iter.nth(old_n) } - self.iter.next() } #[inline] diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 9e7055a370c9d..4321b2187e108 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -200,7 +200,6 @@ macro_rules! step_identical_methods { } #[inline] - #[allow(arithmetic_overflow)] fn forward(start: Self, n: usize) -> Self { // In debug builds, trigger a panic on overflow. // This should optimize completely out in release builds. @@ -212,7 +211,6 @@ macro_rules! step_identical_methods { } #[inline] - #[allow(arithmetic_overflow)] fn backward(start: Self, n: usize) -> Self { // In debug builds, trigger a panic on overflow. // This should optimize completely out in release builds. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 9f7ced829b0ac..83d339d8f40a5 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -225,6 +225,8 @@ pub trait Iterator { /// This function might panic if the iterator has more than [`usize::MAX`] /// elements. /// + /// [`usize::MAX`]: crate::usize::MAX + /// /// # Examples /// /// Basic usage: @@ -567,10 +569,9 @@ pub trait Iterator { Zip::new(self, other.into_iter()) } - /// Creates a new iterator which places a copy of `separator` between adjacent - /// items of the original iterator. + /// Places a copy of `separator` between all elements. /// - /// In case `separator` does not implement [`Clone`] or needs to be + /// In case the separator does not implement [`Clone`] or needs to be /// computed every time, use [`intersperse_with`]. /// /// # Examples @@ -580,19 +581,6 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let mut a = [0, 1, 2].iter().intersperse(&100); - /// assert_eq!(a.next(), Some(&0)); // The first element from `a`. - /// assert_eq!(a.next(), Some(&100)); // The separator. - /// assert_eq!(a.next(), Some(&1)); // The next element from `a`. - /// assert_eq!(a.next(), Some(&100)); // The separator. - /// assert_eq!(a.next(), Some(&2)); // The last element from `a`. - /// assert_eq!(a.next(), None); // The iterator is finished. - /// ``` - /// - /// `intersperse` can be very useful to join an iterator's items using a common element: - /// ``` - /// #![feature(iter_intersperse)] - /// /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::<String>(); /// assert_eq!(hello, "Hello World !"); /// ``` @@ -609,16 +597,7 @@ pub trait Iterator { Intersperse::new(self, separator) } - /// Creates a new iterator which places an item generated by `separator` - /// between adjacent items of the original iterator. - /// - /// The closure will be called exactly once each time an item is placed - /// between two adjacent items from the underlying iterator; specifically, - /// the closure is not called if the underlying iterator yields less than - /// two items and after the last item is yielded. - /// - /// If the iterator's item implements [`Clone`], it may be easier to use - /// [`intersperse`]. + /// Places an element generated by `separator` between all elements. /// /// # Examples /// @@ -627,36 +606,14 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// #[derive(PartialEq, Debug)] - /// struct NotClone(usize); - /// - /// let v = vec![NotClone(0), NotClone(1), NotClone(2)]; - /// let mut it = v.into_iter().intersperse_with(|| NotClone(99)); - /// - /// assert_eq!(it.next(), Some(NotClone(0))); // The first element from `v`. - /// assert_eq!(it.next(), Some(NotClone(99))); // The separator. - /// assert_eq!(it.next(), Some(NotClone(1))); // The next element from `v`. - /// assert_eq!(it.next(), Some(NotClone(99))); // The separator. - /// assert_eq!(it.next(), Some(NotClone(2))); // The last element from from `v`. - /// assert_eq!(it.next(), None); // The iterator is finished. - /// ``` - /// - /// `intersperse_with` can be used in situations where the separator needs - /// to be computed: - /// ``` - /// #![feature(iter_intersperse)] - /// /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); /// - /// // The closure mutably borrows its context to generate an item. /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied(); /// let separator = || happy_emojis.next().unwrap_or(" 🦀 "); /// /// let result = src.intersperse_with(separator).collect::<String>(); /// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!"); /// ``` - /// [`Clone`]: crate::clone::Clone - /// [`intersperse`]: Iterator::intersperse #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G> @@ -914,6 +871,7 @@ pub trait Iterator { /// overflow a [`usize`]. /// /// [`usize`]: type@usize + /// [`usize::MAX`]: crate::usize::MAX /// [`zip`]: Iterator::zip /// /// # Examples @@ -2425,6 +2383,7 @@ pub trait Iterator { /// non-matching elements. /// /// [`Some(index)`]: Some + /// [`usize::MAX`]: crate::usize::MAX /// /// # Examples /// diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index ed8eea672f80b..0900676146c0d 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -33,6 +33,8 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {} /// /// This trait must only be implemented when the contract is upheld. Consumers /// of this trait must inspect [`Iterator::size_hint()`]’s upper bound. +/// +/// [`usize::MAX`]: crate::usize::MAX #[unstable(feature = "trusted_len", issue = "37572")] #[rustc_unsafe_specialization_marker] pub unsafe trait TrustedLen: Iterator {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 263c6c9cf0f26..df8d9ff371fe4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -126,7 +126,6 @@ #![feature(auto_traits)] #![feature(or_patterns)] #![feature(prelude_import)] -#![feature(raw_ref_macros)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 91c61f814e1a8..039112e9f3468 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -3,7 +3,7 @@ //! # Problem statement //! //! We are given a decimal string such as `12.34e56`. This string consists of integral (`12`), -//! fractional (`34`), and exponent (`56`) parts. All parts are optional and interpreted as zero +//! fractional (`45`), and exponent (`56`) parts. All parts are optional and interpreted as zero //! when missing. //! //! We seek the IEEE 754 floating point number that is closest to the exact value of the decimal diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 795f94ec03454..4d876fd8c33e2 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1,13 +1,12 @@ -//! Constants specific to the `f32` single-precision floating point type. +//! This module provides constants which are specific to the implementation +//! of the `f32` floating point data type. //! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* //! //! Mathematically significant numbers are provided in the `consts` sub-module. //! -//! For the constants defined directly in this module -//! (as distinct from those defined in the `consts` sub-module), -//! new code should instead use the associated constants -//! defined directly on the `f32` type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] @@ -24,14 +23,12 @@ use crate::num::FpCategory; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let r = std::f32::RADIX; /// /// // intended way /// let r = f32::RADIX; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f32`")] pub const RADIX: u32 = f32::RADIX; /// Number of significant digits in base 2. @@ -41,17 +38,12 @@ pub const RADIX: u32 = f32::RADIX; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let d = std::f32::MANTISSA_DIGITS; /// /// // intended way /// let d = f32::MANTISSA_DIGITS; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f32`" -)] pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS; /// Approximate number of significant digits in base 10. @@ -61,14 +53,12 @@ pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let d = std::f32::DIGITS; /// /// // intended way /// let d = f32::DIGITS; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f32`")] pub const DIGITS: u32 = f32::DIGITS; /// [Machine epsilon] value for `f32`. @@ -82,17 +72,12 @@ pub const DIGITS: u32 = f32::DIGITS; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let e = std::f32::EPSILON; /// /// // intended way /// let e = f32::EPSILON; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `EPSILON` associated constant on `f32`" -)] pub const EPSILON: f32 = f32::EPSILON; /// Smallest finite `f32` value. @@ -102,14 +87,12 @@ pub const EPSILON: f32 = f32::EPSILON; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f32::MIN; /// /// // intended way /// let min = f32::MIN; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f32`")] pub const MIN: f32 = f32::MIN; /// Smallest positive normal `f32` value. @@ -119,17 +102,12 @@ pub const MIN: f32 = f32::MIN; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f32::MIN_POSITIVE; /// /// // intended way /// let min = f32::MIN_POSITIVE; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MIN_POSITIVE` associated constant on `f32`" -)] pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE; /// Largest finite `f32` value. @@ -139,14 +117,12 @@ pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let max = std::f32::MAX; /// /// // intended way /// let max = f32::MAX; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f32`")] pub const MAX: f32 = f32::MAX; /// One greater than the minimum possible normal power of 2 exponent. @@ -156,17 +132,12 @@ pub const MAX: f32 = f32::MAX; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f32::MIN_EXP; /// /// // intended way /// let min = f32::MIN_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MIN_EXP` associated constant on `f32`" -)] pub const MIN_EXP: i32 = f32::MIN_EXP; /// Maximum possible power of 2 exponent. @@ -176,17 +147,12 @@ pub const MIN_EXP: i32 = f32::MIN_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let max = std::f32::MAX_EXP; /// /// // intended way /// let max = f32::MAX_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MAX_EXP` associated constant on `f32`" -)] pub const MAX_EXP: i32 = f32::MAX_EXP; /// Minimum possible normal power of 10 exponent. @@ -196,17 +162,12 @@ pub const MAX_EXP: i32 = f32::MAX_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f32::MIN_10_EXP; /// /// // intended way /// let min = f32::MIN_10_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MIN_10_EXP` associated constant on `f32`" -)] pub const MIN_10_EXP: i32 = f32::MIN_10_EXP; /// Maximum possible power of 10 exponent. @@ -216,17 +177,12 @@ pub const MIN_10_EXP: i32 = f32::MIN_10_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let max = std::f32::MAX_10_EXP; /// /// // intended way /// let max = f32::MAX_10_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MAX_10_EXP` associated constant on `f32`" -)] pub const MAX_10_EXP: i32 = f32::MAX_10_EXP; /// Not a Number (NaN). @@ -236,14 +192,12 @@ pub const MAX_10_EXP: i32 = f32::MAX_10_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let nan = std::f32::NAN; /// /// // intended way /// let nan = f32::NAN; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f32`")] pub const NAN: f32 = f32::NAN; /// Infinity (∞). @@ -253,17 +207,12 @@ pub const NAN: f32 = f32::NAN; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let inf = std::f32::INFINITY; /// /// // intended way /// let inf = f32::INFINITY; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `INFINITY` associated constant on `f32`" -)] pub const INFINITY: f32 = f32::INFINITY; /// Negative infinity (−∞). @@ -273,17 +222,12 @@ pub const INFINITY: f32 = f32::INFINITY; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let ninf = std::f32::NEG_INFINITY; /// /// // intended way /// let ninf = f32::NEG_INFINITY; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `NEG_INFINITY` associated constant on `f32`" -)] pub const NEG_INFINITY: f32 = f32::NEG_INFINITY; /// Basic mathematical constants. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7af968f7fe84b..3323b7d6774df 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1,13 +1,12 @@ -//! Constants specific to the `f64` double-precision floating point type. +//! This module provides constants which are specific to the implementation +//! of the `f64` floating point data type. //! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* //! //! Mathematically significant numbers are provided in the `consts` sub-module. //! -//! For the constants defined directly in this module -//! (as distinct from those defined in the `consts` sub-module), -//! new code should instead use the associated constants -//! defined directly on the `f64` type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] @@ -24,14 +23,12 @@ use crate::num::FpCategory; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let r = std::f64::RADIX; /// /// // intended way /// let r = f64::RADIX; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f64`")] pub const RADIX: u32 = f64::RADIX; /// Number of significant digits in base 2. @@ -41,17 +38,12 @@ pub const RADIX: u32 = f64::RADIX; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let d = std::f64::MANTISSA_DIGITS; /// /// // intended way /// let d = f64::MANTISSA_DIGITS; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f64`" -)] pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS; /// Approximate number of significant digits in base 10. @@ -61,14 +53,12 @@ pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let d = std::f64::DIGITS; /// /// // intended way /// let d = f64::DIGITS; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f64`")] pub const DIGITS: u32 = f64::DIGITS; /// [Machine epsilon] value for `f64`. @@ -82,17 +72,12 @@ pub const DIGITS: u32 = f64::DIGITS; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let e = std::f64::EPSILON; /// /// // intended way /// let e = f64::EPSILON; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `EPSILON` associated constant on `f64`" -)] pub const EPSILON: f64 = f64::EPSILON; /// Smallest finite `f64` value. @@ -102,14 +87,12 @@ pub const EPSILON: f64 = f64::EPSILON; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f64::MIN; /// /// // intended way /// let min = f64::MIN; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f64`")] pub const MIN: f64 = f64::MIN; /// Smallest positive normal `f64` value. @@ -119,17 +102,12 @@ pub const MIN: f64 = f64::MIN; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f64::MIN_POSITIVE; /// /// // intended way /// let min = f64::MIN_POSITIVE; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MIN_POSITIVE` associated constant on `f64`" -)] pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE; /// Largest finite `f64` value. @@ -139,14 +117,12 @@ pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let max = std::f64::MAX; /// /// // intended way /// let max = f64::MAX; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f64`")] pub const MAX: f64 = f64::MAX; /// One greater than the minimum possible normal power of 2 exponent. @@ -156,17 +132,12 @@ pub const MAX: f64 = f64::MAX; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f64::MIN_EXP; /// /// // intended way /// let min = f64::MIN_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MIN_EXP` associated constant on `f64`" -)] pub const MIN_EXP: i32 = f64::MIN_EXP; /// Maximum possible power of 2 exponent. @@ -176,17 +147,12 @@ pub const MIN_EXP: i32 = f64::MIN_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let max = std::f64::MAX_EXP; /// /// // intended way /// let max = f64::MAX_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MAX_EXP` associated constant on `f64`" -)] pub const MAX_EXP: i32 = f64::MAX_EXP; /// Minimum possible normal power of 10 exponent. @@ -196,17 +162,12 @@ pub const MAX_EXP: i32 = f64::MAX_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let min = std::f64::MIN_10_EXP; /// /// // intended way /// let min = f64::MIN_10_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MIN_10_EXP` associated constant on `f64`" -)] pub const MIN_10_EXP: i32 = f64::MIN_10_EXP; /// Maximum possible power of 10 exponent. @@ -216,17 +177,12 @@ pub const MIN_10_EXP: i32 = f64::MIN_10_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let max = std::f64::MAX_10_EXP; /// /// // intended way /// let max = f64::MAX_10_EXP; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `MAX_10_EXP` associated constant on `f64`" -)] pub const MAX_10_EXP: i32 = f64::MAX_10_EXP; /// Not a Number (NaN). @@ -236,14 +192,12 @@ pub const MAX_10_EXP: i32 = f64::MAX_10_EXP; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let nan = std::f64::NAN; /// /// // intended way /// let nan = f64::NAN; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f64`")] pub const NAN: f64 = f64::NAN; /// Infinity (∞). @@ -253,17 +207,12 @@ pub const NAN: f64 = f64::NAN; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let inf = std::f64::INFINITY; /// /// // intended way /// let inf = f64::INFINITY; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `INFINITY` associated constant on `f64`" -)] pub const INFINITY: f64 = f64::INFINITY; /// Negative infinity (−∞). @@ -273,17 +222,12 @@ pub const INFINITY: f64 = f64::INFINITY; /// /// ```rust /// // deprecated way -/// # #[allow(deprecated, deprecated_in_future)] /// let ninf = std::f64::NEG_INFINITY; /// /// // intended way /// let ninf = f64::NEG_INFINITY; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated( - since = "TBD", - reason = "replaced by the `NEG_INFINITY` associated constant on `f64`" -)] pub const NEG_INFINITY: f64 = f64::NEG_INFINITY; /// Basic mathematical constants. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index f732f11d909e7..162ed7d1b8dfe 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1975,28 +1975,32 @@ macro_rules! int_impl { unsafe { mem::transmute(bytes) } } - /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN).")] + /// **This method is soft-deprecated.** + /// + /// Although using it won’t cause a compilation warning, new code should use + #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")] + /// instead. /// /// Returns the smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] #[rustc_promotable] #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] - #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")] pub const fn min_value() -> Self { Self::MIN } - /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX).")] + /// **This method is soft-deprecated.** + /// + /// Although using it won’t cause a compilation warning, new code should use + #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")] + /// instead. /// /// Returns the largest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] #[rustc_promotable] #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")] pub const fn max_value() -> Self { Self::MAX } diff --git a/library/core/src/num/shells/i128.rs b/library/core/src/num/shells/i128.rs index 785e9a4e9cfb7..08cb795946868 100644 --- a/library/core/src/num/shells/i128.rs +++ b/library/core/src/num/shells/i128.rs @@ -1,13 +1,10 @@ -//! Constants for the 128-bit signed integer type. +//! The 128-bit signed integer type. //! //! *[See also the `i128` primitive type](../../std/primitive.i128.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "i128", since = "1.26.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `i128`" -)] int_module! { i128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/library/core/src/num/shells/i16.rs b/library/core/src/num/shells/i16.rs index 48ea2e3e964c2..288eaceba59d6 100644 --- a/library/core/src/num/shells/i16.rs +++ b/library/core/src/num/shells/i16.rs @@ -1,13 +1,10 @@ -//! Constants for the 16-bit signed integer type. +//! The 16-bit signed integer type. //! //! *[See also the `i16` primitive type](../../std/primitive.i16.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `i16`" -)] int_module! { i16 } diff --git a/library/core/src/num/shells/i32.rs b/library/core/src/num/shells/i32.rs index fce6980f45679..0e1a2ec56ccb2 100644 --- a/library/core/src/num/shells/i32.rs +++ b/library/core/src/num/shells/i32.rs @@ -1,13 +1,10 @@ -//! Constants for the 32-bit signed integer type. +//! The 32-bit signed integer type. //! //! *[See also the `i32` primitive type](../../std/primitive.i32.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `i32`" -)] int_module! { i32 } diff --git a/library/core/src/num/shells/i64.rs b/library/core/src/num/shells/i64.rs index 6aa8fcf452bde..27f7092710b34 100644 --- a/library/core/src/num/shells/i64.rs +++ b/library/core/src/num/shells/i64.rs @@ -1,13 +1,10 @@ -//! Constants for the 64-bit signed integer type. +//! The 64-bit signed integer type. //! //! *[See also the `i64` primitive type](../../std/primitive.i64.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `i64`" -)] int_module! { i64 } diff --git a/library/core/src/num/shells/i8.rs b/library/core/src/num/shells/i8.rs index b4e0fef61bb28..e84b421e1a444 100644 --- a/library/core/src/num/shells/i8.rs +++ b/library/core/src/num/shells/i8.rs @@ -1,13 +1,10 @@ -//! Constants for the 8-bit signed integer type. +//! The 8-bit signed integer type. //! //! *[See also the `i8` primitive type](../../std/primitive.i8.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `i8`" -)] int_module! { i8 } diff --git a/library/core/src/num/shells/int_macros.rs b/library/core/src/num/shells/int_macros.rs index 78513d44b7580..5f8bb648d04ae 100644 --- a/library/core/src/num/shells/int_macros.rs +++ b/library/core/src/num/shells/int_macros.rs @@ -20,7 +20,6 @@ macro_rules! int_module { /// ``` /// #[$attr] - #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")] pub const MIN: $T = $T::MIN; #[doc = concat!( @@ -40,7 +39,6 @@ macro_rules! int_module { /// ``` /// #[$attr] - #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")] pub const MAX: $T = $T::MAX; ) } diff --git a/library/core/src/num/shells/isize.rs b/library/core/src/num/shells/isize.rs index 5dc128d58ae02..0dcfa4a2bd134 100644 --- a/library/core/src/num/shells/isize.rs +++ b/library/core/src/num/shells/isize.rs @@ -1,13 +1,10 @@ -//! Constants for the pointer-sized signed integer type. +//! The pointer-sized signed integer type. //! //! *[See also the `isize` primitive type](../../std/primitive.isize.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `isize`" -)] int_module! { isize } diff --git a/library/core/src/num/shells/u128.rs b/library/core/src/num/shells/u128.rs index 6012584ae86ae..dd45ff141539f 100644 --- a/library/core/src/num/shells/u128.rs +++ b/library/core/src/num/shells/u128.rs @@ -1,13 +1,9 @@ -//! Constants for the 128-bit unsigned integer type. +//! The 128-bit unsigned integer type. //! //! *[See also the `u128` primitive type](../../std/primitive.u128.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "i128", since = "1.26.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `u128`" -)] - int_module! { u128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/library/core/src/num/shells/u16.rs b/library/core/src/num/shells/u16.rs index 36641196403bc..738071643b639 100644 --- a/library/core/src/num/shells/u16.rs +++ b/library/core/src/num/shells/u16.rs @@ -1,13 +1,10 @@ -//! Constants for the 16-bit unsigned integer type. +//! The 16-bit unsigned integer type. //! //! *[See also the `u16` primitive type](../../std/primitive.u16.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `u16`" -)] int_module! { u16 } diff --git a/library/core/src/num/shells/u32.rs b/library/core/src/num/shells/u32.rs index f58f71423dbc3..9800c9099748f 100644 --- a/library/core/src/num/shells/u32.rs +++ b/library/core/src/num/shells/u32.rs @@ -1,13 +1,10 @@ -//! Constants for the 32-bit unsigned integer type. +//! The 32-bit unsigned integer type. //! //! *[See also the `u32` primitive type](../../std/primitive.u32.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `u32`" -)] int_module! { u32 } diff --git a/library/core/src/num/shells/u64.rs b/library/core/src/num/shells/u64.rs index 2b221f66da60a..fb686c396f033 100644 --- a/library/core/src/num/shells/u64.rs +++ b/library/core/src/num/shells/u64.rs @@ -1,13 +1,10 @@ -//! Constants for the 64-bit unsigned integer type. +//! The 64-bit unsigned integer type. //! //! *[See also the `u64` primitive type](../../std/primitive.u64.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `u64`" -)] int_module! { u64 } diff --git a/library/core/src/num/shells/u8.rs b/library/core/src/num/shells/u8.rs index 83ec60dcbd852..c03cbdda25dbb 100644 --- a/library/core/src/num/shells/u8.rs +++ b/library/core/src/num/shells/u8.rs @@ -1,13 +1,10 @@ -//! Constants for the 8-bit unsigned integer type. +//! The 8-bit unsigned integer type. //! //! *[See also the `u8` primitive type](../../std/primitive.u8.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `u8`" -)] int_module! { u8 } diff --git a/library/core/src/num/shells/usize.rs b/library/core/src/num/shells/usize.rs index c38d521f3dae0..a893041615244 100644 --- a/library/core/src/num/shells/usize.rs +++ b/library/core/src/num/shells/usize.rs @@ -1,13 +1,10 @@ -//! Constants for the pointer-sized unsigned integer type. +//! The pointer-sized unsigned integer type. //! //! *[See also the `usize` primitive type](../../std/primitive.usize.html).* //! -//! New code should use the associated constants directly on the primitive type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![rustc_deprecated( - since = "TBD", - reason = "all constants in this module replaced by associated constants on `usize`" -)] int_module! { usize } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 9fccf3f72ce1a..8f141a3ff9e97 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1805,8 +1805,10 @@ macro_rules! uint_impl { unsafe { mem::transmute(bytes) } } - /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN).")] + /// **This method is soft-deprecated.** + /// + /// Although using it won’t cause compilation warning, new code should use + #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")] /// instead. /// /// Returns the smallest value that can be represented by this integer type. @@ -1814,11 +1816,12 @@ macro_rules! uint_impl { #[rustc_promotable] #[inline(always)] #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")] pub const fn min_value() -> Self { Self::MIN } - /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX).")] + /// **This method is soft-deprecated.** + /// + /// Although using it won’t cause compilation warning, new code should use + #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")] /// instead. /// /// Returns the largest value that can be represented by this integer type. @@ -1826,7 +1829,6 @@ macro_rules! uint_impl { #[rustc_promotable] #[inline(always)] #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")] pub const fn max_value() -> Self { Self::MAX } } } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e45fefc7ed765..d849008b88030 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -19,19 +19,12 @@ use crate::slice::{self, SliceIndex}; /// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`. /// However the pointer may still dangle if it isn't dereferenced. /// -/// Unlike `*mut T`, `NonNull<T>` was chosen to be covariant over `T`. This makes it -/// possible to use `NonNull<T>` when building covariant types, but introduces the -/// risk of unsoundness if used in a type that shouldn't actually be covariant. -/// (The opposite choice was made for `*mut T` even though technically the unsoundness -/// could only be caused by calling unsafe functions.) -/// -/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`, -/// and `LinkedList`. This is the case because they provide a public API that follows the -/// normal shared XOR mutable rules of Rust. -/// -/// If your type cannot safely be covariant, you must ensure it contains some -/// additional field to provide invariance. Often this field will be a [`PhantomData`] -/// type like `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`. +/// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. If this is incorrect +/// for your use case, you should include some [`PhantomData`] in your type to +/// provide invariance, such as `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`. +/// Usually this won't be necessary; covariance is correct for most safe abstractions, +/// such as `Box`, `Rc`, `Arc`, `Vec`, and `LinkedList`. This is the case because they +/// provide a public API that follows the normal shared XOR mutable rules of Rust. /// /// Notice that `NonNull<T>` has a `From` instance for `&T`. However, this does /// not change the fact that mutating through a (pointer derived from a) shared diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b06b6e93373f3..de8d7fc29dc05 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -542,9 +542,10 @@ impl<T> [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { - // Can't take two mutable loans from one vector, so instead use raw pointers. - let pa = ptr::raw_mut!(self[a]); - let pb = ptr::raw_mut!(self[b]); + // Can't take two mutable loans from one vector, so instead just cast + // them to their raw pointers to do the swap. + let pa: *mut T = &mut self[a]; + let pb: *mut T = &mut self[b]; // SAFETY: `pa` and `pb` have been created from safe mutable references and refer // to elements in the slice and therefore are guaranteed to be valid and aligned. // Note that accessing the elements behind `a` and `b` is checked and will diff --git a/library/core/src/time.rs b/library/core/src/time.rs index b1443bc33d2ff..88b4e2a2436e7 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1067,23 +1067,13 @@ impl fmt::Debug for Duration { } if self.secs > 0 { - fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10)?; + fmt_decimal(f, self.secs, self.nanos, 100_000_000)?; f.write_str("s") - } else if self.nanos >= NANOS_PER_MILLI { - fmt_decimal( - f, - (self.nanos / NANOS_PER_MILLI) as u64, - self.nanos % NANOS_PER_MILLI, - NANOS_PER_MILLI / 10, - )?; + } else if self.nanos >= 1_000_000 { + fmt_decimal(f, self.nanos as u64 / 1_000_000, self.nanos % 1_000_000, 100_000)?; f.write_str("ms") - } else if self.nanos >= NANOS_PER_MICRO { - fmt_decimal( - f, - (self.nanos / NANOS_PER_MICRO) as u64, - self.nanos % NANOS_PER_MICRO, - NANOS_PER_MICRO / 10, - )?; + } else if self.nanos >= 1_000 { + fmt_decimal(f, self.nanos as u64 / 1_000, self.nanos % 1_000, 100)?; f.write_str("µs") } else { fmt_decimal(f, self.nanos as u64, 0, 1)?; diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs new file mode 100644 index 0000000000000..bc5421bfb5f8f --- /dev/null +++ b/library/core/tests/iter.rs @@ -0,0 +1,3640 @@ +// ignore-tidy-filelength + +use core::cell::Cell; +use core::convert::TryFrom; +use core::iter::TrustedRandomAccess; +use core::iter::*; + +/// An iterator wrapper that panics whenever `next` or `next_back` is called +/// after `None` has been returned. +struct Unfuse<I> { + iter: I, + exhausted: bool, +} + +fn unfuse<I: IntoIterator>(iter: I) -> Unfuse<I::IntoIter> { + Unfuse { iter: iter.into_iter(), exhausted: false } +} + +impl<I> Iterator for Unfuse<I> +where + I: Iterator, +{ + type Item = I::Item; + + fn next(&mut self) -> Option<Self::Item> { + assert!(!self.exhausted); + let next = self.iter.next(); + self.exhausted = next.is_none(); + next + } +} + +impl<I> DoubleEndedIterator for Unfuse<I> +where + I: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option<Self::Item> { + assert!(!self.exhausted); + let next = self.iter.next_back(); + self.exhausted = next.is_none(); + next + } +} + +#[test] +fn test_lt() { + let empty: [isize; 0] = []; + let xs = [1, 2, 3]; + let ys = [1, 2, 0]; + + assert!(!xs.iter().lt(ys.iter())); + assert!(!xs.iter().le(ys.iter())); + assert!(xs.iter().gt(ys.iter())); + assert!(xs.iter().ge(ys.iter())); + + assert!(ys.iter().lt(xs.iter())); + assert!(ys.iter().le(xs.iter())); + assert!(!ys.iter().gt(xs.iter())); + assert!(!ys.iter().ge(xs.iter())); + + assert!(empty.iter().lt(xs.iter())); + assert!(empty.iter().le(xs.iter())); + assert!(!empty.iter().gt(xs.iter())); + assert!(!empty.iter().ge(xs.iter())); + + // Sequence with NaN + let u = [1.0f64, 2.0]; + let v = [0.0f64 / 0.0, 3.0]; + + assert!(!u.iter().lt(v.iter())); + assert!(!u.iter().le(v.iter())); + assert!(!u.iter().gt(v.iter())); + assert!(!u.iter().ge(v.iter())); + + let a = [0.0f64 / 0.0]; + let b = [1.0f64]; + let c = [2.0f64]; + + assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); + assert!(a.iter().le(b.iter()) == (a[0] <= b[0])); + assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); + assert!(a.iter().ge(b.iter()) == (a[0] >= b[0])); + + assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); + assert!(c.iter().le(b.iter()) == (c[0] <= b[0])); + assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); + assert!(c.iter().ge(b.iter()) == (c[0] >= b[0])); +} + +#[test] +fn test_multi_iter() { + let xs = [1, 2, 3, 4]; + let ys = [4, 3, 2, 1]; + assert!(xs.iter().eq(ys.iter().rev())); + assert!(xs.iter().lt(xs.iter().skip(2))); +} + +#[test] +fn test_cmp_by() { + use core::cmp::Ordering; + + let f = |x: i32, y: i32| (x * x).cmp(&y); + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 16].iter().copied(); + + assert_eq!(xs().cmp_by(ys(), f), Ordering::Less); + assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater); + assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal); + assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater); + assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less); + assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater); +} + +#[test] +fn test_partial_cmp_by() { + use core::cmp::Ordering; + + let f = |x: i32, y: i32| (x * x).partial_cmp(&y); + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 16].iter().copied(); + + assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less)); + assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); + assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal)); + assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater)); + assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less)); + assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater)); + + let f = |x: f64, y: f64| (x * x).partial_cmp(&y); + let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied(); + let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied(); + + assert_eq!(xs().partial_cmp_by(ys(), f), None); + assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); +} + +#[test] +fn test_eq_by() { + let f = |x: i32, y: i32| x * x == y; + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 9, 16].iter().copied(); + + assert!(xs().eq_by(ys(), f)); + assert!(!ys().eq_by(xs(), f)); + assert!(!xs().eq_by(xs(), f)); + assert!(!ys().eq_by(ys(), f)); + + assert!(!xs().take(3).eq_by(ys(), f)); + assert!(!xs().eq_by(ys().take(3), f)); + assert!(xs().take(3).eq_by(ys().take(3), f)); +} + +#[test] +fn test_counter_from_iter() { + let it = (0..).step_by(5).take(10); + let xs: Vec<isize> = FromIterator::from_iter(it); + assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); +} + +#[test] +fn test_iterator_chain() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + let it = xs.iter().chain(&ys); + let mut i = 0; + for &x in it { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); + + let ys = (30..).step_by(10).take(4); + let it = xs.iter().cloned().chain(ys); + let mut i = 0; + for x in it { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_iterator_chain_advance_by() { + fn test_chain(xs: &[i32], ys: &[i32]) { + let len = xs.len() + ys.len(); + + for i in 0..xs.len() { + let mut iter = unfuse(xs).chain(unfuse(ys)); + iter.advance_by(i).unwrap(); + assert_eq!(iter.next(), Some(&xs[i])); + assert_eq!(iter.advance_by(100), Err(len - i - 1)); + } + + for i in 0..ys.len() { + let mut iter = unfuse(xs).chain(unfuse(ys)); + iter.advance_by(xs.len() + i).unwrap(); + assert_eq!(iter.next(), Some(&ys[i])); + assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1)); + } + + let mut iter = xs.iter().chain(ys); + iter.advance_by(len).unwrap(); + assert_eq!(iter.next(), None); + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_by(len + 1), Err(len)); + } + + test_chain(&[], &[]); + test_chain(&[], &[0, 1, 2, 3, 4, 5]); + test_chain(&[0, 1, 2, 3, 4, 5], &[]); + test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); +} + +#[test] +fn test_iterator_chain_advance_back_by() { + fn test_chain(xs: &[i32], ys: &[i32]) { + let len = xs.len() + ys.len(); + + for i in 0..ys.len() { + let mut iter = unfuse(xs).chain(unfuse(ys)); + iter.advance_back_by(i).unwrap(); + assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); + assert_eq!(iter.advance_back_by(100), Err(len - i - 1)); + } + + for i in 0..xs.len() { + let mut iter = unfuse(xs).chain(unfuse(ys)); + iter.advance_back_by(ys.len() + i).unwrap(); + assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); + assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1)); + } + + let mut iter = xs.iter().chain(ys); + iter.advance_back_by(len).unwrap(); + assert_eq!(iter.next_back(), None); + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_back_by(len + 1), Err(len)); + } + + test_chain(&[], &[]); + test_chain(&[], &[0, 1, 2, 3, 4, 5]); + test_chain(&[0, 1, 2, 3, 4, 5], &[]); + test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); +} + +#[test] +fn test_iterator_chain_nth() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + for (i, x) in expected.iter().enumerate() { + assert_eq!(Some(x), xs.iter().chain(&ys).nth(i)); + } + assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0)); + + let mut it = xs.iter().chain(&zs); + assert_eq!(it.nth(5), Some(&5)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_chain_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + for (i, x) in expected.iter().rev().enumerate() { + assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i)); + } + assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5)); + + let mut it = xs.iter().chain(&zs); + assert_eq!(it.nth_back(5), Some(&0)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_chain_last() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + assert_eq!(xs.iter().chain(&ys).last(), Some(&60)); + assert_eq!(zs.iter().chain(&ys).last(), Some(&60)); + assert_eq!(ys.iter().chain(&zs).last(), Some(&60)); + assert_eq!(zs.iter().chain(&zs).last(), None); +} + +#[test] +fn test_iterator_chain_count() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + assert_eq!(xs.iter().chain(&ys).count(), 10); + assert_eq!(zs.iter().chain(&ys).count(), 4); +} + +#[test] +fn test_iterator_chain_find() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let mut iter = xs.iter().chain(&ys); + assert_eq!(iter.find(|&&i| i == 4), Some(&4)); + assert_eq!(iter.next(), Some(&5)); + assert_eq!(iter.find(|&&i| i == 40), Some(&40)); + assert_eq!(iter.next(), Some(&50)); + assert_eq!(iter.find(|&&i| i == 100), None); + assert_eq!(iter.next(), None); +} + +struct Toggle { + is_empty: bool, +} + +impl Iterator for Toggle { + type Item = (); + + // alternates between `None` and `Some(())` + fn next(&mut self) -> Option<Self::Item> { + if self.is_empty { + self.is_empty = false; + None + } else { + self.is_empty = true; + Some(()) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + if self.is_empty { (0, Some(0)) } else { (1, Some(1)) } + } +} + +impl DoubleEndedIterator for Toggle { + fn next_back(&mut self) -> Option<Self::Item> { + self.next() + } +} + +#[test] +fn test_iterator_chain_size_hint() { + // this chains an iterator of length 0 with an iterator of length 1, + // so after calling `.next()` once, the iterator is empty and the + // state is `ChainState::Back`. `.size_hint()` should now disregard + // the size hint of the left iterator + let mut iter = Toggle { is_empty: true }.chain(once(())); + assert_eq!(iter.next(), Some(())); + assert_eq!(iter.size_hint(), (0, Some(0))); + + let mut iter = once(()).chain(Toggle { is_empty: true }); + assert_eq!(iter.next_back(), Some(())); + assert_eq!(iter.size_hint(), (0, Some(0))); +} + +#[test] +fn test_iterator_chain_unfused() { + // Chain shouldn't be fused in its second iterator, depending on direction + let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true }); + iter.next().unwrap_none(); + iter.next().unwrap(); + iter.next().unwrap_none(); + + let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty())); + iter.next_back().unwrap_none(); + iter.next_back().unwrap(); + iter.next_back().unwrap_none(); +} + +#[test] +fn test_zip_nth() { + let xs = [0, 1, 2, 4, 5]; + let ys = [10, 11, 12]; + + let mut it = xs.iter().zip(&ys); + assert_eq!(it.nth(0), Some((&0, &10))); + assert_eq!(it.nth(1), Some((&2, &12))); + assert_eq!(it.nth(0), None); + + let mut it = xs.iter().zip(&ys); + assert_eq!(it.nth(3), None); + + let mut it = ys.iter().zip(&xs); + assert_eq!(it.nth(3), None); +} + +#[test] +fn test_zip_nth_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let value = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })) + .skip(1) + .nth(3); + assert_eq!(value, Some((50, 6000))); + assert_eq!(a, vec![1, 2, 3, 4, 5]); + assert_eq!(b, vec![200, 300, 400, 500, 600]); +} + +#[test] +fn test_zip_next_back_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + // The second iterator is one item longer, so `next_back` is called on it + // one more time. + assert_eq!(iter.next_back(), Some((60, 7000))); + assert_eq!(iter.next_back(), Some((50, 6000))); + assert_eq!(iter.next_back(), Some((40, 5000))); + assert_eq!(iter.next_back(), Some((30, 4000))); + assert_eq!(a, vec![6, 5, 4, 3]); + assert_eq!(b, vec![800, 700, 600, 500, 400]); +} + +#[test] +fn test_zip_nth_back_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let value = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })) + .nth_back(3); + assert_eq!(value, Some((30, 4000))); + assert_eq!(a, vec![6, 5, 4, 3]); + assert_eq!(b, vec![800, 700, 600, 500, 400]); +} + +#[test] +fn test_zip_next_back_side_effects_exhausted() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(iter.next_back(), None); + assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert_eq!(b, vec![200, 300, 400]); +} + +#[derive(Debug)] +struct CountClone(Cell<i32>); + +fn count_clone() -> CountClone { + CountClone(Cell::new(0)) +} + +impl PartialEq<i32> for CountClone { + fn eq(&self, rhs: &i32) -> bool { + self.0.get() == *rhs + } +} + +impl Clone for CountClone { + fn clone(&self) -> Self { + let ret = CountClone(self.0.clone()); + let n = self.0.get(); + self.0.set(n + 1); + ret + } +} + +#[test] +fn test_zip_cloned_sideffectful() { + let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; + let ys = [count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&ys, &[1, 1][..]); + + let xs = [count_clone(), count_clone()]; + let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1][..]); + assert_eq!(&ys, &[1, 1, 0, 0][..]); +} + +#[test] +fn test_zip_map_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&ys, &[1, 1, 1, 1]); + + let mut xs = [0; 4]; + let mut ys = [0; 6]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); +} + +#[test] +fn test_zip_map_rev_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + it.next_back(); + } + assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); + assert_eq!(&ys, &[0, 0, 0, 1]); + + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + (&mut it).take(5).count(); + it.next_back(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1]); +} + +#[test] +fn test_zip_nested_sideffectful() { + let mut xs = [0; 6]; + let ys = [0; 4]; + + { + // test that it has the side effect nested inside enumerate + let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); + it.count(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); +} + +#[test] +fn test_zip_nth_back_side_effects_exhausted() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(iter.nth_back(0), None); + assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert_eq!(b, vec![200, 300, 400]); +} + +#[test] +fn test_zip_trusted_random_access_composition() { + let a = [0, 1, 2, 3, 4]; + let b = a; + let c = a; + + let a = a.iter().copied(); + let b = b.iter().copied(); + let mut c = c.iter().copied(); + c.next(); + + let mut z1 = a.zip(b); + assert_eq!(z1.next().unwrap(), (0, 0)); + + let mut z2 = z1.zip(c); + fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {} + assert_trusted_random_access(&z2); + assert_eq!(z2.next().unwrap(), ((1, 1), 1)); +} + +#[test] +fn test_iterator_step_by() { + // Identity + let mut it = (0..).step_by(1).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + + let mut it = (0..).step_by(3).take(4); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(3)); + assert_eq!(it.next(), Some(6)); + assert_eq!(it.next(), Some(9)); + assert_eq!(it.next(), None); + + let mut it = (0..3).step_by(1); + assert_eq!(it.next_back(), Some(2)); + assert_eq!(it.next_back(), Some(1)); + assert_eq!(it.next_back(), Some(0)); + assert_eq!(it.next_back(), None); + + let mut it = (0..11).step_by(3); + assert_eq!(it.next_back(), Some(9)); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(it.next_back(), Some(3)); + assert_eq!(it.next_back(), Some(0)); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); + + let it = (0..18).step_by(5); + assert_eq!(it.clone().nth(0), Some(0)); + assert_eq!(it.clone().nth(1), Some(5)); + assert_eq!(it.clone().nth(2), Some(10)); + assert_eq!(it.clone().nth(3), Some(15)); + assert_eq!(it.clone().nth(4), None); + assert_eq!(it.clone().nth(42), None); +} + +#[test] +fn test_iterator_step_by_nth_overflow() { + #[cfg(target_pointer_width = "8")] + type Bigger = u16; + #[cfg(target_pointer_width = "16")] + type Bigger = u32; + #[cfg(target_pointer_width = "32")] + type Bigger = u64; + #[cfg(target_pointer_width = "64")] + type Bigger = u128; + + #[derive(Clone)] + struct Test(Bigger); + impl Iterator for &mut Test { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + Some(21) + } + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.0 += n as Bigger + 1; + Some(42) + } + } + + let mut it = Test(0); + let root = usize::MAX >> (usize::BITS / 2); + let n = root + 20; + (&mut it).step_by(n).nth(n); + assert_eq!(it.0, n as Bigger * n as Bigger); + + // large step + let mut it = Test(0); + (&mut it).step_by(usize::MAX).nth(5); + assert_eq!(it.0, (usize::MAX as Bigger) * 5); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(2).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 2); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(1).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 1); +} + +#[test] +fn test_iterator_step_by_nth_try_fold() { + let mut it = (0..).step_by(10); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it.next(), Some(60)); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it.next(), Some(90)); + + let mut it = (100..).step_by(10); + assert_eq!(it.try_fold(50, i8::checked_add), None); + assert_eq!(it.next(), Some(110)); + + let mut it = (100..=100).step_by(10); + assert_eq!(it.next(), Some(100)); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); +} + +#[test] +fn test_iterator_step_by_nth_back() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth_back(0), Some(15)); + assert_eq!(it.nth_back(0), Some(10)); + assert_eq!(it.nth_back(0), Some(5)); + assert_eq!(it.nth_back(0), Some(0)); + assert_eq!(it.nth_back(0), None); + + let mut it = (0..16).step_by(5); + assert_eq!(it.next(), Some(0)); // to set `first_take` to `false` + assert_eq!(it.nth_back(0), Some(15)); + assert_eq!(it.nth_back(0), Some(10)); + assert_eq!(it.nth_back(0), Some(5)); + assert_eq!(it.nth_back(0), None); + + let it = || (0..18).step_by(5); + assert_eq!(it().nth_back(0), Some(15)); + assert_eq!(it().nth_back(1), Some(10)); + assert_eq!(it().nth_back(2), Some(5)); + assert_eq!(it().nth_back(3), Some(0)); + assert_eq!(it().nth_back(4), None); + assert_eq!(it().nth_back(42), None); +} + +#[test] +fn test_iterator_step_by_nth_try_rfold() { + let mut it = (0..100).step_by(10); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it.next_back(), Some(70)); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it.next_back(), Some(30)); + + let mut it = (0..100).step_by(10); + assert_eq!(it.try_rfold(50, i8::checked_add), None); + assert_eq!(it.next_back(), Some(80)); + + let mut it = (100..=100).step_by(10); + assert_eq!(it.next_back(), Some(100)); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); +} + +#[test] +#[should_panic] +fn test_iterator_step_by_zero() { + let mut it = (0..).step_by(0); + it.next(); +} + +#[test] +fn test_iterator_step_by_size_hint() { + struct StubSizeHint(usize, Option<usize>); + impl Iterator for StubSizeHint { + type Item = (); + fn next(&mut self) -> Option<()> { + self.0 -= 1; + if let Some(ref mut upper) = self.1 { + *upper -= 1; + } + Some(()) + } + fn size_hint(&self) -> (usize, Option<usize>) { + (self.0, self.1) + } + } + + // The two checks in each case are needed because the logic + // is different before the first call to `next()`. + + let mut it = StubSizeHint(10, Some(10)).step_by(1); + assert_eq!(it.size_hint(), (10, Some(10))); + it.next(); + assert_eq!(it.size_hint(), (9, Some(9))); + + // exact multiple + let mut it = StubSizeHint(10, Some(10)).step_by(3); + assert_eq!(it.size_hint(), (4, Some(4))); + it.next(); + assert_eq!(it.size_hint(), (3, Some(3))); + + // larger base range, but not enough to get another element + let mut it = StubSizeHint(12, Some(12)).step_by(3); + assert_eq!(it.size_hint(), (4, Some(4))); + it.next(); + assert_eq!(it.size_hint(), (3, Some(3))); + + // smaller base range, so fewer resulting elements + let mut it = StubSizeHint(9, Some(9)).step_by(3); + assert_eq!(it.size_hint(), (3, Some(3))); + it.next(); + assert_eq!(it.size_hint(), (2, Some(2))); + + // infinite upper bound + let mut it = StubSizeHint(usize::MAX, None).step_by(1); + assert_eq!(it.size_hint(), (usize::MAX, None)); + it.next(); + assert_eq!(it.size_hint(), (usize::MAX - 1, None)); + + // still infinite with larger step + let mut it = StubSizeHint(7, None).step_by(3); + assert_eq!(it.size_hint(), (3, None)); + it.next(); + assert_eq!(it.size_hint(), (2, None)); + + // propagates ExactSizeIterator + let a = [1, 2, 3, 4, 5]; + let it = a.iter().step_by(2); + assert_eq!(it.len(), 3); + + // Cannot be TrustedLen as a step greater than one makes an iterator + // with (usize::MAX, None) no longer meet the safety requirements + trait TrustedLenCheck { + fn test(self) -> bool; + } + impl<T: Iterator> TrustedLenCheck for T { + default fn test(self) -> bool { + false + } + } + impl<T: TrustedLen> TrustedLenCheck for T { + fn test(self) -> bool { + true + } + } + assert!(TrustedLenCheck::test(a.iter())); + assert!(!TrustedLenCheck::test(a.iter().step_by(1))); +} + +#[test] +fn test_filter_map() { + let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None }); + assert_eq!(it.collect::<Vec<usize>>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]); +} + +#[test] +fn test_filter_map_fold() { + let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]; + let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_iterator_enumerate() { + let xs = [0, 1, 2, 3, 4, 5]; + let it = xs.iter().enumerate(); + for (i, &x) in it { + assert_eq!(i, x); + } +} + +#[test] +fn test_iterator_enumerate_nth() { + let xs = [0, 1, 2, 3, 4, 5]; + for (i, &x) in xs.iter().enumerate() { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth(0) { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth(1) { + assert_eq!(i, x); + } + + let (i, &x) = xs.iter().enumerate().nth(3).unwrap(); + assert_eq!(i, x); + assert_eq!(i, 3); +} + +#[test] +fn test_iterator_enumerate_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(0) { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(1) { + assert_eq!(i, x); + } + + let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap(); + assert_eq!(i, x); + assert_eq!(i, 2); +} + +#[test] +fn test_iterator_enumerate_count() { + let xs = [0, 1, 2, 3, 4, 5]; + assert_eq!(xs.iter().enumerate().count(), 6); +} + +#[test] +fn test_iterator_enumerate_fold() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + // steal a couple to get an interesting offset + assert_eq!(it.next(), Some((0, &0))); + assert_eq!(it.next(), Some((1, &1))); + let i = it.fold(2, |i, (j, &x)| { + assert_eq!(i, j); + assert_eq!(x, xs[j]); + i + 1 + }); + assert_eq!(i, xs.len()); + + let mut it = xs.iter().enumerate(); + assert_eq!(it.next(), Some((0, &0))); + let i = it.rfold(xs.len() - 1, |i, (j, &x)| { + assert_eq!(i, j); + assert_eq!(x, xs[j]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_iterator_filter_count() { + let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5); +} + +#[test] +fn test_iterator_filter_fold() { + let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let ys = [0, 2, 4, 6, 8]; + let it = xs.iter().filter(|&&x| x % 2 == 0); + let i = it.fold(0, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let it = xs.iter().filter(|&&x| x % 2 == 0); + let i = it.rfold(ys.len(), |i, &x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_iterator_peekable() { + let xs = vec![0, 1, 2, 3, 4, 5]; + + let mut it = xs.iter().cloned().peekable(); + assert_eq!(it.len(), 6); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 6); + assert_eq!(it.next().unwrap(), 0); + assert_eq!(it.len(), 5); + assert_eq!(it.next().unwrap(), 1); + assert_eq!(it.len(), 4); + assert_eq!(it.next().unwrap(), 2); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &3); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &3); + assert_eq!(it.len(), 3); + assert_eq!(it.next().unwrap(), 3); + assert_eq!(it.len(), 2); + assert_eq!(it.next().unwrap(), 4); + assert_eq!(it.len(), 1); + assert_eq!(it.peek().unwrap(), &5); + assert_eq!(it.len(), 1); + assert_eq!(it.next().unwrap(), 5); + assert_eq!(it.len(), 0); + assert!(it.peek().is_none()); + assert_eq!(it.len(), 0); + assert!(it.next().is_none()); + assert_eq!(it.len(), 0); + + let mut it = xs.iter().cloned().peekable(); + assert_eq!(it.len(), 6); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 6); + assert_eq!(it.next_back().unwrap(), 5); + assert_eq!(it.len(), 5); + assert_eq!(it.next_back().unwrap(), 4); + assert_eq!(it.len(), 4); + assert_eq!(it.next_back().unwrap(), 3); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 3); + assert_eq!(it.next_back().unwrap(), 2); + assert_eq!(it.len(), 2); + assert_eq!(it.next_back().unwrap(), 1); + assert_eq!(it.len(), 1); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 1); + assert_eq!(it.next_back().unwrap(), 0); + assert_eq!(it.len(), 0); + assert!(it.peek().is_none()); + assert_eq!(it.len(), 0); + assert!(it.next_back().is_none()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_peekable_count() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [10]; + let zs: [i32; 0] = []; + + assert_eq!(xs.iter().peekable().count(), 6); + + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.count(), 6); + + assert_eq!(ys.iter().peekable().count(), 1); + + let mut it = ys.iter().peekable(); + assert_eq!(it.peek(), Some(&&10)); + assert_eq!(it.count(), 1); + + assert_eq!(zs.iter().peekable().count(), 0); + + let mut it = zs.iter().peekable(); + assert_eq!(it.peek(), None); +} + +#[test] +fn test_iterator_peekable_nth() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().peekable(); + + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.nth(0), Some(&0)); + assert_eq!(it.peek(), Some(&&1)); + assert_eq!(it.nth(1), Some(&2)); + assert_eq!(it.peek(), Some(&&3)); + assert_eq!(it.nth(2), Some(&5)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_peekable_last() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [0]; + + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.last(), Some(&5)); + + let mut it = ys.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.last(), Some(&0)); + + let mut it = ys.iter().peekable(); + assert_eq!(it.next(), Some(&0)); + assert_eq!(it.peek(), None); + assert_eq!(it.last(), None); +} + +#[test] +fn test_iterator_peekable_fold() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + let i = it.fold(0, |i, &x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); +} + +#[test] +fn test_iterator_peekable_rfold() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + let i = it.rfold(0, |i, &x| { + assert_eq!(x, xs[xs.len() - 1 - i]); + i + 1 + }); + assert_eq!(i, xs.len()); +} + +#[test] +fn test_iterator_peekable_next_if_eq() { + // first, try on references + let xs = vec!["Heart", "of", "Gold"]; + let mut it = xs.into_iter().peekable(); + // try before `peek()` + assert_eq!(it.next_if_eq(&"trillian"), None); + assert_eq!(it.next_if_eq(&"Heart"), Some("Heart")); + // try after peek() + assert_eq!(it.peek(), Some(&"of")); + assert_eq!(it.next_if_eq(&"of"), Some("of")); + assert_eq!(it.next_if_eq(&"zaphod"), None); + // make sure `next()` still behaves + assert_eq!(it.next(), Some("Gold")); + + // make sure comparison works for owned values + let xs = vec![String::from("Ludicrous"), "speed".into()]; + let mut it = xs.into_iter().peekable(); + // make sure basic functionality works + assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into())); + assert_eq!(it.next_if_eq("speed"), Some("speed".into())); + assert_eq!(it.next_if_eq(""), None); +} + +#[test] +fn test_iterator_peekable_mut() { + let mut it = vec![1, 2, 3].into_iter().peekable(); + if let Some(p) = it.peek_mut() { + if *p == 1 { + *p = 5; + } + } + assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]); +} + +/// This is an iterator that follows the Iterator contract, +/// but it is not fused. After having returned None once, it will start +/// producing elements if .next() is called again. +pub struct CycleIter<'a, T> { + index: usize, + data: &'a [T], +} + +pub fn cycle<T>(data: &[T]) -> CycleIter<'_, T> { + CycleIter { index: 0, data } +} + +impl<'a, T> Iterator for CycleIter<'a, T> { + type Item = &'a T; + fn next(&mut self) -> Option<Self::Item> { + let elt = self.data.get(self.index); + self.index += 1; + self.index %= 1 + self.data.len(); + elt + } +} + +#[test] +fn test_iterator_peekable_remember_peek_none_1() { + // Check that the loop using .peek() terminates + let data = [1, 2, 3]; + let mut iter = cycle(&data).peekable(); + + let mut n = 0; + while let Some(_) = iter.next() { + let is_the_last = iter.peek().is_none(); + assert_eq!(is_the_last, n == data.len() - 1); + n += 1; + if n > data.len() { + break; + } + } + assert_eq!(n, data.len()); +} + +#[test] +fn test_iterator_peekable_remember_peek_none_2() { + let data = [0]; + let mut iter = cycle(&data).peekable(); + iter.next(); + assert_eq!(iter.peek(), None); + assert_eq!(iter.last(), None); +} + +#[test] +fn test_iterator_peekable_remember_peek_none_3() { + let data = [0]; + let mut iter = cycle(&data).peekable(); + iter.peek(); + assert_eq!(iter.nth(0), Some(&0)); + + let mut iter = cycle(&data).peekable(); + iter.next(); + assert_eq!(iter.peek(), None); + assert_eq!(iter.nth(0), None); +} + +#[test] +fn test_iterator_take_while() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0, 1, 2, 3, 5, 13]; + let it = xs.iter().take_while(|&x| *x < 15); + let mut i = 0; + for x in it { + assert_eq!(*x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +#[test] +fn test_iterator_skip_while() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [15, 16, 17, 19]; + let it = xs.iter().skip_while(|&x| *x < 15); + let mut i = 0; + for x in it { + assert_eq!(*x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +#[test] +fn test_iterator_skip_while_fold() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [15, 16, 17, 19]; + let it = xs.iter().skip_while(|&x| *x < 15); + let i = it.fold(0, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().skip_while(|&x| *x < 15); + assert_eq!(it.next(), Some(&ys[0])); // process skips before folding + let i = it.fold(1, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); +} + +#[test] +fn test_iterator_skip() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let ys = [13, 15, 16, 17, 19, 20, 30]; + let mut it = xs.iter().skip(5); + let mut i = 0; + while let Some(&x) = it.next() { + assert_eq!(x, ys[i]); + i += 1; + assert_eq!(it.len(), xs.len() - 5 - i); + } + assert_eq!(i, ys.len()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_skip_doubleended() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let mut it = xs.iter().rev().skip(5); + assert_eq!(it.next(), Some(&15)); + assert_eq!(it.by_ref().rev().next(), Some(&0)); + assert_eq!(it.next(), Some(&13)); + assert_eq!(it.by_ref().rev().next(), Some(&1)); + assert_eq!(it.next(), Some(&5)); + assert_eq!(it.by_ref().rev().next(), Some(&2)); + assert_eq!(it.next(), Some(&3)); + assert_eq!(it.next(), None); + let mut it = xs.iter().rev().skip(5).rev(); + assert_eq!(it.next(), Some(&0)); + assert_eq!(it.rev().next(), Some(&15)); + let mut it_base = xs.iter(); + { + let mut it = it_base.by_ref().skip(5).rev(); + assert_eq!(it.next(), Some(&30)); + assert_eq!(it.next(), Some(&20)); + assert_eq!(it.next(), Some(&19)); + assert_eq!(it.next(), Some(&17)); + assert_eq!(it.next(), Some(&16)); + assert_eq!(it.next(), Some(&15)); + assert_eq!(it.next(), Some(&13)); + assert_eq!(it.next(), None); + } + // make sure the skipped parts have not been consumed + assert_eq!(it_base.next(), Some(&0)); + assert_eq!(it_base.next(), Some(&1)); + assert_eq!(it_base.next(), Some(&2)); + assert_eq!(it_base.next(), Some(&3)); + assert_eq!(it_base.next(), Some(&5)); + assert_eq!(it_base.next(), None); + let it = xs.iter().skip(5).rev(); + assert_eq!(it.last(), Some(&13)); +} + +#[test] +fn test_iterator_skip_nth() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + + let mut it = xs.iter().skip(0); + assert_eq!(it.nth(0), Some(&0)); + assert_eq!(it.nth(1), Some(&2)); + + let mut it = xs.iter().skip(5); + assert_eq!(it.nth(0), Some(&13)); + assert_eq!(it.nth(1), Some(&16)); + + let mut it = xs.iter().skip(12); + assert_eq!(it.nth(0), None); +} + +#[test] +fn test_iterator_skip_count() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + + assert_eq!(xs.iter().skip(0).count(), 12); + assert_eq!(xs.iter().skip(1).count(), 11); + assert_eq!(xs.iter().skip(11).count(), 1); + assert_eq!(xs.iter().skip(12).count(), 0); + assert_eq!(xs.iter().skip(13).count(), 0); +} + +#[test] +fn test_iterator_skip_last() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + + assert_eq!(xs.iter().skip(0).last(), Some(&30)); + assert_eq!(xs.iter().skip(1).last(), Some(&30)); + assert_eq!(xs.iter().skip(11).last(), Some(&30)); + assert_eq!(xs.iter().skip(12).last(), None); + assert_eq!(xs.iter().skip(13).last(), None); + + let mut it = xs.iter().skip(5); + assert_eq!(it.next(), Some(&13)); + assert_eq!(it.last(), Some(&30)); +} + +#[test] +fn test_iterator_skip_fold() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let ys = [13, 15, 16, 17, 19, 20, 30]; + + let it = xs.iter().skip(5); + let i = it.fold(0, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().skip(5); + assert_eq!(it.next(), Some(&ys[0])); // process skips before folding + let i = it.fold(1, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let it = xs.iter().skip(5); + let i = it.rfold(ys.len(), |i, &x| { + let i = i - 1; + assert_eq!(x, ys[i]); + i + }); + assert_eq!(i, 0); + + let mut it = xs.iter().skip(5); + assert_eq!(it.next(), Some(&ys[0])); // process skips before folding + let i = it.rfold(ys.len(), |i, &x| { + let i = i - 1; + assert_eq!(x, ys[i]); + i + }); + assert_eq!(i, 1); +} + +#[test] +fn test_iterator_take() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0, 1, 2, 3, 5]; + + let mut it = xs.iter().take(ys.len()); + let mut i = 0; + assert_eq!(it.len(), ys.len()); + while let Some(&x) = it.next() { + assert_eq!(x, ys[i]); + i += 1; + assert_eq!(it.len(), ys.len() - i); + } + assert_eq!(i, ys.len()); + assert_eq!(it.len(), 0); + + let mut it = xs.iter().take(ys.len()); + let mut i = 0; + assert_eq!(it.len(), ys.len()); + while let Some(&x) = it.next_back() { + i += 1; + assert_eq!(x, ys[ys.len() - i]); + assert_eq!(it.len(), ys.len() - i); + } + assert_eq!(i, ys.len()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_take_nth() { + let xs = [0, 1, 2, 4, 5]; + let mut it = xs.iter(); + { + let mut take = it.by_ref().take(3); + let mut i = 0; + while let Some(&x) = take.nth(0) { + assert_eq!(x, i); + i += 1; + } + } + assert_eq!(it.nth(1), Some(&5)); + assert_eq!(it.nth(0), None); + + let xs = [0, 1, 2, 3, 4]; + let mut it = xs.iter().take(7); + let mut i = 1; + while let Some(&x) = it.nth(1) { + assert_eq!(x, i); + i += 2; + } +} + +#[test] +fn test_iterator_take_nth_back() { + let xs = [0, 1, 2, 4, 5]; + let mut it = xs.iter(); + { + let mut take = it.by_ref().take(3); + let mut i = 0; + while let Some(&x) = take.nth_back(0) { + i += 1; + assert_eq!(x, 3 - i); + } + } + assert_eq!(it.nth_back(0), None); + + let xs = [0, 1, 2, 3, 4]; + let mut it = xs.iter().take(7); + assert_eq!(it.nth_back(1), Some(&3)); + assert_eq!(it.nth_back(1), Some(&1)); + assert_eq!(it.nth_back(1), None); +} + +#[test] +fn test_iterator_take_short() { + let xs = [0, 1, 2, 3]; + + let mut it = xs.iter().take(5); + let mut i = 0; + assert_eq!(it.len(), xs.len()); + while let Some(&x) = it.next() { + assert_eq!(x, xs[i]); + i += 1; + assert_eq!(it.len(), xs.len() - i); + } + assert_eq!(i, xs.len()); + assert_eq!(it.len(), 0); + + let mut it = xs.iter().take(5); + let mut i = 0; + assert_eq!(it.len(), xs.len()); + while let Some(&x) = it.next_back() { + i += 1; + assert_eq!(x, xs[xs.len() - i]); + assert_eq!(it.len(), xs.len() - i); + } + assert_eq!(i, xs.len()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_scan() { + // test the type inference + fn add(old: &mut isize, new: &usize) -> Option<f64> { + *old += *new as isize; + Some(*old as f64) + } + let xs = [0, 1, 2, 3, 4]; + let ys = [0f64, 1.0, 3.0, 6.0, 10.0]; + + let it = xs.iter().scan(0, add); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +#[test] +fn test_iterator_flat_map() { + let xs = [0, 3, 6]; + let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3)); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +/// Tests `FlatMap::fold` with items already picked off the front and back, +/// to make sure all parts of the `FlatMap` are folded correctly. +#[test] +fn test_iterator_flat_map_fold() { + let xs = [0, 3, 6]; + let ys = [1, 2, 3, 4, 5, 6, 7]; + let mut it = xs.iter().flat_map(|&x| x..x + 3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().flat_map(|&x| x..x + 3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_iterator_flatten() { + let xs = [0, 3, 6]; + let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten(); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +/// Tests `Flatten::fold` with items already picked off the front and back, +/// to make sure all parts of the `Flatten` are folded correctly. +#[test] +fn test_iterator_flatten_fold() { + let xs = [0, 3, 6]; + let ys = [1, 2, 3, 4, 5, 6, 7]; + let mut it = xs.iter().map(|&x| x..x + 3).flatten(); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().map(|&x| x..x + 3).flatten(); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_inspect() { + let xs = [1, 2, 3, 4]; + let mut n = 0; + + let ys = xs.iter().cloned().inspect(|_| n += 1).collect::<Vec<usize>>(); + + assert_eq!(n, xs.len()); + assert_eq!(&xs[..], &ys[..]); +} + +#[test] +fn test_inspect_fold() { + let xs = [1, 2, 3, 4]; + let mut n = 0; + { + let it = xs.iter().inspect(|_| n += 1); + let i = it.fold(0, |i, &x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); + } + assert_eq!(n, xs.len()); + + let mut n = 0; + { + let it = xs.iter().inspect(|_| n += 1); + let i = it.rfold(xs.len(), |i, &x| { + assert_eq!(x, xs[i - 1]); + i - 1 + }); + assert_eq!(i, 0); + } + assert_eq!(n, xs.len()); +} + +#[test] +fn test_cycle() { + let cycle_len = 3; + let it = (0..).step_by(1).take(cycle_len).cycle(); + assert_eq!(it.size_hint(), (usize::MAX, None)); + for (i, x) in it.take(100).enumerate() { + assert_eq!(i % cycle_len, x); + } + + let mut it = (0..).step_by(1).take(0).cycle(); + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None); + + assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0); + + assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4); + + assert_eq!((0..10).cycle().take(5).sum::<i32>(), 10); + assert_eq!((0..10).cycle().take(15).sum::<i32>(), 55); + assert_eq!((0..10).cycle().take(25).sum::<i32>(), 100); + + let mut iter = (0..10).cycle(); + iter.nth(14); + assert_eq!(iter.take(8).sum::<i32>(), 38); + + let mut iter = (0..10).cycle(); + iter.nth(9); + assert_eq!(iter.take(3).sum::<i32>(), 3); +} + +#[test] +fn test_iterator_nth() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth(i).unwrap(), &v[i]); + } + assert_eq!(v.iter().nth(v.len()), None); +} + +#[test] +fn test_iterator_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]); + } + assert_eq!(v.iter().nth_back(v.len()), None); +} + +#[test] +fn test_iterator_rev_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]); + } + assert_eq!(v.iter().rev().nth_back(v.len()), None); +} + +#[test] +fn test_iterator_rev_nth() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]); + } + assert_eq!(v.iter().rev().nth(v.len()), None); +} + +#[test] +fn test_iterator_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[i]); + assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_back_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_rev_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_rev_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[i]); + assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_last() { + let v: &[_] = &[0, 1, 2, 3, 4]; + assert_eq!(v.iter().last().unwrap(), &4); + assert_eq!(v[..1].iter().last().unwrap(), &0); +} + +#[test] +fn test_iterator_len() { + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().count(), 4); + assert_eq!(v[..10].iter().count(), 10); + assert_eq!(v[..0].iter().count(), 0); +} + +#[test] +fn test_iterator_sum() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().sum::<i32>(), 6); + assert_eq!(v.iter().cloned().sum::<i32>(), 55); + assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0); +} + +#[test] +fn test_iterator_sum_result() { + let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10)); + let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(())); + + #[derive(PartialEq, Debug)] + struct S(Result<i32, ()>); + + impl Sum<Result<i32, ()>> for S { + fn sum<I: Iterator<Item = Result<i32, ()>>>(mut iter: I) -> Self { + // takes the sum by repeatedly calling `next` on `iter`, + // thus testing that repeated calls to `ResultShunt::try_fold` + // produce the expected results + Self(iter.by_ref().sum()) + } + } + + let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::<S>(), S(Ok(10))); + let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::<S>(), S(Err(()))); +} + +#[test] +fn test_iterator_sum_option() { + let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)]; + assert_eq!(v.iter().cloned().sum::<Option<i32>>(), Some(10)); + let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)]; + assert_eq!(v.iter().cloned().sum::<Option<i32>>(), None); +} + +#[test] +fn test_iterator_product() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().product::<i32>(), 0); + assert_eq!(v[1..5].iter().cloned().product::<i32>(), 24); + assert_eq!(v[..0].iter().cloned().product::<i32>(), 1); +} + +#[test] +fn test_iterator_product_result() { + let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24)); + let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(())); +} + +/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped +/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min` +/// return the correct element if some of them are equal. +#[derive(Debug)] +struct Mod3(i32); + +impl PartialEq for Mod3 { + fn eq(&self, other: &Self) -> bool { + self.0 % 3 == other.0 % 3 + } +} + +impl Eq for Mod3 {} + +impl PartialOrd for Mod3 { + fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Mod3 { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + (self.0 % 3).cmp(&(other.0 % 3)) + } +} + +#[test] +fn test_iterator_product_option() { + let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)]; + assert_eq!(v.iter().cloned().product::<Option<i32>>(), Some(24)); + let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)]; + assert_eq!(v.iter().cloned().product::<Option<i32>>(), None); +} + +#[test] +fn test_iterator_max() { + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().max(), Some(3)); + assert_eq!(v.iter().cloned().max(), Some(10)); + assert_eq!(v[..0].iter().cloned().max(), None); + assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8)); +} + +#[test] +fn test_iterator_min() { + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().min(), Some(0)); + assert_eq!(v.iter().cloned().min(), Some(0)); + assert_eq!(v[..0].iter().cloned().min(), None); + assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0)); +} + +#[test] +fn test_iterator_size_hint() { + let c = (0..).step_by(1); + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let v2 = &[10, 11, 12]; + let vi = v.iter(); + + assert_eq!((0..).size_hint(), (usize::MAX, None)); + assert_eq!(c.size_hint(), (usize::MAX, None)); + assert_eq!(vi.clone().size_hint(), (10, Some(10))); + + assert_eq!(c.clone().take(5).size_hint(), (5, Some(5))); + assert_eq!(c.clone().skip(5).size_hint().1, None); + assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None)); + assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None)); + assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None)); + assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); + assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None)); + assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None)); + assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); + + assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5))); + assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10))); + assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7))); + assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0))); + assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); + assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13))); + assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3))); + assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10))); + assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); +} + +#[test] +fn test_collect() { + let a = vec![1, 2, 3, 4, 5]; + let b: Vec<isize> = a.iter().cloned().collect(); + assert!(a == b); +} + +#[test] +fn test_all() { + let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); + assert!(v.iter().all(|&x| x < 10)); + assert!(!v.iter().all(|&x| x % 2 == 0)); + assert!(!v.iter().all(|&x| x > 100)); + assert!(v[..0].iter().all(|_| panic!())); +} + +#[test] +fn test_any() { + let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); + assert!(v.iter().any(|&x| x < 10)); + assert!(v.iter().any(|&x| x % 2 == 0)); + assert!(!v.iter().any(|&x| x > 100)); + assert!(!v[..0].iter().any(|_| panic!())); +} + +#[test] +fn test_find() { + let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11]; + assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14); + assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3); + assert!(v.iter().find(|&&x| x % 12 == 0).is_none()); +} + +#[test] +fn test_find_map() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[3, 5]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[4, 5]; + assert_eq!(xs.iter().find_map(half_if_even), Some(2)); + let xs: &[isize] = &[3, 6]; + assert_eq!(xs.iter().find_map(half_if_even), Some(3)); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.find_map(half_if_even), Some(1)); + assert_eq!(iter.find_map(half_if_even), Some(2)); + assert_eq!(iter.find_map(half_if_even), Some(3)); + assert_eq!(iter.next(), Some(&7)); + + fn half_if_even(x: &isize) -> Option<isize> { + if x % 2 == 0 { Some(x / 2) } else { None } + } +} + +#[test] +fn test_try_find() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().try_find(testfn), Ok(None)); + let xs: &[isize] = &[1, 2, 3, 4]; + assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2))); + let xs: &[isize] = &[1, 3, 4]; + assert_eq!(xs.iter().try_find(testfn), Err(())); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.try_find(testfn), Ok(Some(&2))); + assert_eq!(iter.try_find(testfn), Err(())); + assert_eq!(iter.next(), Some(&5)); + + fn testfn(x: &&isize) -> Result<bool, ()> { + if **x == 2 { + return Ok(true); + } + if **x == 4 { + return Err(()); + } + Ok(false) + } +} + +#[test] +fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> { + let a = ["1", "2"]; + + let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> { + Ok(s.parse::<i32>()? == search) + }; + + let val = a.iter().try_find(|&&s| is_my_num(s, 2))?; + assert_eq!(val, Some(&"2")); + + Ok(()) +} + +#[test] +fn test_position() { + let v = &[1, 3, 9, 27, 103, 14, 11]; + assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5); + assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1); + assert!(v.iter().position(|x| *x % 12 == 0).is_none()); +} + +#[test] +fn test_count() { + let xs = &[1, 2, 2, 1, 5, 9, 0, 2]; + assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3); + assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1); + assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0); +} + +#[test] +fn test_max_by_key() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10); +} + +#[test] +fn test_max_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10); +} + +#[test] +fn test_min_by_key() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0); +} + +#[test] +fn test_min_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0); +} + +#[test] +fn test_by_ref() { + let mut xs = 0..10; + // sum the first five values + let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b); + assert_eq!(partial_sum, 10); + assert_eq!(xs.next(), Some(5)); +} + +#[test] +fn test_rev() { + let xs = [2, 4, 6, 8, 10, 12, 14, 16]; + let mut it = xs.iter(); + it.next(); + it.next(); + assert!(it.rev().cloned().collect::<Vec<isize>>() == vec![16, 14, 12, 10, 8, 6]); +} + +#[test] +fn test_copied() { + let xs = [2, 4, 6, 8]; + + let mut it = xs.iter().copied(); + assert_eq!(it.len(), 4); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.len(), 2); + assert_eq!(it.next_back(), Some(8)); + assert_eq!(it.len(), 1); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(it.len(), 0); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_cloned() { + let xs = [2, 4, 6, 8]; + + let mut it = xs.iter().cloned(); + assert_eq!(it.len(), 4); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.len(), 2); + assert_eq!(it.next_back(), Some(8)); + assert_eq!(it.len(), 1); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(it.len(), 0); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_cloned_side_effects() { + let mut count = 0; + { + let iter = [1, 2, 3] + .iter() + .map(|x| { + count += 1; + x + }) + .cloned() + .zip(&[1]); + for _ in iter {} + } + assert_eq!(count, 2); +} + +#[test] +fn test_double_ended_map() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().map(|&x| x * -1); + assert_eq!(it.next(), Some(-1)); + assert_eq!(it.next(), Some(-2)); + assert_eq!(it.next_back(), Some(-6)); + assert_eq!(it.next_back(), Some(-5)); + assert_eq!(it.next(), Some(-3)); + assert_eq!(it.next_back(), Some(-4)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_double_ended_enumerate() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().cloned().enumerate(); + assert_eq!(it.next(), Some((0, 1))); + assert_eq!(it.next(), Some((1, 2))); + assert_eq!(it.next_back(), Some((5, 6))); + assert_eq!(it.next_back(), Some((4, 5))); + assert_eq!(it.next_back(), Some((3, 4))); + assert_eq!(it.next_back(), Some((2, 3))); + assert_eq!(it.next(), None); +} + +#[test] +fn test_double_ended_zip() { + let xs = [1, 2, 3, 4, 5, 6]; + let ys = [1, 2, 3, 7]; + let a = xs.iter().cloned(); + let b = ys.iter().cloned(); + let mut it = a.zip(b); + assert_eq!(it.next(), Some((1, 1))); + assert_eq!(it.next(), Some((2, 2))); + assert_eq!(it.next_back(), Some((4, 7))); + assert_eq!(it.next_back(), Some((3, 3))); + assert_eq!(it.next(), None); +} + +#[test] +fn test_double_ended_filter() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().filter(|&x| *x & 1 == 0); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &4); + assert_eq!(it.next().unwrap(), &2); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_double_ended_filter_map() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None }); + assert_eq!(it.next_back().unwrap(), 12); + assert_eq!(it.next_back().unwrap(), 8); + assert_eq!(it.next().unwrap(), 4); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_double_ended_chain() { + let xs = [1, 2, 3, 4, 5]; + let ys = [7, 9, 11]; + let mut it = xs.iter().chain(&ys).rev(); + assert_eq!(it.next().unwrap(), &11); + assert_eq!(it.next().unwrap(), &9); + assert_eq!(it.next_back().unwrap(), &1); + assert_eq!(it.next_back().unwrap(), &2); + assert_eq!(it.next_back().unwrap(), &3); + assert_eq!(it.next_back().unwrap(), &4); + assert_eq!(it.next_back().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + + // test that .chain() is well behaved with an unfused iterator + struct CrazyIterator(bool); + impl CrazyIterator { + fn new() -> CrazyIterator { + CrazyIterator(false) + } + } + impl Iterator for CrazyIterator { + type Item = i32; + fn next(&mut self) -> Option<i32> { + if self.0 { + Some(99) + } else { + self.0 = true; + None + } + } + } + + impl DoubleEndedIterator for CrazyIterator { + fn next_back(&mut self) -> Option<i32> { + self.next() + } + } + + assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0)); + assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0)); +} + +#[test] +fn test_rposition() { + fn f(xy: &(isize, char)) -> bool { + let (_x, y) = *xy; + y == 'b' + } + fn g(xy: &(isize, char)) -> bool { + let (_x, y) = *xy; + y == 'd' + } + let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + + assert_eq!(v.iter().rposition(f), Some(3)); + assert!(v.iter().rposition(g).is_none()); +} + +#[test] +fn test_rev_rposition() { + let v = [0, 0, 1, 1]; + assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1)); +} + +#[test] +#[should_panic] +fn test_rposition_panic() { + let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), (box 0, box 0), (box 0, box 0)]; + let mut i = 0; + v.iter().rposition(|_elt| { + if i == 2 { + panic!() + } + i += 1; + false + }); +} + +#[test] +fn test_double_ended_flat_map() { + let u = [0, 1]; + let v = [5, 6, 7, 8]; + let mut it = u.iter().flat_map(|x| &v[*x..v.len()]); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_double_ended_flatten() { + let u = [0, 1]; + let v = [5, 6, 7, 8]; + let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten(); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_double_ended_range() { + assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]); + for _ in (10..0).rev() { + panic!("unreachable"); + } + + assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]); + for _ in (10..0).rev() { + panic!("unreachable"); + } +} + +#[test] +fn test_range() { + assert_eq!((0..5).collect::<Vec<_>>(), [0, 1, 2, 3, 4]); + assert_eq!((-10..-1).collect::<Vec<_>>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]); + assert_eq!((0..5).rev().collect::<Vec<_>>(), [4, 3, 2, 1, 0]); + assert_eq!((200..-5).count(), 0); + assert_eq!((200..-5).rev().count(), 0); + assert_eq!((200..200).count(), 0); + assert_eq!((200..200).rev().count(), 0); + + assert_eq!((0..100).size_hint(), (100, Some(100))); + // this test is only meaningful when sizeof usize < sizeof u64 + assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1))); + assert_eq!((-10..-1).size_hint(), (9, Some(9))); + assert_eq!((-1..-10).size_hint(), (0, Some(0))); + + assert_eq!((-70..58).size_hint(), (128, Some(128))); + assert_eq!((-128..127).size_hint(), (255, Some(255))); + assert_eq!( + (-2..isize::MAX).size_hint(), + (isize::MAX as usize + 2, Some(isize::MAX as usize + 2)) + ); +} + +#[test] +fn test_char_range() { + use std::char; + // Miri is too slow + let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' }; + let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX }; + assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32))); + assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev())); + + assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); + assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2))); + assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1); + assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1))); +} + +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + +#[test] +fn test_range_inclusive_exhaustion() { + let mut r = 10..=10; + assert_eq!(r.next(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); + + assert_eq!(*r.start(), 10); + assert_eq!(*r.end(), 10); + assert_ne!(r, 10..=10); + + let mut r = 10..=10; + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + + assert_eq!(*r.start(), 10); + assert_eq!(*r.end(), 10); + assert_ne!(r, 10..=10); + + let mut r = 10..=12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert_eq!(r.next(), Some(12)); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + + let mut r = 10..=12; + assert_eq!(r.next_back(), Some(12)); + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + + let mut r = 10..=12; + assert_eq!(r.nth(2), Some(12)); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + + let mut r = 10..=12; + assert_eq!(r.nth(5), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + + let mut r = 100..=10; + assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); + assert_eq!(r, 100..=10); + + let mut r = 100..=10; + assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..=10); +} + +#[test] +fn test_range_nth() { + assert_eq!((10..15).nth(0), Some(10)); + assert_eq!((10..15).nth(1), Some(11)); + assert_eq!((10..15).nth(4), Some(14)); + assert_eq!((10..15).nth(5), None); + + let mut r = 10..20; + assert_eq!(r.nth(2), Some(12)); + assert_eq!(r, 13..20); + assert_eq!(r.nth(2), Some(15)); + assert_eq!(r, 16..20); + assert_eq!(r.nth(10), None); + assert_eq!(r, 20..20); +} + +#[test] +fn test_range_nth_back() { + assert_eq!((10..15).nth_back(0), Some(14)); + assert_eq!((10..15).nth_back(1), Some(13)); + assert_eq!((10..15).nth_back(4), Some(10)); + assert_eq!((10..15).nth_back(5), None); + assert_eq!((-120..80_i8).nth_back(199), Some(-120)); + + let mut r = 10..20; + assert_eq!(r.nth_back(2), Some(17)); + assert_eq!(r, 10..17); + assert_eq!(r.nth_back(2), Some(14)); + assert_eq!(r, 10..14); + assert_eq!(r.nth_back(10), None); + assert_eq!(r, 10..10); +} + +#[test] +fn test_range_from_nth() { + assert_eq!((10..).nth(0), Some(10)); + assert_eq!((10..).nth(1), Some(11)); + assert_eq!((10..).nth(4), Some(14)); + + let mut r = 10..; + assert_eq!(r.nth(2), Some(12)); + assert_eq!(r, 13..); + assert_eq!(r.nth(2), Some(15)); + assert_eq!(r, 16..); + assert_eq!(r.nth(10), Some(26)); + assert_eq!(r, 27..); + + assert_eq!((0..).size_hint(), (usize::MAX, None)); +} + +fn is_trusted_len<I: TrustedLen>(_: I) {} + +#[test] +fn test_range_from_take() { + let mut it = (0..).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + is_trusted_len((0..).take(3)); + assert_eq!((0..).take(3).size_hint(), (3, Some(3))); + assert_eq!((0..).take(0).size_hint(), (0, Some(0))); + assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_range_from_take_collect() { + let v: Vec<_> = (0..).take(3).collect(); + assert_eq!(v, vec![0, 1, 2]); +} + +#[test] +fn test_range_inclusive_nth() { + assert_eq!((10..=15).nth(0), Some(10)); + assert_eq!((10..=15).nth(1), Some(11)); + assert_eq!((10..=15).nth(5), Some(15)); + assert_eq!((10..=15).nth(6), None); + + let mut exhausted_via_next = 10_u8..=20; + while exhausted_via_next.next().is_some() {} + + let mut r = 10_u8..=20; + assert_eq!(r.nth(2), Some(12)); + assert_eq!(r, 13..=20); + assert_eq!(r.nth(2), Some(15)); + assert_eq!(r, 16..=20); + assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); + assert_eq!(r.nth(10), None); + assert_eq!(r.is_empty(), true); + assert_eq!(r, exhausted_via_next); + assert_eq!(ExactSizeIterator::is_empty(&r), true); +} + +#[test] +fn test_range_inclusive_nth_back() { + assert_eq!((10..=15).nth_back(0), Some(15)); + assert_eq!((10..=15).nth_back(1), Some(14)); + assert_eq!((10..=15).nth_back(5), Some(10)); + assert_eq!((10..=15).nth_back(6), None); + assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); + + let mut exhausted_via_next_back = 10_u8..=20; + while exhausted_via_next_back.next_back().is_some() {} + + let mut r = 10_u8..=20; + assert_eq!(r.nth_back(2), Some(18)); + assert_eq!(r, 10..=17); + assert_eq!(r.nth_back(2), Some(15)); + assert_eq!(r, 10..=14); + assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); + assert_eq!(r.nth_back(10), None); + assert_eq!(r.is_empty(), true); + assert_eq!(r, exhausted_via_next_back); + assert_eq!(ExactSizeIterator::is_empty(&r), true); +} + +#[test] +fn test_range_len() { + assert_eq!((0..10_u8).len(), 10); + assert_eq!((9..10_u8).len(), 1); + assert_eq!((10..10_u8).len(), 0); + assert_eq!((11..10_u8).len(), 0); + assert_eq!((100..10_u8).len(), 0); +} + +#[test] +fn test_range_inclusive_len() { + assert_eq!((0..=10_u8).len(), 11); + assert_eq!((9..=10_u8).len(), 2); + assert_eq!((10..=10_u8).len(), 1); + assert_eq!((11..=10_u8).len(), 0); + assert_eq!((100..=10_u8).len(), 0); +} + +#[test] +fn test_range_step() { + #![allow(deprecated)] + + assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]); + assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]); + assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]); + assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]); + assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []); + assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []); + + assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20))); + assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1))); + assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4))); + assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4))); + assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4))); + assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); + assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); + assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2))); + assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3))); + assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_step_by_skip() { + assert_eq!((0..640).step_by(128).skip(1).collect::<Vec<_>>(), [128, 256, 384, 512]); + assert_eq!((0..=50).step_by(10).nth(3), Some(30)); + assert_eq!((200..=255u8).step_by(10).nth(3), Some(230)); +} + +#[test] +fn test_range_inclusive_step() { + assert_eq!((0..=50).step_by(10).collect::<Vec<_>>(), [0, 10, 20, 30, 40, 50]); + assert_eq!((0..=5).step_by(1).collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5]); + assert_eq!((200..=255u8).step_by(10).collect::<Vec<_>>(), [200, 210, 220, 230, 240, 250]); + assert_eq!((250..=255u8).step_by(1).collect::<Vec<_>>(), [250, 251, 252, 253, 254, 255]); +} + +#[test] +fn test_range_last_max() { + assert_eq!((0..20).last(), Some(19)); + assert_eq!((-20..0).last(), Some(-1)); + assert_eq!((5..5).last(), None); + + assert_eq!((0..20).max(), Some(19)); + assert_eq!((-20..0).max(), Some(-1)); + assert_eq!((5..5).max(), None); +} + +#[test] +fn test_range_inclusive_last_max() { + assert_eq!((0..=20).last(), Some(20)); + assert_eq!((-20..=0).last(), Some(0)); + assert_eq!((5..=5).last(), Some(5)); + let mut r = 10..=10; + r.next(); + assert_eq!(r.last(), None); + + assert_eq!((0..=20).max(), Some(20)); + assert_eq!((-20..=0).max(), Some(0)); + assert_eq!((5..=5).max(), Some(5)); + let mut r = 10..=10; + r.next(); + assert_eq!(r.max(), None); +} + +#[test] +fn test_range_min() { + assert_eq!((0..20).min(), Some(0)); + assert_eq!((-20..0).min(), Some(-20)); + assert_eq!((5..5).min(), None); +} + +#[test] +fn test_range_inclusive_min() { + assert_eq!((0..=20).min(), Some(0)); + assert_eq!((-20..=0).min(), Some(-20)); + assert_eq!((5..=5).min(), Some(5)); + let mut r = 10..=10; + r.next(); + assert_eq!(r.min(), None); +} + +#[test] +fn test_range_inclusive_folds() { + assert_eq!((1..=10).sum::<i32>(), 55); + assert_eq!((1..=10).rev().sum::<i32>(), 55); + + let mut it = 44..=50; + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it, 47..=50); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it, 50..=50); + assert_eq!(it.try_fold(0, i8::checked_add), Some(50)); + assert!(it.is_empty()); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); + assert!(it.is_empty()); + + let mut it = 40..=47; + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it, 40..=44); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it, 40..=41); + assert_eq!(it.try_rfold(0, i8::checked_add), Some(81)); + assert!(it.is_empty()); + assert_eq!(it.try_rfold(0, i8::checked_add), Some(0)); + assert!(it.is_empty()); + + let mut it = 10..=20; + assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165)); + assert!(it.is_empty()); + assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0)); + assert!(it.is_empty()); + + let mut it = 10..=20; + assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165)); + assert!(it.is_empty()); + assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0)); + assert!(it.is_empty()); +} + +#[test] +fn test_range_size_hint() { + assert_eq!((0..0usize).size_hint(), (0, Some(0))); + assert_eq!((0..100usize).size_hint(), (100, Some(100))); + assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); + + let umax = u128::try_from(usize::MAX).unwrap(); + assert_eq!((0..0u128).size_hint(), (0, Some(0))); + assert_eq!((0..100u128).size_hint(), (100, Some(100))); + assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None)); + + assert_eq!((0..0isize).size_hint(), (0, Some(0))); + assert_eq!((-100..100isize).size_hint(), (200, Some(200))); + assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); + + let imin = i128::try_from(isize::MIN).unwrap(); + let imax = i128::try_from(isize::MAX).unwrap(); + assert_eq!((0..0i128).size_hint(), (0, Some(0))); + assert_eq!((-100..100i128).size_hint(), (200, Some(200))); + assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_range_inclusive_size_hint() { + assert_eq!((1..=0usize).size_hint(), (0, Some(0))); + assert_eq!((0..=0usize).size_hint(), (1, Some(1))); + assert_eq!((0..=100usize).size_hint(), (101, Some(101))); + assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None)); + + let umax = u128::try_from(usize::MAX).unwrap(); + assert_eq!((1..=0u128).size_hint(), (0, Some(0))); + assert_eq!((0..=0u128).size_hint(), (1, Some(1))); + assert_eq!((0..=100u128).size_hint(), (101, Some(101))); + assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((0..=umax).size_hint(), (usize::MAX, None)); + assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None)); + + assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); + assert_eq!((0..=0isize).size_hint(), (1, Some(1))); + assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); + assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None)); + + let imin = i128::try_from(isize::MIN).unwrap(); + let imax = i128::try_from(isize::MAX).unwrap(); + assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); + assert_eq!((0..=0i128).size_hint(), (1, Some(1))); + assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); + assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((imin..=imax).size_hint(), (usize::MAX, None)); + assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat() { + let mut it = repeat(42); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(repeat(42).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_take() { + let mut it = repeat(42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat(42).take(3)); + assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let v: Vec<_> = repeat(42).take(3).collect(); + assert_eq!(v, vec![42, 42, 42]); +} + +#[test] +fn test_repeat_with() { + #[derive(PartialEq, Debug)] + struct NotClone(usize); + let mut it = repeat_with(|| NotClone(42)); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_with_take() { + let mut it = repeat_with(|| 42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat_with(|| 42).take(3)); + assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_with_take_collect() { + let mut curr = 1; + let v: Vec<_> = repeat_with(|| { + let tmp = curr; + curr *= 2; + tmp + }) + .take(5) + .collect(); + assert_eq!(v, vec![1, 2, 4, 8, 16]); +} + +#[test] +fn test_successors() { + let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); + assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]); + assert_eq!(powers_of_10.next(), None); + + let mut empty = successors(None::<u32>, |_| unimplemented!()); + assert_eq!(empty.next(), None); + assert_eq!(empty.next(), None); +} + +#[test] +fn test_fuse() { + let mut it = 0..3; + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.len(), 2); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.len(), 1); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.len(), 0); + assert_eq!(it.next(), None); + assert_eq!(it.len(), 0); + assert_eq!(it.next(), None); + assert_eq!(it.len(), 0); + assert_eq!(it.next(), None); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_fuse_nth() { + let xs = [0, 1, 2]; + let mut it = xs.iter(); + + assert_eq!(it.len(), 3); + assert_eq!(it.nth(2), Some(&2)); + assert_eq!(it.len(), 0); + assert_eq!(it.nth(2), None); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_fuse_last() { + let xs = [0, 1, 2]; + let it = xs.iter(); + + assert_eq!(it.len(), 3); + assert_eq!(it.last(), Some(&2)); +} + +#[test] +fn test_fuse_count() { + let xs = [0, 1, 2]; + let it = xs.iter(); + + assert_eq!(it.len(), 3); + assert_eq!(it.count(), 3); + // Can't check len now because count consumes. +} + +#[test] +fn test_fuse_fold() { + let xs = [0, 1, 2]; + let it = xs.iter(); // `FusedIterator` + let i = it.fuse().fold(0, |i, &x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); + + let it = xs.iter(); // `FusedIterator` + let i = it.fuse().rfold(xs.len(), |i, &x| { + assert_eq!(x, xs[i - 1]); + i - 1 + }); + assert_eq!(i, 0); + + let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator` + let i = it.fuse().fold(0, |i, x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); +} + +#[test] +fn test_once() { + let mut it = once(42); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_once_with() { + let count = Cell::new(0); + let mut it = once_with(|| { + count.set(count.get() + 1); + 42 + }); + + assert_eq!(count.get(), 0); + assert_eq!(it.next(), Some(42)); + assert_eq!(count.get(), 1); + assert_eq!(it.next(), None); + assert_eq!(count.get(), 1); + assert_eq!(it.next(), None); + assert_eq!(count.get(), 1); +} + +#[test] +fn test_empty() { + let mut it = empty::<i32>(); + assert_eq!(it.next(), None); +} + +#[test] +fn test_chain_fold() { + let xs = [1, 2, 3]; + let ys = [1, 2, 0]; + + let mut iter = xs.iter().chain(&ys); + iter.next(); + let mut result = Vec::new(); + iter.fold((), |(), &elt| result.push(elt)); + assert_eq!(&[2, 3, 1, 2, 0], &result[..]); +} + +#[test] +fn test_steps_between() { + assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize)); + assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize)); + assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize)); + assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize)); + assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize)); + assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize)); + + // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms + + assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize)); + assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize)); + if cfg!(target_pointer_width = "64") { + assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX)); + } + assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None); + assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None); + assert_eq!( + Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,), + None, + ); +} + +#[test] +fn test_step_forward() { + assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8)); + assert_eq!(Step::forward_checked(252_u8, 200_usize), None); + assert_eq!(Step::forward_checked(0_u8, 256_usize), None); + assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8)); + assert_eq!(Step::forward_checked(-110_i8, 248_usize), None); + assert_eq!(Step::forward_checked(-126_i8, 256_usize), None); + + assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16)); + assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX)); + assert_eq!(Step::forward_checked(36_u16, 65500_usize), None); + assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16)); + assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16)); + assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None); + assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None); + + assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128)); + assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128)); + assert_eq!( + Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize), + Some(u128::MAX), + ); + assert_eq!( + Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize), + None + ); + assert_eq!( + Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize), + Some(i128::MAX), + ); + assert_eq!( + Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), + None + ); +} + +#[test] +fn test_step_backward() { + assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8)); + assert_eq!(Step::backward_checked(100_u8, 200_usize), None); + assert_eq!(Step::backward_checked(255_u8, 256_usize), None); + assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8)); + assert_eq!(Step::backward_checked(110_i8, 248_usize), None); + assert_eq!(Step::backward_checked(127_i8, 256_usize), None); + + assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16)); + assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16)); + assert_eq!(Step::backward_checked(10_u16, 11_usize), None); + assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16)); + assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16)); + assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None); + assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None); + + assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128)); + assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128)); + assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128)); + assert_eq!(Step::backward_checked(10_u128, 11_usize), None); + assert_eq!( + Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), + Some(i128::MIN) + ); +} + +#[test] +fn test_rev_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f)); + assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f)); + + let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; + let mut iter = a.iter().rev(); + assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(&70)); + let mut iter = a.iter().rev(); + assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(&60)); +} + +#[test] +fn test_cloned_try_folds() { + let a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let f = &|acc, x| i32::checked_add(2 * acc, x); + let f_ref = &|acc, &x| i32::checked_add(2 * acc, x); + assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref)); + assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref)); + + let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; + let mut iter = a.iter().cloned(); + assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(60)); + let mut iter = a.iter().cloned(); + assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(70)); +} + +#[test] +fn test_chain_try_folds() { + let c = || (0..10).chain(10..20); + + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f)); + assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f)); + + let mut iter = c(); + assert_eq!(iter.position(|x| x == 5), Some(5)); + assert_eq!(iter.next(), Some(6), "stopped in front, state Both"); + assert_eq!(iter.position(|x| x == 13), Some(6)); + assert_eq!(iter.next(), Some(14), "stopped in back, state Back"); + assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum())); + + let mut iter = c().rev(); // use rev to access try_rfold + assert_eq!(iter.position(|x| x == 15), Some(4)); + assert_eq!(iter.next(), Some(14), "stopped in back, state Both"); + assert_eq!(iter.position(|x| x == 5), Some(8)); + assert_eq!(iter.next(), Some(4), "stopped in front, state Front"); + assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum())); + + let mut iter = c(); + iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front + assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f)); + + let mut iter = c(); + iter.nth(14); // skip the first 15, ending in state Back + assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f)); +} + +#[test] +fn test_map_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f)); + assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f)); + + let mut iter = (0..40).map(|x| x + 10); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(46)); +} + +#[test] +fn test_filter_try_folds() { + fn p(&x: &i32) -> bool { + 0 <= x && x < 10 + } + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f)); + assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f)); + + let mut iter = (0..40).filter(|&x| x % 2 == 1); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(25)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(31)); +} + +#[test] +fn test_filter_map_try_folds() { + let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None }; + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f)); + assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f)); + + let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) }); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(38)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(78)); +} + +#[test] +fn test_enumerate_try_folds() { + let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i); + assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f)); + assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f)); + + let mut iter = (100..200).enumerate(); + let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?); + assert_eq!(iter.try_fold(0, f), None); + assert_eq!(iter.next(), Some((7, 107))); + assert_eq!(iter.try_rfold(0, f), None); + assert_eq!(iter.next_back(), Some((11, 111))); +} + +#[test] +fn test_peek_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + + assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f)); + assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f)); + + let mut iter = (1..20).peekable(); + assert_eq!(iter.peek(), Some(&1)); + assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f)); + + let mut iter = (1..20).peekable(); + assert_eq!(iter.peek(), Some(&1)); + assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f)); + + let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); + assert_eq!(iter.peek(), Some(&100)); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.peek(), Some(&40)); + + let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); + assert_eq!(iter.peek(), Some(&100)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.peek(), Some(&100)); + assert_eq!(iter.next_back(), Some(50)); + + let mut iter = (2..5).peekable(); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_for_each(Err), Err(2)); + assert_eq!(iter.peek(), Some(&3)); + assert_eq!(iter.try_for_each(Err), Err(3)); + assert_eq!(iter.peek(), Some(&4)); + assert_eq!(iter.try_for_each(Err), Err(4)); + assert_eq!(iter.peek(), None); + assert_eq!(iter.try_for_each(Err), Ok(())); + + let mut iter = (2..5).peekable(); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4)); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3)); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2)); + assert_eq!(iter.peek(), None); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(())); +} + +#[test] +fn test_skip_while_try_fold() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + fn p(&x: &i32) -> bool { + (x % 10) <= 5 + } + assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f)); + let mut iter = (1..20).skip_while(p); + assert_eq!(iter.nth(5), Some(11)); + assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f)); + + let mut iter = (0..50).skip_while(|&x| (x % 20) < 15); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(23)); +} + +#[test] +fn test_take_while_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f)); + let mut iter = (1..20).take_while(|&x| x != 10); + assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum())); + assert_eq!(iter.next(), None, "flag should be set"); + let iter = (1..20).take_while(|&x| x != 10); + assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum()); + + let mut iter = (10..50).take_while(|&x| x != 40); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); +} + +#[test] +fn test_skip_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f)); + assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f)); + + let mut iter = (0..30).skip(10); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(24)); +} + +#[test] +fn test_skip_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(0), Some(&5)); + assert_eq!(it.nth_back(1), Some(&3)); + assert_eq!(it.nth_back(0), Some(&2)); + assert_eq!(it.nth_back(0), None); + + let ys = [2, 3, 4, 5]; + let mut ity = ys.iter(); + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(1), ity.nth_back(1)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(4), None); + assert_eq!(it.nth_back(0), None); + + let mut it = xs.iter(); + it.by_ref().skip(2).nth_back(3); + assert_eq!(it.next_back(), Some(&1)); + + let mut it = xs.iter(); + it.by_ref().skip(2).nth_back(10); + assert_eq!(it.next_back(), Some(&1)); +} + +#[test] +fn test_take_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f)); + assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f)); + + let mut iter = (10..30).take(20); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(24)); + + let mut iter = (2..20).take(3); + assert_eq!(iter.try_for_each(Err), Err(2)); + assert_eq!(iter.try_for_each(Err), Err(3)); + assert_eq!(iter.try_for_each(Err), Err(4)); + assert_eq!(iter.try_for_each(Err), Ok(())); + + let mut iter = (2..20).take(3).rev(); + assert_eq!(iter.try_for_each(Err), Err(4)); + assert_eq!(iter.try_for_each(Err), Err(3)); + assert_eq!(iter.try_for_each(Err), Err(2)); + assert_eq!(iter.try_for_each(Err), Ok(())); +} + +#[test] +fn test_flat_map_try_folds() { + let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); + let mr = &|x| (5 * x)..(5 * x + 5); + assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f)); + assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f)); + let mut iter = (0..10).flat_map(mr); + iter.next(); + iter.next_back(); // have front and back iters in progress + assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); + + let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4)); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(17)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(35)); +} + +#[test] +fn test_flatten_try_folds() { + let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); + let mr = &|x| (5 * x)..(5 * x + 5); + assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f)); + assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f)); + let mut iter = (0..10).map(mr).flatten(); + iter.next(); + iter.next_back(); // have front and back iters in progress + assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); + + let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten(); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(17)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(35)); +} + +#[test] +fn test_functor_laws() { + // identity: + fn identity<T>(x: T) -> T { + x + } + assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum()); + + // composition: + fn f(x: usize) -> usize { + x + 3 + } + fn g(x: usize) -> usize { + x * 2 + } + fn h(x: usize) -> usize { + g(f(x)) + } + assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum()); +} + +#[test] +fn test_monad_laws_left_identity() { + fn f(x: usize) -> impl Iterator<Item = usize> { + (0..10).map(move |y| x * y) + } + assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum()); +} + +#[test] +fn test_monad_laws_right_identity() { + assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum()); +} + +#[test] +fn test_monad_laws_associativity() { + fn f(x: usize) -> impl Iterator<Item = usize> { + 0..x + } + fn g(x: usize) -> impl Iterator<Item = usize> { + (0..x).rev() + } + assert_eq!( + (0..10).flat_map(f).flat_map(g).sum::<usize>(), + (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>() + ); +} + +#[test] +fn test_is_sorted() { + assert!([1, 2, 2, 9].iter().is_sorted()); + assert!(![1, 3, 2].iter().is_sorted()); + assert!([0].iter().is_sorted()); + assert!(std::iter::empty::<i32>().is_sorted()); + assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); + assert!([-2, -1, 0, 3].iter().is_sorted()); + assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); + assert!(!["c", "bb", "aaa"].iter().is_sorted()); + assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); +} + +#[test] +fn test_partition() { + fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) { + let i = xs.iter_mut().partition_in_place(p); + assert_eq!(expected, i); + assert!(xs[..i].iter().all(p)); + assert!(!xs[i..].iter().any(p)); + assert!(xs.iter().is_partitioned(p)); + if i == 0 || i == xs.len() { + assert!(xs.iter().rev().is_partitioned(p)); + } else { + assert!(!xs.iter().rev().is_partitioned(p)); + } + } + + check(&mut [], |_| true, 0); + check(&mut [], |_| false, 0); + + check(&mut [0], |_| true, 1); + check(&mut [0], |_| false, 0); + + check(&mut [-1, 1], |&x| x > 0, 1); + check(&mut [-1, 1], |&x| x < 0, 1); + + let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + check(xs, |_| true, 10); + check(xs, |_| false, 0); + check(xs, |&x| x % 2 == 0, 5); // evens + check(xs, |&x| x % 2 == 1, 5); // odds + check(xs, |&x| x % 3 == 0, 4); // multiple of 3 + check(xs, |&x| x % 4 == 0, 3); // multiple of 4 + check(xs, |&x| x % 5 == 0, 2); // multiple of 5 + check(xs, |&x| x < 3, 3); // small + check(xs, |&x| x > 6, 3); // large +} + +/// An iterator that panics whenever `next` or next_back` is called +/// after `None` has already been returned. This does not violate +/// `Iterator`'s contract. Used to test that iterator adaptors don't +/// poll their inner iterators after exhausting them. +struct NonFused<I> { + iter: I, + done: bool, +} + +impl<I> NonFused<I> { + fn new(iter: I) -> Self { + Self { iter, done: false } + } +} + +impl<I> Iterator for NonFused<I> +where + I: Iterator, +{ + type Item = I::Item; + + fn next(&mut self) -> Option<Self::Item> { + assert!(!self.done, "this iterator has already returned None"); + self.iter.next().or_else(|| { + self.done = true; + None + }) + } +} + +impl<I> DoubleEndedIterator for NonFused<I> +where + I: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option<Self::Item> { + assert!(!self.done, "this iterator has already returned None"); + self.iter.next_back().or_else(|| { + self.done = true; + None + }) + } +} + +#[test] +fn test_peekable_non_fused() { + let mut iter = NonFused::new(empty::<i32>()).peekable(); + + assert_eq!(iter.peek(), None); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_flatten_non_fused_outer() { + let mut iter = NonFused::new(once(0..2)).flatten(); + + assert_eq!(iter.next_back(), Some(1)); + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.next(), None); +} + +#[test] +fn test_flatten_non_fused_inner() { + let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new); + + assert_eq!(iter.next_back(), Some(2)); + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), None); +} + +#[test] +pub fn extend_for_unit() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} + +#[test] +fn test_intersperse() { + let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>(); + assert_eq!(v, vec![]); + + let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>(); + assert_eq!(v, vec![1]); + + let xs = ["a", "", "b", "c"]; + let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); + let text: String = v.concat(); + assert_eq!(text, "a, , b, c".to_string()); + + let ys = [0, 1, 2, 3]; + let mut it = ys[..0].iter().map(|x| *x).intersperse(1); + assert!(it.next() == None); +} + +#[test] +fn test_intersperse_size_hint() { + let iter = std::iter::empty::<i32>().intersperse(0); + assert_eq!(iter.size_hint(), (0, Some(0))); + + let xs = ["a", "", "b", "c"]; + let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); + assert_eq!(iter.size_hint(), (7, Some(7))); + + assert_eq!(iter.next(), Some("a")); + assert_eq!(iter.size_hint(), (6, Some(6))); + assert_eq!(iter.next(), Some(", ")); + assert_eq!(iter.size_hint(), (5, Some(5))); + + assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0))); +} + +#[test] +fn test_fold_specialization_intersperse() { + let mut iter = (1..2).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); + + let mut iter = (1..3).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); + + let mut iter = (1..4).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); +} + +#[test] +fn test_try_fold_specialization_intersperse_ok() { + let mut iter = (1..2).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); + + let mut iter = (1..3).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); + + let mut iter = (1..4).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); +} + +#[test] +fn test_try_fold_specialization_intersperse_err() { + let orig_iter = ["a", "b"].iter().copied().intersperse("-"); + + // Abort after the first item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|_| None::<()>); + assert_eq!(iter.next(), Some("-")); + assert_eq!(iter.next(), Some("b")); + assert_eq!(iter.next(), None); + + // Abort after the second item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|item| if item == "-" { None } else { Some(()) }); + assert_eq!(iter.next(), Some("b")); + assert_eq!(iter.next(), None); + + // Abort after the third item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); + assert_eq!(iter.next(), None); +} + +#[test] +fn test_intersperse_with() { + #[derive(PartialEq, Debug)] + struct NotClone { + u: u32, + } + let r = vec![NotClone { u: 0 }, NotClone { u: 1 }] + .into_iter() + .intersperse_with(|| NotClone { u: 2 }) + .collect::<Vec<_>>(); + assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]); + + let mut ctr = 100; + let separator = || { + ctr *= 2; + ctr + }; + let r = (0..3).intersperse_with(separator).collect::<Vec<_>>(); + assert_eq!(r, vec![0, 200, 1, 400, 2]); +} diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs deleted file mode 100644 index ca5ae12ae263f..0000000000000 --- a/library/core/tests/iter/adapters/chain.rs +++ /dev/null @@ -1,272 +0,0 @@ -use super::*; -use core::iter::*; - -#[test] -fn test_iterator_chain() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - let it = xs.iter().chain(&ys); - let mut i = 0; - for &x in it { - assert_eq!(x, expected[i]); - i += 1; - } - assert_eq!(i, expected.len()); - - let ys = (30..).step_by(10).take(4); - let it = xs.iter().cloned().chain(ys); - let mut i = 0; - for x in it { - assert_eq!(x, expected[i]); - i += 1; - } - assert_eq!(i, expected.len()); -} - -#[test] -fn test_iterator_chain_advance_by() { - fn test_chain(xs: &[i32], ys: &[i32]) { - let len = xs.len() + ys.len(); - - for i in 0..xs.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_by(i).unwrap(); - assert_eq!(iter.next(), Some(&xs[i])); - assert_eq!(iter.advance_by(100), Err(len - i - 1)); - } - - for i in 0..ys.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_by(xs.len() + i).unwrap(); - assert_eq!(iter.next(), Some(&ys[i])); - assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1)); - } - - let mut iter = xs.iter().chain(ys); - iter.advance_by(len).unwrap(); - assert_eq!(iter.next(), None); - - let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_by(len + 1), Err(len)); - } - - test_chain(&[], &[]); - test_chain(&[], &[0, 1, 2, 3, 4, 5]); - test_chain(&[0, 1, 2, 3, 4, 5], &[]); - test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); -} - -#[test] -fn test_iterator_chain_advance_back_by() { - fn test_chain(xs: &[i32], ys: &[i32]) { - let len = xs.len() + ys.len(); - - for i in 0..ys.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_back_by(i).unwrap(); - assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), Err(len - i - 1)); - } - - for i in 0..xs.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_back_by(ys.len() + i).unwrap(); - assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1)); - } - - let mut iter = xs.iter().chain(ys); - iter.advance_back_by(len).unwrap(); - assert_eq!(iter.next_back(), None); - - let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_back_by(len + 1), Err(len)); - } - - test_chain(&[], &[]); - test_chain(&[], &[0, 1, 2, 3, 4, 5]); - test_chain(&[0, 1, 2, 3, 4, 5], &[]); - test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); -} - -#[test] -fn test_iterator_chain_nth() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - for (i, x) in expected.iter().enumerate() { - assert_eq!(Some(x), xs.iter().chain(&ys).nth(i)); - } - assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0)); - - let mut it = xs.iter().chain(&zs); - assert_eq!(it.nth(5), Some(&5)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_chain_nth_back() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - for (i, x) in expected.iter().rev().enumerate() { - assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i)); - } - assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5)); - - let mut it = xs.iter().chain(&zs); - assert_eq!(it.nth_back(5), Some(&0)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_chain_last() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - assert_eq!(xs.iter().chain(&ys).last(), Some(&60)); - assert_eq!(zs.iter().chain(&ys).last(), Some(&60)); - assert_eq!(ys.iter().chain(&zs).last(), Some(&60)); - assert_eq!(zs.iter().chain(&zs).last(), None); -} - -#[test] -fn test_iterator_chain_count() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - assert_eq!(xs.iter().chain(&ys).count(), 10); - assert_eq!(zs.iter().chain(&ys).count(), 4); -} - -#[test] -fn test_iterator_chain_find() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let mut iter = xs.iter().chain(&ys); - assert_eq!(iter.find(|&&i| i == 4), Some(&4)); - assert_eq!(iter.next(), Some(&5)); - assert_eq!(iter.find(|&&i| i == 40), Some(&40)); - assert_eq!(iter.next(), Some(&50)); - assert_eq!(iter.find(|&&i| i == 100), None); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_iterator_chain_size_hint() { - // this chains an iterator of length 0 with an iterator of length 1, - // so after calling `.next()` once, the iterator is empty and the - // state is `ChainState::Back`. `.size_hint()` should now disregard - // the size hint of the left iterator - let mut iter = Toggle { is_empty: true }.chain(once(())); - assert_eq!(iter.next(), Some(())); - assert_eq!(iter.size_hint(), (0, Some(0))); - - let mut iter = once(()).chain(Toggle { is_empty: true }); - assert_eq!(iter.next_back(), Some(())); - assert_eq!(iter.size_hint(), (0, Some(0))); -} - -#[test] -fn test_iterator_chain_unfused() { - // Chain shouldn't be fused in its second iterator, depending on direction - let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true }); - iter.next().unwrap_none(); - iter.next().unwrap(); - iter.next().unwrap_none(); - - let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty())); - iter.next_back().unwrap_none(); - iter.next_back().unwrap(); - iter.next_back().unwrap_none(); -} - -#[test] -fn test_chain_fold() { - let xs = [1, 2, 3]; - let ys = [1, 2, 0]; - - let mut iter = xs.iter().chain(&ys); - iter.next(); - let mut result = Vec::new(); - iter.fold((), |(), &elt| result.push(elt)); - assert_eq!(&[2, 3, 1, 2, 0], &result[..]); -} - -#[test] -fn test_chain_try_folds() { - let c = || (0..10).chain(10..20); - - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f)); - assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f)); - - let mut iter = c(); - assert_eq!(iter.position(|x| x == 5), Some(5)); - assert_eq!(iter.next(), Some(6), "stopped in front, state Both"); - assert_eq!(iter.position(|x| x == 13), Some(6)); - assert_eq!(iter.next(), Some(14), "stopped in back, state Back"); - assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum())); - - let mut iter = c().rev(); // use rev to access try_rfold - assert_eq!(iter.position(|x| x == 15), Some(4)); - assert_eq!(iter.next(), Some(14), "stopped in back, state Both"); - assert_eq!(iter.position(|x| x == 5), Some(8)); - assert_eq!(iter.next(), Some(4), "stopped in front, state Front"); - assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum())); - - let mut iter = c(); - iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front - assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f)); - - let mut iter = c(); - iter.nth(14); // skip the first 15, ending in state Back - assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f)); -} - -#[test] -fn test_double_ended_chain() { - let xs = [1, 2, 3, 4, 5]; - let ys = [7, 9, 11]; - let mut it = xs.iter().chain(&ys).rev(); - assert_eq!(it.next().unwrap(), &11); - assert_eq!(it.next().unwrap(), &9); - assert_eq!(it.next_back().unwrap(), &1); - assert_eq!(it.next_back().unwrap(), &2); - assert_eq!(it.next_back().unwrap(), &3); - assert_eq!(it.next_back().unwrap(), &4); - assert_eq!(it.next_back().unwrap(), &5); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back(), None); - - // test that .chain() is well behaved with an unfused iterator - struct CrazyIterator(bool); - impl CrazyIterator { - fn new() -> CrazyIterator { - CrazyIterator(false) - } - } - impl Iterator for CrazyIterator { - type Item = i32; - fn next(&mut self) -> Option<i32> { - if self.0 { - Some(99) - } else { - self.0 = true; - None - } - } - } - - impl DoubleEndedIterator for CrazyIterator { - fn next_back(&mut self) -> Option<i32> { - self.next() - } - } - - assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0)); - assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0)); -} diff --git a/library/core/tests/iter/adapters/cloned.rs b/library/core/tests/iter/adapters/cloned.rs deleted file mode 100644 index 78babb7feab18..0000000000000 --- a/library/core/tests/iter/adapters/cloned.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::iter::*; - -#[test] -fn test_cloned() { - let xs = [2, 4, 6, 8]; - - let mut it = xs.iter().cloned(); - assert_eq!(it.len(), 4); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.len(), 2); - assert_eq!(it.next_back(), Some(8)); - assert_eq!(it.len(), 1); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(it.len(), 0); - assert_eq!(it.next_back(), None); -} - -#[test] -fn test_cloned_side_effects() { - let mut count = 0; - { - let iter = [1, 2, 3] - .iter() - .map(|x| { - count += 1; - x - }) - .cloned() - .zip(&[1]); - for _ in iter {} - } - assert_eq!(count, 2); -} - -#[test] -fn test_cloned_try_folds() { - let a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let f = &|acc, x| i32::checked_add(2 * acc, x); - let f_ref = &|acc, &x| i32::checked_add(2 * acc, x); - assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref)); - assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref)); - - let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; - let mut iter = a.iter().cloned(); - assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None); - assert_eq!(iter.next(), Some(60)); - let mut iter = a.iter().cloned(); - assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None); - assert_eq!(iter.next_back(), Some(70)); -} diff --git a/library/core/tests/iter/adapters/copied.rs b/library/core/tests/iter/adapters/copied.rs deleted file mode 100644 index b12f2035dc133..0000000000000 --- a/library/core/tests/iter/adapters/copied.rs +++ /dev/null @@ -1,18 +0,0 @@ -use core::iter::*; - -#[test] -fn test_copied() { - let xs = [2, 4, 6, 8]; - - let mut it = xs.iter().copied(); - assert_eq!(it.len(), 4); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.len(), 2); - assert_eq!(it.next_back(), Some(8)); - assert_eq!(it.len(), 1); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(it.len(), 0); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/cycle.rs b/library/core/tests/iter/adapters/cycle.rs deleted file mode 100644 index 8831c09b48b3f..0000000000000 --- a/library/core/tests/iter/adapters/cycle.rs +++ /dev/null @@ -1,31 +0,0 @@ -use core::iter::*; - -#[test] -fn test_cycle() { - let cycle_len = 3; - let it = (0..).step_by(1).take(cycle_len).cycle(); - assert_eq!(it.size_hint(), (usize::MAX, None)); - for (i, x) in it.take(100).enumerate() { - assert_eq!(i % cycle_len, x); - } - - let mut it = (0..).step_by(1).take(0).cycle(); - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next(), None); - - assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0); - - assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4); - - assert_eq!((0..10).cycle().take(5).sum::<i32>(), 10); - assert_eq!((0..10).cycle().take(15).sum::<i32>(), 55); - assert_eq!((0..10).cycle().take(25).sum::<i32>(), 100); - - let mut iter = (0..10).cycle(); - iter.nth(14); - assert_eq!(iter.take(8).sum::<i32>(), 38); - - let mut iter = (0..10).cycle(); - iter.nth(9); - assert_eq!(iter.take(3).sum::<i32>(), 3); -} diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs deleted file mode 100644 index 0e60338784797..0000000000000 --- a/library/core/tests/iter/adapters/enumerate.rs +++ /dev/null @@ -1,107 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_enumerate() { - let xs = [0, 1, 2, 3, 4, 5]; - let it = xs.iter().enumerate(); - for (i, &x) in it { - assert_eq!(i, x); - } -} - -#[test] -fn test_iterator_enumerate_nth() { - let xs = [0, 1, 2, 3, 4, 5]; - for (i, &x) in xs.iter().enumerate() { - assert_eq!(i, x); - } - - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth(0) { - assert_eq!(i, x); - } - - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth(1) { - assert_eq!(i, x); - } - - let (i, &x) = xs.iter().enumerate().nth(3).unwrap(); - assert_eq!(i, x); - assert_eq!(i, 3); -} - -#[test] -fn test_iterator_enumerate_nth_back() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth_back(0) { - assert_eq!(i, x); - } - - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth_back(1) { - assert_eq!(i, x); - } - - let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap(); - assert_eq!(i, x); - assert_eq!(i, 2); -} - -#[test] -fn test_iterator_enumerate_count() { - let xs = [0, 1, 2, 3, 4, 5]; - assert_eq!(xs.iter().enumerate().count(), 6); -} - -#[test] -fn test_iterator_enumerate_fold() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().enumerate(); - // steal a couple to get an interesting offset - assert_eq!(it.next(), Some((0, &0))); - assert_eq!(it.next(), Some((1, &1))); - let i = it.fold(2, |i, (j, &x)| { - assert_eq!(i, j); - assert_eq!(x, xs[j]); - i + 1 - }); - assert_eq!(i, xs.len()); - - let mut it = xs.iter().enumerate(); - assert_eq!(it.next(), Some((0, &0))); - let i = it.rfold(xs.len() - 1, |i, (j, &x)| { - assert_eq!(i, j); - assert_eq!(x, xs[j]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_enumerate_try_folds() { - let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i); - assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f)); - assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f)); - - let mut iter = (100..200).enumerate(); - let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?); - assert_eq!(iter.try_fold(0, f), None); - assert_eq!(iter.next(), Some((7, 107))); - assert_eq!(iter.try_rfold(0, f), None); - assert_eq!(iter.next_back(), Some((11, 111))); -} - -#[test] -fn test_double_ended_enumerate() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().cloned().enumerate(); - assert_eq!(it.next(), Some((0, 1))); - assert_eq!(it.next(), Some((1, 2))); - assert_eq!(it.next_back(), Some((5, 6))); - assert_eq!(it.next_back(), Some((4, 5))); - assert_eq!(it.next_back(), Some((3, 4))); - assert_eq!(it.next_back(), Some((2, 3))); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/adapters/filter.rs b/library/core/tests/iter/adapters/filter.rs deleted file mode 100644 index a2050d89d8564..0000000000000 --- a/library/core/tests/iter/adapters/filter.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_filter_count() { - let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5); -} - -#[test] -fn test_iterator_filter_fold() { - let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let ys = [0, 2, 4, 6, 8]; - let it = xs.iter().filter(|&&x| x % 2 == 0); - let i = it.fold(0, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let it = xs.iter().filter(|&&x| x % 2 == 0); - let i = it.rfold(ys.len(), |i, &x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_filter_try_folds() { - fn p(&x: &i32) -> bool { - 0 <= x && x < 10 - } - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f)); - assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f)); - - let mut iter = (0..40).filter(|&x| x % 2 == 1); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(25)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(31)); -} - -#[test] -fn test_double_ended_filter() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().filter(|&x| *x & 1 == 0); - assert_eq!(it.next_back().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &4); - assert_eq!(it.next().unwrap(), &2); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/filter_map.rs b/library/core/tests/iter/adapters/filter_map.rs deleted file mode 100644 index 46738eda63f3d..0000000000000 --- a/library/core/tests/iter/adapters/filter_map.rs +++ /dev/null @@ -1,50 +0,0 @@ -use core::iter::*; - -#[test] -fn test_filter_map() { - let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None }); - assert_eq!(it.collect::<Vec<usize>>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]); -} - -#[test] -fn test_filter_map_fold() { - let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]; - let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); - let i = it.fold(0, |i, x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); - let i = it.rfold(ys.len(), |i, x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_filter_map_try_folds() { - let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None }; - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f)); - assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f)); - - let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) }); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(38)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(78)); -} - -#[test] -fn test_double_ended_filter_map() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None }); - assert_eq!(it.next_back().unwrap(), 12); - assert_eq!(it.next_back().unwrap(), 8); - assert_eq!(it.next().unwrap(), 4); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/flat_map.rs b/library/core/tests/iter/adapters/flat_map.rs deleted file mode 100644 index ee945e69801b8..0000000000000 --- a/library/core/tests/iter/adapters/flat_map.rs +++ /dev/null @@ -1,74 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_flat_map() { - let xs = [0, 3, 6]; - let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3)); - let mut i = 0; - for x in it { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -/// Tests `FlatMap::fold` with items already picked off the front and back, -/// to make sure all parts of the `FlatMap` are folded correctly. -#[test] -fn test_iterator_flat_map_fold() { - let xs = [0, 3, 6]; - let ys = [1, 2, 3, 4, 5, 6, 7]; - let mut it = xs.iter().flat_map(|&x| x..x + 3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.fold(0, |i, x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().flat_map(|&x| x..x + 3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.rfold(ys.len(), |i, x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_flat_map_try_folds() { - let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); - let mr = &|x| (5 * x)..(5 * x + 5); - assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f)); - assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f)); - let mut iter = (0..10).flat_map(mr); - iter.next(); - iter.next_back(); // have front and back iters in progress - assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); - - let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4)); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(17)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(35)); -} - -#[test] -fn test_double_ended_flat_map() { - let u = [0, 1]; - let v = [5, 6, 7, 8]; - let mut it = u.iter().flat_map(|x| &v[*x..v.len()]); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &5); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs deleted file mode 100644 index bd2c6fd9252df..0000000000000 --- a/library/core/tests/iter/adapters/flatten.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::*; -use core::iter::*; - -#[test] -fn test_iterator_flatten() { - let xs = [0, 3, 6]; - let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten(); - let mut i = 0; - for x in it { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -/// Tests `Flatten::fold` with items already picked off the front and back, -/// to make sure all parts of the `Flatten` are folded correctly. -#[test] -fn test_iterator_flatten_fold() { - let xs = [0, 3, 6]; - let ys = [1, 2, 3, 4, 5, 6, 7]; - let mut it = xs.iter().map(|&x| x..x + 3).flatten(); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.fold(0, |i, x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().map(|&x| x..x + 3).flatten(); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.rfold(ys.len(), |i, x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_flatten_try_folds() { - let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); - let mr = &|x| (5 * x)..(5 * x + 5); - assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f)); - assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f)); - let mut iter = (0..10).map(mr).flatten(); - iter.next(); - iter.next_back(); // have front and back iters in progress - assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); - - let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten(); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(17)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(35)); -} - -#[test] -fn test_flatten_non_fused_outer() { - let mut iter = NonFused::new(once(0..2)).flatten(); - - assert_eq!(iter.next_back(), Some(1)); - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_flatten_non_fused_inner() { - let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new); - - assert_eq!(iter.next_back(), Some(2)); - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_double_ended_flatten() { - let u = [0, 1]; - let v = [5, 6, 7, 8]; - let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten(); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &5); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/fuse.rs b/library/core/tests/iter/adapters/fuse.rs deleted file mode 100644 index f41b379b3ac7f..0000000000000 --- a/library/core/tests/iter/adapters/fuse.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::iter::*; - -#[test] -fn test_fuse_nth() { - let xs = [0, 1, 2]; - let mut it = xs.iter(); - - assert_eq!(it.len(), 3); - assert_eq!(it.nth(2), Some(&2)); - assert_eq!(it.len(), 0); - assert_eq!(it.nth(2), None); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_fuse_last() { - let xs = [0, 1, 2]; - let it = xs.iter(); - - assert_eq!(it.len(), 3); - assert_eq!(it.last(), Some(&2)); -} - -#[test] -fn test_fuse_count() { - let xs = [0, 1, 2]; - let it = xs.iter(); - - assert_eq!(it.len(), 3); - assert_eq!(it.count(), 3); - // Can't check len now because count consumes. -} - -#[test] -fn test_fuse_fold() { - let xs = [0, 1, 2]; - let it = xs.iter(); // `FusedIterator` - let i = it.fuse().fold(0, |i, &x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); - - let it = xs.iter(); // `FusedIterator` - let i = it.fuse().rfold(xs.len(), |i, &x| { - assert_eq!(x, xs[i - 1]); - i - 1 - }); - assert_eq!(i, 0); - - let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator` - let i = it.fuse().fold(0, |i, x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); -} - -#[test] -fn test_fuse() { - let mut it = 0..3; - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.len(), 2); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.len(), 1); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.len(), 0); - assert_eq!(it.next(), None); - assert_eq!(it.len(), 0); - assert_eq!(it.next(), None); - assert_eq!(it.len(), 0); - assert_eq!(it.next(), None); - assert_eq!(it.len(), 0); -} diff --git a/library/core/tests/iter/adapters/inspect.rs b/library/core/tests/iter/adapters/inspect.rs deleted file mode 100644 index 939e3a28a7204..0000000000000 --- a/library/core/tests/iter/adapters/inspect.rs +++ /dev/null @@ -1,38 +0,0 @@ -use core::iter::*; - -#[test] -fn test_inspect() { - let xs = [1, 2, 3, 4]; - let mut n = 0; - - let ys = xs.iter().cloned().inspect(|_| n += 1).collect::<Vec<usize>>(); - - assert_eq!(n, xs.len()); - assert_eq!(&xs[..], &ys[..]); -} - -#[test] -fn test_inspect_fold() { - let xs = [1, 2, 3, 4]; - let mut n = 0; - { - let it = xs.iter().inspect(|_| n += 1); - let i = it.fold(0, |i, &x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); - } - assert_eq!(n, xs.len()); - - let mut n = 0; - { - let it = xs.iter().inspect(|_| n += 1); - let i = it.rfold(xs.len(), |i, &x| { - assert_eq!(x, xs[i - 1]); - i - 1 - }); - assert_eq!(i, 0); - } - assert_eq!(n, xs.len()); -} diff --git a/library/core/tests/iter/adapters/intersperse.rs b/library/core/tests/iter/adapters/intersperse.rs deleted file mode 100644 index 9dbe232e4eec8..0000000000000 --- a/library/core/tests/iter/adapters/intersperse.rs +++ /dev/null @@ -1,154 +0,0 @@ -use core::iter::*; - -#[test] -fn test_intersperse() { - let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>(); - assert_eq!(v, vec![]); - - let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>(); - assert_eq!(v, vec![1]); - - let xs = ["a", "", "b", "c"]; - let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); - let text: String = v.concat(); - assert_eq!(text, "a, , b, c".to_string()); - - let ys = [0, 1, 2, 3]; - let mut it = ys[..0].iter().map(|x| *x).intersperse(1); - assert!(it.next() == None); -} - -#[test] -fn test_intersperse_size_hint() { - let iter = std::iter::empty::<i32>().intersperse(0); - assert_eq!(iter.size_hint(), (0, Some(0))); - - let xs = ["a", "", "b", "c"]; - let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); - assert_eq!(iter.size_hint(), (7, Some(7))); - - assert_eq!(iter.next(), Some("a")); - assert_eq!(iter.size_hint(), (6, Some(6))); - assert_eq!(iter.next(), Some(", ")); - assert_eq!(iter.size_hint(), (5, Some(5))); - - assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0))); -} - -#[test] -fn test_fold_specialization_intersperse() { - let mut iter = (1..2).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); - - let mut iter = (1..3).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); - - let mut iter = (1..4).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); -} - -#[test] -fn test_try_fold_specialization_intersperse_ok() { - let mut iter = (1..2).intersperse(0); - iter.clone().try_for_each(|x| { - assert_eq!(Some(x), iter.next()); - Some(()) - }); - - let mut iter = (1..3).intersperse(0); - iter.clone().try_for_each(|x| { - assert_eq!(Some(x), iter.next()); - Some(()) - }); - - let mut iter = (1..4).intersperse(0); - iter.clone().try_for_each(|x| { - assert_eq!(Some(x), iter.next()); - Some(()) - }); -} - -#[test] -fn test_intersperse_with() { - #[derive(PartialEq, Debug)] - struct NotClone { - u: u32, - } - let r = vec![NotClone { u: 0 }, NotClone { u: 1 }] - .into_iter() - .intersperse_with(|| NotClone { u: 2 }) - .collect::<Vec<_>>(); - assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]); - - let mut ctr = 100; - let separator = || { - ctr *= 2; - ctr - }; - let r = (0..3).intersperse_with(separator).collect::<Vec<_>>(); - assert_eq!(r, vec![0, 200, 1, 400, 2]); -} - -#[test] -fn test_intersperse_fold() { - let v = (1..4).intersperse(9).fold(Vec::new(), |mut acc, x| { - acc.push(x); - acc - }); - assert_eq!(v.as_slice(), [1, 9, 2, 9, 3]); - - let mut iter = (1..4).intersperse(9); - assert_eq!(iter.next(), Some(1)); - let v = iter.fold(Vec::new(), |mut acc, x| { - acc.push(x); - acc - }); - assert_eq!(v.as_slice(), [9, 2, 9, 3]); - - struct NoneAtStart(i32); // Produces: None, Some(2), Some(3), None, ... - impl Iterator for NoneAtStart { - type Item = i32; - fn next(&mut self) -> Option<i32> { - self.0 += 1; - Some(self.0).filter(|i| i % 3 != 1) - } - } - - let v = NoneAtStart(0).intersperse(1000).fold(0, |a, b| a + b); - assert_eq!(v, 0); -} - -#[test] -fn test_intersperse_collect_string() { - let contents = vec![1, 2, 3]; - - let contents_string = contents - .into_iter() - .map(|id| id.to_string()) - .intersperse(", ".to_owned()) - .collect::<String>(); - assert_eq!(contents_string, "1, 2, 3"); -} - -#[test] -fn test_try_fold_specialization_intersperse_err() { - let orig_iter = ["a", "b"].iter().copied().intersperse("-"); - - // Abort after the first item. - let mut iter = orig_iter.clone(); - iter.try_for_each(|_| None::<()>); - assert_eq!(iter.next(), Some("-")); - assert_eq!(iter.next(), Some("b")); - assert_eq!(iter.next(), None); - - // Abort after the second item. - let mut iter = orig_iter.clone(); - iter.try_for_each(|item| if item == "-" { None } else { Some(()) }); - assert_eq!(iter.next(), Some("b")); - assert_eq!(iter.next(), None); - - // Abort after the third item. - let mut iter = orig_iter.clone(); - iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); - assert_eq!(iter.next(), None); -} diff --git a/library/core/tests/iter/adapters/map.rs b/library/core/tests/iter/adapters/map.rs deleted file mode 100644 index 77ce3819b322e..0000000000000 --- a/library/core/tests/iter/adapters/map.rs +++ /dev/null @@ -1,27 +0,0 @@ -use core::iter::*; - -#[test] -fn test_map_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f)); - assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f)); - - let mut iter = (0..40).map(|x| x + 10); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(46)); -} - -#[test] -fn test_double_ended_map() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().map(|&x| x * -1); - assert_eq!(it.next(), Some(-1)); - assert_eq!(it.next(), Some(-2)); - assert_eq!(it.next_back(), Some(-6)); - assert_eq!(it.next_back(), Some(-5)); - assert_eq!(it.next(), Some(-3)); - assert_eq!(it.next_back(), Some(-4)); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs deleted file mode 100644 index 96a53be1eaa50..0000000000000 --- a/library/core/tests/iter/adapters/mod.rs +++ /dev/null @@ -1,185 +0,0 @@ -mod chain; -mod cloned; -mod copied; -mod cycle; -mod enumerate; -mod filter; -mod filter_map; -mod flat_map; -mod flatten; -mod fuse; -mod inspect; -mod intersperse; -mod map; -mod peekable; -mod scan; -mod skip; -mod skip_while; -mod step_by; -mod take; -mod take_while; -mod zip; - -use core::cell::Cell; - -/// An iterator that panics whenever `next` or next_back` is called -/// after `None` has already been returned. This does not violate -/// `Iterator`'s contract. Used to test that iterator adaptors don't -/// poll their inner iterators after exhausting them. -pub struct NonFused<I> { - iter: I, - done: bool, -} - -impl<I> NonFused<I> { - pub fn new(iter: I) -> Self { - Self { iter, done: false } - } -} - -impl<I> Iterator for NonFused<I> -where - I: Iterator, -{ - type Item = I::Item; - - fn next(&mut self) -> Option<Self::Item> { - assert!(!self.done, "this iterator has already returned None"); - self.iter.next().or_else(|| { - self.done = true; - None - }) - } -} - -impl<I> DoubleEndedIterator for NonFused<I> -where - I: DoubleEndedIterator, -{ - fn next_back(&mut self) -> Option<Self::Item> { - assert!(!self.done, "this iterator has already returned None"); - self.iter.next_back().or_else(|| { - self.done = true; - None - }) - } -} - -/// An iterator wrapper that panics whenever `next` or `next_back` is called -/// after `None` has been returned. -pub struct Unfuse<I> { - iter: I, - exhausted: bool, -} - -impl<I> Unfuse<I> { - pub fn new<T>(iter: T) -> Self - where - T: IntoIterator<IntoIter = I>, - { - Self { iter: iter.into_iter(), exhausted: false } - } -} - -impl<I> Iterator for Unfuse<I> -where - I: Iterator, -{ - type Item = I::Item; - - fn next(&mut self) -> Option<Self::Item> { - assert!(!self.exhausted); - let next = self.iter.next(); - self.exhausted = next.is_none(); - next - } -} - -impl<I> DoubleEndedIterator for Unfuse<I> -where - I: DoubleEndedIterator, -{ - fn next_back(&mut self) -> Option<Self::Item> { - assert!(!self.exhausted); - let next = self.iter.next_back(); - self.exhausted = next.is_none(); - next - } -} - -pub struct Toggle { - is_empty: bool, -} - -impl Iterator for Toggle { - type Item = (); - - // alternates between `None` and `Some(())` - fn next(&mut self) -> Option<Self::Item> { - if self.is_empty { - self.is_empty = false; - None - } else { - self.is_empty = true; - Some(()) - } - } - - fn size_hint(&self) -> (usize, Option<usize>) { - if self.is_empty { (0, Some(0)) } else { (1, Some(1)) } - } -} - -impl DoubleEndedIterator for Toggle { - fn next_back(&mut self) -> Option<Self::Item> { - self.next() - } -} - -/// This is an iterator that follows the Iterator contract, -/// but it is not fused. After having returned None once, it will start -/// producing elements if .next() is called again. -pub struct CycleIter<'a, T> { - index: usize, - data: &'a [T], -} - -impl<'a, T> CycleIter<'a, T> { - pub fn new(data: &'a [T]) -> Self { - Self { index: 0, data } - } -} - -impl<'a, T> Iterator for CycleIter<'a, T> { - type Item = &'a T; - fn next(&mut self) -> Option<Self::Item> { - let elt = self.data.get(self.index); - self.index += 1; - self.index %= 1 + self.data.len(); - elt - } -} - -#[derive(Debug)] -struct CountClone(Cell<i32>); - -impl CountClone { - pub fn new() -> Self { - Self(Cell::new(0)) - } -} - -impl PartialEq<i32> for CountClone { - fn eq(&self, rhs: &i32) -> bool { - self.0.get() == *rhs - } -} - -impl Clone for CountClone { - fn clone(&self) -> Self { - let ret = CountClone(self.0.clone()); - let n = self.0.get(); - self.0.set(n + 1); - ret - } -} diff --git a/library/core/tests/iter/adapters/peekable.rs b/library/core/tests/iter/adapters/peekable.rs deleted file mode 100644 index 390414d4aa213..0000000000000 --- a/library/core/tests/iter/adapters/peekable.rs +++ /dev/null @@ -1,272 +0,0 @@ -use super::*; -use core::iter::*; - -#[test] -fn test_iterator_peekable() { - let xs = vec![0, 1, 2, 3, 4, 5]; - - let mut it = xs.iter().cloned().peekable(); - assert_eq!(it.len(), 6); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 6); - assert_eq!(it.next().unwrap(), 0); - assert_eq!(it.len(), 5); - assert_eq!(it.next().unwrap(), 1); - assert_eq!(it.len(), 4); - assert_eq!(it.next().unwrap(), 2); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &3); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &3); - assert_eq!(it.len(), 3); - assert_eq!(it.next().unwrap(), 3); - assert_eq!(it.len(), 2); - assert_eq!(it.next().unwrap(), 4); - assert_eq!(it.len(), 1); - assert_eq!(it.peek().unwrap(), &5); - assert_eq!(it.len(), 1); - assert_eq!(it.next().unwrap(), 5); - assert_eq!(it.len(), 0); - assert!(it.peek().is_none()); - assert_eq!(it.len(), 0); - assert!(it.next().is_none()); - assert_eq!(it.len(), 0); - - let mut it = xs.iter().cloned().peekable(); - assert_eq!(it.len(), 6); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 6); - assert_eq!(it.next_back().unwrap(), 5); - assert_eq!(it.len(), 5); - assert_eq!(it.next_back().unwrap(), 4); - assert_eq!(it.len(), 4); - assert_eq!(it.next_back().unwrap(), 3); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 3); - assert_eq!(it.next_back().unwrap(), 2); - assert_eq!(it.len(), 2); - assert_eq!(it.next_back().unwrap(), 1); - assert_eq!(it.len(), 1); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 1); - assert_eq!(it.next_back().unwrap(), 0); - assert_eq!(it.len(), 0); - assert!(it.peek().is_none()); - assert_eq!(it.len(), 0); - assert!(it.next_back().is_none()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_iterator_peekable_count() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [10]; - let zs: [i32; 0] = []; - - assert_eq!(xs.iter().peekable().count(), 6); - - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.count(), 6); - - assert_eq!(ys.iter().peekable().count(), 1); - - let mut it = ys.iter().peekable(); - assert_eq!(it.peek(), Some(&&10)); - assert_eq!(it.count(), 1); - - assert_eq!(zs.iter().peekable().count(), 0); - - let mut it = zs.iter().peekable(); - assert_eq!(it.peek(), None); -} - -#[test] -fn test_iterator_peekable_nth() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().peekable(); - - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.nth(0), Some(&0)); - assert_eq!(it.peek(), Some(&&1)); - assert_eq!(it.nth(1), Some(&2)); - assert_eq!(it.peek(), Some(&&3)); - assert_eq!(it.nth(2), Some(&5)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_peekable_last() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [0]; - - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.last(), Some(&5)); - - let mut it = ys.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.last(), Some(&0)); - - let mut it = ys.iter().peekable(); - assert_eq!(it.next(), Some(&0)); - assert_eq!(it.peek(), None); - assert_eq!(it.last(), None); -} - -#[test] -fn test_iterator_peekable_fold() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - let i = it.fold(0, |i, &x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); -} - -#[test] -fn test_iterator_peekable_rfold() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - let i = it.rfold(0, |i, &x| { - assert_eq!(x, xs[xs.len() - 1 - i]); - i + 1 - }); - assert_eq!(i, xs.len()); -} - -#[test] -fn test_iterator_peekable_next_if_eq() { - // first, try on references - let xs = vec!["Heart", "of", "Gold"]; - let mut it = xs.into_iter().peekable(); - // try before `peek()` - assert_eq!(it.next_if_eq(&"trillian"), None); - assert_eq!(it.next_if_eq(&"Heart"), Some("Heart")); - // try after peek() - assert_eq!(it.peek(), Some(&"of")); - assert_eq!(it.next_if_eq(&"of"), Some("of")); - assert_eq!(it.next_if_eq(&"zaphod"), None); - // make sure `next()` still behaves - assert_eq!(it.next(), Some("Gold")); - - // make sure comparison works for owned values - let xs = vec![String::from("Ludicrous"), "speed".into()]; - let mut it = xs.into_iter().peekable(); - // make sure basic functionality works - assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into())); - assert_eq!(it.next_if_eq("speed"), Some("speed".into())); - assert_eq!(it.next_if_eq(""), None); -} - -#[test] -fn test_iterator_peekable_mut() { - let mut it = vec![1, 2, 3].into_iter().peekable(); - if let Some(p) = it.peek_mut() { - if *p == 1 { - *p = 5; - } - } - assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]); -} - -#[test] -fn test_iterator_peekable_remember_peek_none_1() { - // Check that the loop using .peek() terminates - let data = [1, 2, 3]; - let mut iter = CycleIter::new(&data).peekable(); - - let mut n = 0; - while let Some(_) = iter.next() { - let is_the_last = iter.peek().is_none(); - assert_eq!(is_the_last, n == data.len() - 1); - n += 1; - if n > data.len() { - break; - } - } - assert_eq!(n, data.len()); -} - -#[test] -fn test_iterator_peekable_remember_peek_none_2() { - let data = [0]; - let mut iter = CycleIter::new(&data).peekable(); - iter.next(); - assert_eq!(iter.peek(), None); - assert_eq!(iter.last(), None); -} - -#[test] -fn test_iterator_peekable_remember_peek_none_3() { - let data = [0]; - let mut iter = CycleIter::new(&data).peekable(); - iter.peek(); - assert_eq!(iter.nth(0), Some(&0)); - - let mut iter = CycleIter::new(&data).peekable(); - iter.next(); - assert_eq!(iter.peek(), None); - assert_eq!(iter.nth(0), None); -} - -#[test] -fn test_peek_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - - assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f)); - assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f)); - - let mut iter = (1..20).peekable(); - assert_eq!(iter.peek(), Some(&1)); - assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f)); - - let mut iter = (1..20).peekable(); - assert_eq!(iter.peek(), Some(&1)); - assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f)); - - let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); - assert_eq!(iter.peek(), Some(&100)); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.peek(), Some(&40)); - - let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); - assert_eq!(iter.peek(), Some(&100)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.peek(), Some(&100)); - assert_eq!(iter.next_back(), Some(50)); - - let mut iter = (2..5).peekable(); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_for_each(Err), Err(2)); - assert_eq!(iter.peek(), Some(&3)); - assert_eq!(iter.try_for_each(Err), Err(3)); - assert_eq!(iter.peek(), Some(&4)); - assert_eq!(iter.try_for_each(Err), Err(4)); - assert_eq!(iter.peek(), None); - assert_eq!(iter.try_for_each(Err), Ok(())); - - let mut iter = (2..5).peekable(); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4)); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3)); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2)); - assert_eq!(iter.peek(), None); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(())); -} - -#[test] -fn test_peekable_non_fused() { - let mut iter = NonFused::new(empty::<i32>()).peekable(); - - assert_eq!(iter.peek(), None); - assert_eq!(iter.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/scan.rs b/library/core/tests/iter/adapters/scan.rs deleted file mode 100644 index 1d28ca6b7fdc5..0000000000000 --- a/library/core/tests/iter/adapters/scan.rs +++ /dev/null @@ -1,20 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_scan() { - // test the type inference - fn add(old: &mut isize, new: &usize) -> Option<f64> { - *old += *new as isize; - Some(*old as f64) - } - let xs = [0, 1, 2, 3, 4]; - let ys = [0f64, 1.0, 3.0, 6.0, 10.0]; - - let it = xs.iter().scan(0, add); - let mut i = 0; - for x in it { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs deleted file mode 100644 index cf60057a1644a..0000000000000 --- a/library/core/tests/iter/adapters/skip.rs +++ /dev/null @@ -1,181 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_skip() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let ys = [13, 15, 16, 17, 19, 20, 30]; - let mut it = xs.iter().skip(5); - let mut i = 0; - while let Some(&x) = it.next() { - assert_eq!(x, ys[i]); - i += 1; - assert_eq!(it.len(), xs.len() - 5 - i); - } - assert_eq!(i, ys.len()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_iterator_skip_doubleended() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let mut it = xs.iter().rev().skip(5); - assert_eq!(it.next(), Some(&15)); - assert_eq!(it.by_ref().rev().next(), Some(&0)); - assert_eq!(it.next(), Some(&13)); - assert_eq!(it.by_ref().rev().next(), Some(&1)); - assert_eq!(it.next(), Some(&5)); - assert_eq!(it.by_ref().rev().next(), Some(&2)); - assert_eq!(it.next(), Some(&3)); - assert_eq!(it.next(), None); - let mut it = xs.iter().rev().skip(5).rev(); - assert_eq!(it.next(), Some(&0)); - assert_eq!(it.rev().next(), Some(&15)); - let mut it_base = xs.iter(); - { - let mut it = it_base.by_ref().skip(5).rev(); - assert_eq!(it.next(), Some(&30)); - assert_eq!(it.next(), Some(&20)); - assert_eq!(it.next(), Some(&19)); - assert_eq!(it.next(), Some(&17)); - assert_eq!(it.next(), Some(&16)); - assert_eq!(it.next(), Some(&15)); - assert_eq!(it.next(), Some(&13)); - assert_eq!(it.next(), None); - } - // make sure the skipped parts have not been consumed - assert_eq!(it_base.next(), Some(&0)); - assert_eq!(it_base.next(), Some(&1)); - assert_eq!(it_base.next(), Some(&2)); - assert_eq!(it_base.next(), Some(&3)); - assert_eq!(it_base.next(), Some(&5)); - assert_eq!(it_base.next(), None); - let it = xs.iter().skip(5).rev(); - assert_eq!(it.last(), Some(&13)); -} - -#[test] -fn test_iterator_skip_nth() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - - let mut it = xs.iter().skip(0); - assert_eq!(it.nth(0), Some(&0)); - assert_eq!(it.nth(1), Some(&2)); - - let mut it = xs.iter().skip(5); - assert_eq!(it.nth(0), Some(&13)); - assert_eq!(it.nth(1), Some(&16)); - - let mut it = xs.iter().skip(12); - assert_eq!(it.nth(0), None); -} - -#[test] -fn test_iterator_skip_count() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - - assert_eq!(xs.iter().skip(0).count(), 12); - assert_eq!(xs.iter().skip(1).count(), 11); - assert_eq!(xs.iter().skip(11).count(), 1); - assert_eq!(xs.iter().skip(12).count(), 0); - assert_eq!(xs.iter().skip(13).count(), 0); -} - -#[test] -fn test_iterator_skip_last() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - - assert_eq!(xs.iter().skip(0).last(), Some(&30)); - assert_eq!(xs.iter().skip(1).last(), Some(&30)); - assert_eq!(xs.iter().skip(11).last(), Some(&30)); - assert_eq!(xs.iter().skip(12).last(), None); - assert_eq!(xs.iter().skip(13).last(), None); - - let mut it = xs.iter().skip(5); - assert_eq!(it.next(), Some(&13)); - assert_eq!(it.last(), Some(&30)); -} - -#[test] -fn test_iterator_skip_fold() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let ys = [13, 15, 16, 17, 19, 20, 30]; - - let it = xs.iter().skip(5); - let i = it.fold(0, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().skip(5); - assert_eq!(it.next(), Some(&ys[0])); // process skips before folding - let i = it.fold(1, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let it = xs.iter().skip(5); - let i = it.rfold(ys.len(), |i, &x| { - let i = i - 1; - assert_eq!(x, ys[i]); - i - }); - assert_eq!(i, 0); - - let mut it = xs.iter().skip(5); - assert_eq!(it.next(), Some(&ys[0])); // process skips before folding - let i = it.rfold(ys.len(), |i, &x| { - let i = i - 1; - assert_eq!(x, ys[i]); - i - }); - assert_eq!(i, 1); -} - -#[test] -fn test_skip_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f)); - assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f)); - - let mut iter = (0..30).skip(10); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(24)); -} - -#[test] -fn test_skip_nth_back() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().skip(2); - assert_eq!(it.nth_back(0), Some(&5)); - assert_eq!(it.nth_back(1), Some(&3)); - assert_eq!(it.nth_back(0), Some(&2)); - assert_eq!(it.nth_back(0), None); - - let ys = [2, 3, 4, 5]; - let mut ity = ys.iter(); - let mut it = xs.iter().skip(2); - assert_eq!(it.nth_back(1), ity.nth_back(1)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - assert_eq!(it.nth_back(0), ity.nth_back(0)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - assert_eq!(it.nth_back(0), ity.nth_back(0)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - assert_eq!(it.nth_back(0), ity.nth_back(0)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - - let mut it = xs.iter().skip(2); - assert_eq!(it.nth_back(4), None); - assert_eq!(it.nth_back(0), None); - - let mut it = xs.iter(); - it.by_ref().skip(2).nth_back(3); - assert_eq!(it.next_back(), Some(&1)); - - let mut it = xs.iter(); - it.by_ref().skip(2).nth_back(10); - assert_eq!(it.next_back(), Some(&1)); -} diff --git a/library/core/tests/iter/adapters/skip_while.rs b/library/core/tests/iter/adapters/skip_while.rs deleted file mode 100644 index 929d4f6e64fd0..0000000000000 --- a/library/core/tests/iter/adapters/skip_while.rs +++ /dev/null @@ -1,50 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_skip_while() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [15, 16, 17, 19]; - let it = xs.iter().skip_while(|&x| *x < 15); - let mut i = 0; - for x in it { - assert_eq!(*x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -#[test] -fn test_iterator_skip_while_fold() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [15, 16, 17, 19]; - let it = xs.iter().skip_while(|&x| *x < 15); - let i = it.fold(0, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().skip_while(|&x| *x < 15); - assert_eq!(it.next(), Some(&ys[0])); // process skips before folding - let i = it.fold(1, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); -} - -#[test] -fn test_skip_while_try_fold() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - fn p(&x: &i32) -> bool { - (x % 10) <= 5 - } - assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f)); - let mut iter = (1..20).skip_while(p); - assert_eq!(iter.nth(5), Some(11)); - assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f)); - - let mut iter = (0..50).skip_while(|&x| (x % 20) < 15); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(23)); -} diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs deleted file mode 100644 index 6502c7fb79588..0000000000000 --- a/library/core/tests/iter/adapters/step_by.rs +++ /dev/null @@ -1,248 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_step_by() { - // Identity - let mut it = (0..).step_by(1).take(3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), None); - - let mut it = (0..).step_by(3).take(4); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(3)); - assert_eq!(it.next(), Some(6)); - assert_eq!(it.next(), Some(9)); - assert_eq!(it.next(), None); - - let mut it = (0..3).step_by(1); - assert_eq!(it.next_back(), Some(2)); - assert_eq!(it.next_back(), Some(1)); - assert_eq!(it.next_back(), Some(0)); - assert_eq!(it.next_back(), None); - - let mut it = (0..11).step_by(3); - assert_eq!(it.next_back(), Some(9)); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(it.next_back(), Some(3)); - assert_eq!(it.next_back(), Some(0)); - assert_eq!(it.next_back(), None); -} - -#[test] -fn test_iterator_step_by_nth() { - let mut it = (0..16).step_by(5); - assert_eq!(it.nth(0), Some(0)); - assert_eq!(it.nth(0), Some(5)); - assert_eq!(it.nth(0), Some(10)); - assert_eq!(it.nth(0), Some(15)); - assert_eq!(it.nth(0), None); - - let it = (0..18).step_by(5); - assert_eq!(it.clone().nth(0), Some(0)); - assert_eq!(it.clone().nth(1), Some(5)); - assert_eq!(it.clone().nth(2), Some(10)); - assert_eq!(it.clone().nth(3), Some(15)); - assert_eq!(it.clone().nth(4), None); - assert_eq!(it.clone().nth(42), None); -} - -#[test] -fn test_iterator_step_by_nth_overflow() { - #[cfg(target_pointer_width = "8")] - type Bigger = u16; - #[cfg(target_pointer_width = "16")] - type Bigger = u32; - #[cfg(target_pointer_width = "32")] - type Bigger = u64; - #[cfg(target_pointer_width = "64")] - type Bigger = u128; - - #[derive(Clone)] - struct Test(Bigger); - impl Iterator for &mut Test { - type Item = i32; - fn next(&mut self) -> Option<Self::Item> { - Some(21) - } - fn nth(&mut self, n: usize) -> Option<Self::Item> { - self.0 += n as Bigger + 1; - Some(42) - } - } - - let mut it = Test(0); - let root = usize::MAX >> (usize::BITS / 2); - let n = root + 20; - (&mut it).step_by(n).nth(n); - assert_eq!(it.0, n as Bigger * n as Bigger); - - // large step - let mut it = Test(0); - (&mut it).step_by(usize::MAX).nth(5); - assert_eq!(it.0, (usize::MAX as Bigger) * 5); - - // n + 1 overflows - let mut it = Test(0); - (&mut it).step_by(2).nth(usize::MAX); - assert_eq!(it.0, (usize::MAX as Bigger) * 2); - - // n + 1 overflows - let mut it = Test(0); - (&mut it).step_by(1).nth(usize::MAX); - assert_eq!(it.0, (usize::MAX as Bigger) * 1); -} - -#[test] -fn test_iterator_step_by_nth_try_fold() { - let mut it = (0..).step_by(10); - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it.next(), Some(60)); - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it.next(), Some(90)); - - let mut it = (100..).step_by(10); - assert_eq!(it.try_fold(50, i8::checked_add), None); - assert_eq!(it.next(), Some(110)); - - let mut it = (100..=100).step_by(10); - assert_eq!(it.next(), Some(100)); - assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); -} - -#[test] -fn test_iterator_step_by_nth_back() { - let mut it = (0..16).step_by(5); - assert_eq!(it.nth_back(0), Some(15)); - assert_eq!(it.nth_back(0), Some(10)); - assert_eq!(it.nth_back(0), Some(5)); - assert_eq!(it.nth_back(0), Some(0)); - assert_eq!(it.nth_back(0), None); - - let mut it = (0..16).step_by(5); - assert_eq!(it.next(), Some(0)); // to set `first_take` to `false` - assert_eq!(it.nth_back(0), Some(15)); - assert_eq!(it.nth_back(0), Some(10)); - assert_eq!(it.nth_back(0), Some(5)); - assert_eq!(it.nth_back(0), None); - - let it = || (0..18).step_by(5); - assert_eq!(it().nth_back(0), Some(15)); - assert_eq!(it().nth_back(1), Some(10)); - assert_eq!(it().nth_back(2), Some(5)); - assert_eq!(it().nth_back(3), Some(0)); - assert_eq!(it().nth_back(4), None); - assert_eq!(it().nth_back(42), None); -} - -#[test] -fn test_iterator_step_by_nth_try_rfold() { - let mut it = (0..100).step_by(10); - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it.next_back(), Some(70)); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it.next_back(), Some(30)); - - let mut it = (0..100).step_by(10); - assert_eq!(it.try_rfold(50, i8::checked_add), None); - assert_eq!(it.next_back(), Some(80)); - - let mut it = (100..=100).step_by(10); - assert_eq!(it.next_back(), Some(100)); - assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); -} - -#[test] -#[should_panic] -fn test_iterator_step_by_zero() { - let mut it = (0..).step_by(0); - it.next(); -} - -#[test] -fn test_iterator_step_by_size_hint() { - struct StubSizeHint(usize, Option<usize>); - impl Iterator for StubSizeHint { - type Item = (); - fn next(&mut self) -> Option<()> { - self.0 -= 1; - if let Some(ref mut upper) = self.1 { - *upper -= 1; - } - Some(()) - } - fn size_hint(&self) -> (usize, Option<usize>) { - (self.0, self.1) - } - } - - // The two checks in each case are needed because the logic - // is different before the first call to `next()`. - - let mut it = StubSizeHint(10, Some(10)).step_by(1); - assert_eq!(it.size_hint(), (10, Some(10))); - it.next(); - assert_eq!(it.size_hint(), (9, Some(9))); - - // exact multiple - let mut it = StubSizeHint(10, Some(10)).step_by(3); - assert_eq!(it.size_hint(), (4, Some(4))); - it.next(); - assert_eq!(it.size_hint(), (3, Some(3))); - - // larger base range, but not enough to get another element - let mut it = StubSizeHint(12, Some(12)).step_by(3); - assert_eq!(it.size_hint(), (4, Some(4))); - it.next(); - assert_eq!(it.size_hint(), (3, Some(3))); - - // smaller base range, so fewer resulting elements - let mut it = StubSizeHint(9, Some(9)).step_by(3); - assert_eq!(it.size_hint(), (3, Some(3))); - it.next(); - assert_eq!(it.size_hint(), (2, Some(2))); - - // infinite upper bound - let mut it = StubSizeHint(usize::MAX, None).step_by(1); - assert_eq!(it.size_hint(), (usize::MAX, None)); - it.next(); - assert_eq!(it.size_hint(), (usize::MAX - 1, None)); - - // still infinite with larger step - let mut it = StubSizeHint(7, None).step_by(3); - assert_eq!(it.size_hint(), (3, None)); - it.next(); - assert_eq!(it.size_hint(), (2, None)); - - // propagates ExactSizeIterator - let a = [1, 2, 3, 4, 5]; - let it = a.iter().step_by(2); - assert_eq!(it.len(), 3); - - // Cannot be TrustedLen as a step greater than one makes an iterator - // with (usize::MAX, None) no longer meet the safety requirements - trait TrustedLenCheck { - fn test(self) -> bool; - } - impl<T: Iterator> TrustedLenCheck for T { - default fn test(self) -> bool { - false - } - } - impl<T: TrustedLen> TrustedLenCheck for T { - fn test(self) -> bool { - true - } - } - assert!(TrustedLenCheck::test(a.iter())); - assert!(!TrustedLenCheck::test(a.iter().step_by(1))); -} - -#[test] -fn test_step_by_skip() { - assert_eq!((0..640).step_by(128).skip(1).collect::<Vec<_>>(), [128, 256, 384, 512]); - assert_eq!((0..=50).step_by(10).nth(3), Some(30)); - assert_eq!((200..=255u8).step_by(10).nth(3), Some(230)); -} diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs deleted file mode 100644 index 89f9cb1e2ed1b..0000000000000 --- a/library/core/tests/iter/adapters/take.rs +++ /dev/null @@ -1,126 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_take() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [0, 1, 2, 3, 5]; - - let mut it = xs.iter().take(ys.len()); - let mut i = 0; - assert_eq!(it.len(), ys.len()); - while let Some(&x) = it.next() { - assert_eq!(x, ys[i]); - i += 1; - assert_eq!(it.len(), ys.len() - i); - } - assert_eq!(i, ys.len()); - assert_eq!(it.len(), 0); - - let mut it = xs.iter().take(ys.len()); - let mut i = 0; - assert_eq!(it.len(), ys.len()); - while let Some(&x) = it.next_back() { - i += 1; - assert_eq!(x, ys[ys.len() - i]); - assert_eq!(it.len(), ys.len() - i); - } - assert_eq!(i, ys.len()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_iterator_take_nth() { - let xs = [0, 1, 2, 4, 5]; - let mut it = xs.iter(); - { - let mut take = it.by_ref().take(3); - let mut i = 0; - while let Some(&x) = take.nth(0) { - assert_eq!(x, i); - i += 1; - } - } - assert_eq!(it.nth(1), Some(&5)); - assert_eq!(it.nth(0), None); - - let xs = [0, 1, 2, 3, 4]; - let mut it = xs.iter().take(7); - let mut i = 1; - while let Some(&x) = it.nth(1) { - assert_eq!(x, i); - i += 2; - } -} - -#[test] -fn test_iterator_take_nth_back() { - let xs = [0, 1, 2, 4, 5]; - let mut it = xs.iter(); - { - let mut take = it.by_ref().take(3); - let mut i = 0; - while let Some(&x) = take.nth_back(0) { - i += 1; - assert_eq!(x, 3 - i); - } - } - assert_eq!(it.nth_back(0), None); - - let xs = [0, 1, 2, 3, 4]; - let mut it = xs.iter().take(7); - assert_eq!(it.nth_back(1), Some(&3)); - assert_eq!(it.nth_back(1), Some(&1)); - assert_eq!(it.nth_back(1), None); -} - -#[test] -fn test_iterator_take_short() { - let xs = [0, 1, 2, 3]; - - let mut it = xs.iter().take(5); - let mut i = 0; - assert_eq!(it.len(), xs.len()); - while let Some(&x) = it.next() { - assert_eq!(x, xs[i]); - i += 1; - assert_eq!(it.len(), xs.len() - i); - } - assert_eq!(i, xs.len()); - assert_eq!(it.len(), 0); - - let mut it = xs.iter().take(5); - let mut i = 0; - assert_eq!(it.len(), xs.len()); - while let Some(&x) = it.next_back() { - i += 1; - assert_eq!(x, xs[xs.len() - i]); - assert_eq!(it.len(), xs.len() - i); - } - assert_eq!(i, xs.len()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_take_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f)); - assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f)); - - let mut iter = (10..30).take(20); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(24)); - - let mut iter = (2..20).take(3); - assert_eq!(iter.try_for_each(Err), Err(2)); - assert_eq!(iter.try_for_each(Err), Err(3)); - assert_eq!(iter.try_for_each(Err), Err(4)); - assert_eq!(iter.try_for_each(Err), Ok(())); - - let mut iter = (2..20).take(3).rev(); - assert_eq!(iter.try_for_each(Err), Err(4)); - assert_eq!(iter.try_for_each(Err), Err(3)); - assert_eq!(iter.try_for_each(Err), Err(2)); - assert_eq!(iter.try_for_each(Err), Ok(())); -} diff --git a/library/core/tests/iter/adapters/take_while.rs b/library/core/tests/iter/adapters/take_while.rs deleted file mode 100644 index 6f1ebab29b31c..0000000000000 --- a/library/core/tests/iter/adapters/take_while.rs +++ /dev/null @@ -1,29 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_take_while() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [0, 1, 2, 3, 5, 13]; - let it = xs.iter().take_while(|&x| *x < 15); - let mut i = 0; - for x in it { - assert_eq!(*x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -#[test] -fn test_take_while_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f)); - let mut iter = (1..20).take_while(|&x| x != 10); - assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum())); - assert_eq!(iter.next(), None, "flag should be set"); - let iter = (1..20).take_while(|&x| x != 10); - assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum()); - - let mut iter = (10..50).take_while(|&x| x != 40); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); -} diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs deleted file mode 100644 index 1fce0951e365e..0000000000000 --- a/library/core/tests/iter/adapters/zip.rs +++ /dev/null @@ -1,247 +0,0 @@ -use super::*; -use core::iter::*; - -#[test] -fn test_zip_nth() { - let xs = [0, 1, 2, 4, 5]; - let ys = [10, 11, 12]; - - let mut it = xs.iter().zip(&ys); - assert_eq!(it.nth(0), Some((&0, &10))); - assert_eq!(it.nth(1), Some((&2, &12))); - assert_eq!(it.nth(0), None); - - let mut it = xs.iter().zip(&ys); - assert_eq!(it.nth(3), None); - - let mut it = ys.iter().zip(&xs); - assert_eq!(it.nth(3), None); -} - -#[test] -fn test_zip_nth_side_effects() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let value = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })) - .skip(1) - .nth(3); - assert_eq!(value, Some((50, 6000))); - assert_eq!(a, vec![1, 2, 3, 4, 5]); - assert_eq!(b, vec![200, 300, 400, 500, 600]); -} - -#[test] -fn test_zip_next_back_side_effects() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let mut iter = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })); - - // The second iterator is one item longer, so `next_back` is called on it - // one more time. - assert_eq!(iter.next_back(), Some((60, 7000))); - assert_eq!(iter.next_back(), Some((50, 6000))); - assert_eq!(iter.next_back(), Some((40, 5000))); - assert_eq!(iter.next_back(), Some((30, 4000))); - assert_eq!(a, vec![6, 5, 4, 3]); - assert_eq!(b, vec![800, 700, 600, 500, 400]); -} - -#[test] -fn test_zip_nth_back_side_effects() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let value = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })) - .nth_back(3); - assert_eq!(value, Some((30, 4000))); - assert_eq!(a, vec![6, 5, 4, 3]); - assert_eq!(b, vec![800, 700, 600, 500, 400]); -} - -#[test] -fn test_zip_next_back_side_effects_exhausted() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let mut iter = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })); - - iter.next(); - iter.next(); - iter.next(); - iter.next(); - assert_eq!(iter.next_back(), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); - assert_eq!(b, vec![200, 300, 400]); -} - -#[test] -fn test_zip_cloned_sideffectful() { - let xs = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()]; - let ys = [CountClone::new(), CountClone::new()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - - assert_eq!(&xs, &[1, 1, 1, 0][..]); - assert_eq!(&ys, &[1, 1][..]); - - let xs = [CountClone::new(), CountClone::new()]; - let ys = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - - assert_eq!(&xs, &[1, 1][..]); - assert_eq!(&ys, &[1, 1, 0, 0][..]); -} - -#[test] -fn test_zip_map_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); - assert_eq!(&ys, &[1, 1, 1, 1]); - - let mut xs = [0; 4]; - let mut ys = [0; 6]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - - assert_eq!(&xs, &[1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); -} - -#[test] -fn test_zip_map_rev_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - it.next_back(); - } - assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); - assert_eq!(&ys, &[0, 0, 0, 1]); - - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - (&mut it).take(5).count(); - it.next_back(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1]); -} - -#[test] -fn test_zip_nested_sideffectful() { - let mut xs = [0; 6]; - let ys = [0; 4]; - - { - // test that it has the side effect nested inside enumerate - let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); - it.count(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); -} - -#[test] -fn test_zip_nth_back_side_effects_exhausted() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let mut iter = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })); - - iter.next(); - iter.next(); - iter.next(); - iter.next(); - assert_eq!(iter.nth_back(0), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); - assert_eq!(b, vec![200, 300, 400]); -} - -#[test] -fn test_zip_trusted_random_access_composition() { - let a = [0, 1, 2, 3, 4]; - let b = a; - let c = a; - - let a = a.iter().copied(); - let b = b.iter().copied(); - let mut c = c.iter().copied(); - c.next(); - - let mut z1 = a.zip(b); - assert_eq!(z1.next().unwrap(), (0, 0)); - - let mut z2 = z1.zip(c); - fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {} - assert_trusted_random_access(&z2); - assert_eq!(z2.next().unwrap(), ((1, 1), 1)); -} - -#[test] -fn test_double_ended_zip() { - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - let a = xs.iter().cloned(); - let b = ys.iter().cloned(); - let mut it = a.zip(b); - assert_eq!(it.next(), Some((1, 1))); - assert_eq!(it.next(), Some((2, 2))); - assert_eq!(it.next_back(), Some((4, 7))); - assert_eq!(it.next_back(), Some((3, 3))); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs deleted file mode 100644 index 770b6f7601fa2..0000000000000 --- a/library/core/tests/iter/mod.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Note -//! ---- -//! You're probably viewing this file because you're adding a test (or you might -//! just be browsing, in that case, hey there!). -//! -//! The iter test suite is split into two big modules, and some miscellaneous -//! smaller modules. The two big modules are `adapters` and `traits`. -//! -//! `adapters` are for methods on `Iterator` that adapt the data inside the -//! iterator, whether it be by emitting another iterator or returning an item -//! from inside the iterator after executing a closure on each item. -//! -//! `traits` are for trait's that extend an `Iterator` (and the `Iterator` -//! trait itself, mostly containing miscellaneous methods). For the most part, -//! if a test in `traits` uses a specific adapter, then it should be moved to -//! that adapter's test file in `adapters`. - -mod adapters; -mod range; -mod sources; -mod traits; - -use core::cell::Cell; -use core::convert::TryFrom; -use core::iter::*; - -pub fn is_trusted_len<I: TrustedLen>(_: I) {} - -#[test] -fn test_multi_iter() { - let xs = [1, 2, 3, 4]; - let ys = [4, 3, 2, 1]; - assert!(xs.iter().eq(ys.iter().rev())); - assert!(xs.iter().lt(xs.iter().skip(2))); -} - -#[test] -fn test_counter_from_iter() { - let it = (0..).step_by(5).take(10); - let xs: Vec<isize> = FromIterator::from_iter(it); - assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); -} - -#[test] -fn test_functor_laws() { - // identity: - fn identity<T>(x: T) -> T { - x - } - assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum()); - - // composition: - fn f(x: usize) -> usize { - x + 3 - } - fn g(x: usize) -> usize { - x * 2 - } - fn h(x: usize) -> usize { - g(f(x)) - } - assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum()); -} - -#[test] -fn test_monad_laws_left_identity() { - fn f(x: usize) -> impl Iterator<Item = usize> { - (0..10).map(move |y| x * y) - } - assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum()); -} - -#[test] -fn test_monad_laws_right_identity() { - assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum()); -} - -#[test] -fn test_monad_laws_associativity() { - fn f(x: usize) -> impl Iterator<Item = usize> { - 0..x - } - fn g(x: usize) -> impl Iterator<Item = usize> { - (0..x).rev() - } - assert_eq!( - (0..10).flat_map(f).flat_map(g).sum::<usize>(), - (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>() - ); -} - -#[test] -pub fn extend_for_unit() { - let mut x = 0; - { - let iter = (0..5).map(|_| { - x += 1; - }); - ().extend(iter); - } - assert_eq!(x, 5); -} diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs deleted file mode 100644 index 44adc3c58d249..0000000000000 --- a/library/core/tests/iter/range.rs +++ /dev/null @@ -1,446 +0,0 @@ -use super::*; - -#[test] -fn test_range() { - assert_eq!((0..5).collect::<Vec<_>>(), [0, 1, 2, 3, 4]); - assert_eq!((-10..-1).collect::<Vec<_>>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]); - assert_eq!((0..5).rev().collect::<Vec<_>>(), [4, 3, 2, 1, 0]); - assert_eq!((200..-5).count(), 0); - assert_eq!((200..-5).rev().count(), 0); - assert_eq!((200..200).count(), 0); - assert_eq!((200..200).rev().count(), 0); - - assert_eq!((0..100).size_hint(), (100, Some(100))); - // this test is only meaningful when sizeof usize < sizeof u64 - assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1))); - assert_eq!((-10..-1).size_hint(), (9, Some(9))); - assert_eq!((-1..-10).size_hint(), (0, Some(0))); - - assert_eq!((-70..58).size_hint(), (128, Some(128))); - assert_eq!((-128..127).size_hint(), (255, Some(255))); - assert_eq!( - (-2..isize::MAX).size_hint(), - (isize::MAX as usize + 2, Some(isize::MAX as usize + 2)) - ); -} - -#[test] -fn test_char_range() { - use std::char; - // Miri is too slow - let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' }; - let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX }; - assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32))); - assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev())); - - assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); - assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2))); - assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1); - assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1))); -} - -#[test] -fn test_range_exhaustion() { - let mut r = 10..10; - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next_back(), None); - assert_eq!(r, 10..10); - - let mut r = 10..12; - assert_eq!(r.next(), Some(10)); - assert_eq!(r.next(), Some(11)); - assert!(r.is_empty()); - assert_eq!(r, 12..12); - assert_eq!(r.next(), None); - - let mut r = 10..12; - assert_eq!(r.next_back(), Some(11)); - assert_eq!(r.next_back(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r, 10..10); - assert_eq!(r.next_back(), None); - - let mut r = 100..10; - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next_back(), None); - assert_eq!(r, 100..10); -} - -#[test] -fn test_range_inclusive_exhaustion() { - let mut r = 10..=10; - assert_eq!(r.next(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next(), None); - - assert_eq!(*r.start(), 10); - assert_eq!(*r.end(), 10); - assert_ne!(r, 10..=10); - - let mut r = 10..=10; - assert_eq!(r.next_back(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r.next_back(), None); - - assert_eq!(*r.start(), 10); - assert_eq!(*r.end(), 10); - assert_ne!(r, 10..=10); - - let mut r = 10..=12; - assert_eq!(r.next(), Some(10)); - assert_eq!(r.next(), Some(11)); - assert_eq!(r.next(), Some(12)); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - - let mut r = 10..=12; - assert_eq!(r.next_back(), Some(12)); - assert_eq!(r.next_back(), Some(11)); - assert_eq!(r.next_back(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r.next_back(), None); - - let mut r = 10..=12; - assert_eq!(r.nth(2), Some(12)); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - - let mut r = 10..=12; - assert_eq!(r.nth(5), None); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - - let mut r = 100..=10; - assert_eq!(r.next(), None); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next(), None); - assert_eq!(r, 100..=10); - - let mut r = 100..=10; - assert_eq!(r.next_back(), None); - assert!(r.is_empty()); - assert_eq!(r.next_back(), None); - assert_eq!(r.next_back(), None); - assert_eq!(r, 100..=10); -} - -#[test] -fn test_range_nth() { - assert_eq!((10..15).nth(0), Some(10)); - assert_eq!((10..15).nth(1), Some(11)); - assert_eq!((10..15).nth(4), Some(14)); - assert_eq!((10..15).nth(5), None); - - let mut r = 10..20; - assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13..20); - assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16..20); - assert_eq!(r.nth(10), None); - assert_eq!(r, 20..20); -} - -#[test] -fn test_range_nth_back() { - assert_eq!((10..15).nth_back(0), Some(14)); - assert_eq!((10..15).nth_back(1), Some(13)); - assert_eq!((10..15).nth_back(4), Some(10)); - assert_eq!((10..15).nth_back(5), None); - assert_eq!((-120..80_i8).nth_back(199), Some(-120)); - - let mut r = 10..20; - assert_eq!(r.nth_back(2), Some(17)); - assert_eq!(r, 10..17); - assert_eq!(r.nth_back(2), Some(14)); - assert_eq!(r, 10..14); - assert_eq!(r.nth_back(10), None); - assert_eq!(r, 10..10); -} - -#[test] -fn test_range_from_nth() { - assert_eq!((10..).nth(0), Some(10)); - assert_eq!((10..).nth(1), Some(11)); - assert_eq!((10..).nth(4), Some(14)); - - let mut r = 10..; - assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13..); - assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16..); - assert_eq!(r.nth(10), Some(26)); - assert_eq!(r, 27..); - - assert_eq!((0..).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_range_from_take() { - let mut it = (0..).take(3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), None); - is_trusted_len((0..).take(3)); - assert_eq!((0..).take(3).size_hint(), (3, Some(3))); - assert_eq!((0..).take(0).size_hint(), (0, Some(0))); - assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_range_from_take_collect() { - let v: Vec<_> = (0..).take(3).collect(); - assert_eq!(v, vec![0, 1, 2]); -} - -#[test] -fn test_range_inclusive_nth() { - assert_eq!((10..=15).nth(0), Some(10)); - assert_eq!((10..=15).nth(1), Some(11)); - assert_eq!((10..=15).nth(5), Some(15)); - assert_eq!((10..=15).nth(6), None); - - let mut exhausted_via_next = 10_u8..=20; - while exhausted_via_next.next().is_some() {} - - let mut r = 10_u8..=20; - assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13..=20); - assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16..=20); - assert_eq!(r.is_empty(), false); - assert_eq!(ExactSizeIterator::is_empty(&r), false); - assert_eq!(r.nth(10), None); - assert_eq!(r.is_empty(), true); - assert_eq!(r, exhausted_via_next); - assert_eq!(ExactSizeIterator::is_empty(&r), true); -} - -#[test] -fn test_range_inclusive_nth_back() { - assert_eq!((10..=15).nth_back(0), Some(15)); - assert_eq!((10..=15).nth_back(1), Some(14)); - assert_eq!((10..=15).nth_back(5), Some(10)); - assert_eq!((10..=15).nth_back(6), None); - assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); - - let mut exhausted_via_next_back = 10_u8..=20; - while exhausted_via_next_back.next_back().is_some() {} - - let mut r = 10_u8..=20; - assert_eq!(r.nth_back(2), Some(18)); - assert_eq!(r, 10..=17); - assert_eq!(r.nth_back(2), Some(15)); - assert_eq!(r, 10..=14); - assert_eq!(r.is_empty(), false); - assert_eq!(ExactSizeIterator::is_empty(&r), false); - assert_eq!(r.nth_back(10), None); - assert_eq!(r.is_empty(), true); - assert_eq!(r, exhausted_via_next_back); - assert_eq!(ExactSizeIterator::is_empty(&r), true); -} - -#[test] -fn test_range_len() { - assert_eq!((0..10_u8).len(), 10); - assert_eq!((9..10_u8).len(), 1); - assert_eq!((10..10_u8).len(), 0); - assert_eq!((11..10_u8).len(), 0); - assert_eq!((100..10_u8).len(), 0); -} - -#[test] -fn test_range_inclusive_len() { - assert_eq!((0..=10_u8).len(), 11); - assert_eq!((9..=10_u8).len(), 2); - assert_eq!((10..=10_u8).len(), 1); - assert_eq!((11..=10_u8).len(), 0); - assert_eq!((100..=10_u8).len(), 0); -} - -#[test] -fn test_range_step() { - #![allow(deprecated)] - - assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]); - assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]); - assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]); - assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]); - assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []); - assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []); - - assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20))); - assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1))); - assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4))); - assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4))); - assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4))); - assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); - assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); - assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2))); - assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3))); - assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_range_inclusive_step() { - assert_eq!((0..=50).step_by(10).collect::<Vec<_>>(), [0, 10, 20, 30, 40, 50]); - assert_eq!((0..=5).step_by(1).collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5]); - assert_eq!((200..=255u8).step_by(10).collect::<Vec<_>>(), [200, 210, 220, 230, 240, 250]); - assert_eq!((250..=255u8).step_by(1).collect::<Vec<_>>(), [250, 251, 252, 253, 254, 255]); -} - -#[test] -fn test_range_last_max() { - assert_eq!((0..20).last(), Some(19)); - assert_eq!((-20..0).last(), Some(-1)); - assert_eq!((5..5).last(), None); - - assert_eq!((0..20).max(), Some(19)); - assert_eq!((-20..0).max(), Some(-1)); - assert_eq!((5..5).max(), None); -} - -#[test] -fn test_range_inclusive_last_max() { - assert_eq!((0..=20).last(), Some(20)); - assert_eq!((-20..=0).last(), Some(0)); - assert_eq!((5..=5).last(), Some(5)); - let mut r = 10..=10; - r.next(); - assert_eq!(r.last(), None); - - assert_eq!((0..=20).max(), Some(20)); - assert_eq!((-20..=0).max(), Some(0)); - assert_eq!((5..=5).max(), Some(5)); - let mut r = 10..=10; - r.next(); - assert_eq!(r.max(), None); -} - -#[test] -fn test_range_min() { - assert_eq!((0..20).min(), Some(0)); - assert_eq!((-20..0).min(), Some(-20)); - assert_eq!((5..5).min(), None); -} - -#[test] -fn test_range_inclusive_min() { - assert_eq!((0..=20).min(), Some(0)); - assert_eq!((-20..=0).min(), Some(-20)); - assert_eq!((5..=5).min(), Some(5)); - let mut r = 10..=10; - r.next(); - assert_eq!(r.min(), None); -} - -#[test] -fn test_range_inclusive_folds() { - assert_eq!((1..=10).sum::<i32>(), 55); - assert_eq!((1..=10).rev().sum::<i32>(), 55); - - let mut it = 44..=50; - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it, 47..=50); - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it, 50..=50); - assert_eq!(it.try_fold(0, i8::checked_add), Some(50)); - assert!(it.is_empty()); - assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); - assert!(it.is_empty()); - - let mut it = 40..=47; - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it, 40..=44); - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it, 40..=41); - assert_eq!(it.try_rfold(0, i8::checked_add), Some(81)); - assert!(it.is_empty()); - assert_eq!(it.try_rfold(0, i8::checked_add), Some(0)); - assert!(it.is_empty()); - - let mut it = 10..=20; - assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165)); - assert!(it.is_empty()); - assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0)); - assert!(it.is_empty()); - - let mut it = 10..=20; - assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165)); - assert!(it.is_empty()); - assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0)); - assert!(it.is_empty()); -} - -#[test] -fn test_range_size_hint() { - assert_eq!((0..0usize).size_hint(), (0, Some(0))); - assert_eq!((0..100usize).size_hint(), (100, Some(100))); - assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); - - let umax = u128::try_from(usize::MAX).unwrap(); - assert_eq!((0..0u128).size_hint(), (0, Some(0))); - assert_eq!((0..100u128).size_hint(), (100, Some(100))); - assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None)); - - assert_eq!((0..0isize).size_hint(), (0, Some(0))); - assert_eq!((-100..100isize).size_hint(), (200, Some(200))); - assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); - - let imin = i128::try_from(isize::MIN).unwrap(); - let imax = i128::try_from(isize::MAX).unwrap(); - assert_eq!((0..0i128).size_hint(), (0, Some(0))); - assert_eq!((-100..100i128).size_hint(), (200, Some(200))); - assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_range_inclusive_size_hint() { - assert_eq!((1..=0usize).size_hint(), (0, Some(0))); - assert_eq!((0..=0usize).size_hint(), (1, Some(1))); - assert_eq!((0..=100usize).size_hint(), (101, Some(101))); - assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None)); - - let umax = u128::try_from(usize::MAX).unwrap(); - assert_eq!((1..=0u128).size_hint(), (0, Some(0))); - assert_eq!((0..=0u128).size_hint(), (1, Some(1))); - assert_eq!((0..=100u128).size_hint(), (101, Some(101))); - assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((0..=umax).size_hint(), (usize::MAX, None)); - assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None)); - - assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); - assert_eq!((0..=0isize).size_hint(), (1, Some(1))); - assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); - assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None)); - - let imin = i128::try_from(isize::MIN).unwrap(); - let imax = i128::try_from(isize::MAX).unwrap(); - assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); - assert_eq!((0..=0i128).size_hint(), (1, Some(1))); - assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); - assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((imin..=imax).size_hint(), (usize::MAX, None)); - assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_double_ended_range() { - assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]); - for _ in (10..0).rev() { - panic!("unreachable"); - } - - assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]); - for _ in (10..0).rev() { - panic!("unreachable"); - } -} diff --git a/library/core/tests/iter/sources.rs b/library/core/tests/iter/sources.rs deleted file mode 100644 index d0114ade6e463..0000000000000 --- a/library/core/tests/iter/sources.rs +++ /dev/null @@ -1,108 +0,0 @@ -use super::*; -use core::iter::*; - -#[test] -fn test_repeat() { - let mut it = repeat(42); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(repeat(42).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_repeat_take() { - let mut it = repeat(42).take(3); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), None); - is_trusted_len(repeat(42).take(3)); - assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3))); - assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0))); - assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_repeat_take_collect() { - let v: Vec<_> = repeat(42).take(3).collect(); - assert_eq!(v, vec![42, 42, 42]); -} - -#[test] -fn test_repeat_with() { - #[derive(PartialEq, Debug)] - struct NotClone(usize); - let mut it = repeat_with(|| NotClone(42)); - assert_eq!(it.next(), Some(NotClone(42))); - assert_eq!(it.next(), Some(NotClone(42))); - assert_eq!(it.next(), Some(NotClone(42))); - assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_repeat_with_take() { - let mut it = repeat_with(|| 42).take(3); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), None); - is_trusted_len(repeat_with(|| 42).take(3)); - assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); - assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); - assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_repeat_with_take_collect() { - let mut curr = 1; - let v: Vec<_> = repeat_with(|| { - let tmp = curr; - curr *= 2; - tmp - }) - .take(5) - .collect(); - assert_eq!(v, vec![1, 2, 4, 8, 16]); -} - -#[test] -fn test_successors() { - let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); - assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]); - assert_eq!(powers_of_10.next(), None); - - let mut empty = successors(None::<u32>, |_| unimplemented!()); - assert_eq!(empty.next(), None); - assert_eq!(empty.next(), None); -} - -#[test] -fn test_once() { - let mut it = once(42); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_once_with() { - let count = Cell::new(0); - let mut it = once_with(|| { - count.set(count.get() + 1); - 42 - }); - - assert_eq!(count.get(), 0); - assert_eq!(it.next(), Some(42)); - assert_eq!(count.get(), 1); - assert_eq!(it.next(), None); - assert_eq!(count.get(), 1); - assert_eq!(it.next(), None); - assert_eq!(count.get(), 1); -} - -#[test] -fn test_empty() { - let mut it = empty::<i32>(); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/traits/accum.rs b/library/core/tests/iter/traits/accum.rs deleted file mode 100644 index f3eeb31fe5803..0000000000000 --- a/library/core/tests/iter/traits/accum.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_sum() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().sum::<i32>(), 6); - assert_eq!(v.iter().cloned().sum::<i32>(), 55); - assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0); -} - -#[test] -fn test_iterator_sum_result() { - let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10)); - let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(())); - - #[derive(PartialEq, Debug)] - struct S(Result<i32, ()>); - - impl Sum<Result<i32, ()>> for S { - fn sum<I: Iterator<Item = Result<i32, ()>>>(mut iter: I) -> Self { - // takes the sum by repeatedly calling `next` on `iter`, - // thus testing that repeated calls to `ResultShunt::try_fold` - // produce the expected results - Self(iter.by_ref().sum()) - } - } - - let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::<S>(), S(Ok(10))); - let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::<S>(), S(Err(()))); -} - -#[test] -fn test_iterator_sum_option() { - let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)]; - assert_eq!(v.iter().cloned().sum::<Option<i32>>(), Some(10)); - let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)]; - assert_eq!(v.iter().cloned().sum::<Option<i32>>(), None); -} - -#[test] -fn test_iterator_product() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().product::<i32>(), 0); - assert_eq!(v[1..5].iter().cloned().product::<i32>(), 24); - assert_eq!(v[..0].iter().cloned().product::<i32>(), 1); -} - -#[test] -fn test_iterator_product_result() { - let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24)); - let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(())); -} - -#[test] -fn test_iterator_product_option() { - let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)]; - assert_eq!(v.iter().cloned().product::<Option<i32>>(), Some(24)); - let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)]; - assert_eq!(v.iter().cloned().product::<Option<i32>>(), None); -} diff --git a/library/core/tests/iter/traits/double_ended.rs b/library/core/tests/iter/traits/double_ended.rs deleted file mode 100644 index 947d19d3dfed0..0000000000000 --- a/library/core/tests/iter/traits/double_ended.rs +++ /dev/null @@ -1,90 +0,0 @@ -//! Note -//! ---- -//! You're probably viewing this file because you're adding a test (or you might -//! just be browsing, in that case, hey there!). -//! -//! If you've made a test that happens to use one of DoubleEnded's methods, but -//! it tests another adapter or trait, you should *add it to the adapter or -//! trait's test file*. -//! -//! Some examples would be `adapters::cloned::test_cloned_try_folds` or -//! `adapters::flat_map::test_double_ended_flat_map`, which use `try_fold` and -//! `next_back`, but test their own adapter. - -#[test] -fn test_iterator_rev_nth_back() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]); - } - assert_eq!(v.iter().rev().nth_back(v.len()), None); -} - -#[test] -fn test_iterator_rev_nth() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]); - } - assert_eq!(v.iter().rev().nth(v.len()), None); -} - -#[test] -fn test_rev() { - let xs = [2, 4, 6, 8, 10, 12, 14, 16]; - let mut it = xs.iter(); - it.next(); - it.next(); - assert!(it.rev().cloned().collect::<Vec<isize>>() == vec![16, 14, 12, 10, 8, 6]); -} - -#[test] -fn test_rev_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f)); - assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f)); - - let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; - let mut iter = a.iter().rev(); - assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); - assert_eq!(iter.next(), Some(&70)); - let mut iter = a.iter().rev(); - assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); - assert_eq!(iter.next_back(), Some(&60)); -} - -#[test] -fn test_rposition() { - fn f(xy: &(isize, char)) -> bool { - let (_x, y) = *xy; - y == 'b' - } - fn g(xy: &(isize, char)) -> bool { - let (_x, y) = *xy; - y == 'd' - } - let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(v.iter().rposition(f), Some(3)); - assert!(v.iter().rposition(g).is_none()); -} - -#[test] -fn test_rev_rposition() { - let v = [0, 0, 1, 1]; - assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1)); -} - -#[test] -#[should_panic] -fn test_rposition_panic() { - let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), (box 0, box 0), (box 0, box 0)]; - let mut i = 0; - v.iter().rposition(|_elt| { - if i == 2 { - panic!() - } - i += 1; - false - }); -} diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs deleted file mode 100644 index 422e389e38017..0000000000000 --- a/library/core/tests/iter/traits/iterator.rs +++ /dev/null @@ -1,470 +0,0 @@ -/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped -/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min` -/// return the correct element if some of them are equal. -#[derive(Debug)] -struct Mod3(i32); - -impl PartialEq for Mod3 { - fn eq(&self, other: &Self) -> bool { - self.0 % 3 == other.0 % 3 - } -} - -impl Eq for Mod3 {} - -impl PartialOrd for Mod3 { - fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Mod3 { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - (self.0 % 3).cmp(&(other.0 % 3)) - } -} - -#[test] -fn test_lt() { - let empty: [isize; 0] = []; - let xs = [1, 2, 3]; - let ys = [1, 2, 0]; - - assert!(!xs.iter().lt(ys.iter())); - assert!(!xs.iter().le(ys.iter())); - assert!(xs.iter().gt(ys.iter())); - assert!(xs.iter().ge(ys.iter())); - - assert!(ys.iter().lt(xs.iter())); - assert!(ys.iter().le(xs.iter())); - assert!(!ys.iter().gt(xs.iter())); - assert!(!ys.iter().ge(xs.iter())); - - assert!(empty.iter().lt(xs.iter())); - assert!(empty.iter().le(xs.iter())); - assert!(!empty.iter().gt(xs.iter())); - assert!(!empty.iter().ge(xs.iter())); - - // Sequence with NaN - let u = [1.0f64, 2.0]; - let v = [0.0f64 / 0.0, 3.0]; - - assert!(!u.iter().lt(v.iter())); - assert!(!u.iter().le(v.iter())); - assert!(!u.iter().gt(v.iter())); - assert!(!u.iter().ge(v.iter())); - - let a = [0.0f64 / 0.0]; - let b = [1.0f64]; - let c = [2.0f64]; - - assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); - assert!(a.iter().le(b.iter()) == (a[0] <= b[0])); - assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); - assert!(a.iter().ge(b.iter()) == (a[0] >= b[0])); - - assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); - assert!(c.iter().le(b.iter()) == (c[0] <= b[0])); - assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); - assert!(c.iter().ge(b.iter()) == (c[0] >= b[0])); -} - -#[test] -fn test_cmp_by() { - use core::cmp::Ordering; - - let f = |x: i32, y: i32| (x * x).cmp(&y); - let xs = || [1, 2, 3, 4].iter().copied(); - let ys = || [1, 4, 16].iter().copied(); - - assert_eq!(xs().cmp_by(ys(), f), Ordering::Less); - assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater); - assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal); - assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater); - assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less); - assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater); -} - -#[test] -fn test_partial_cmp_by() { - use core::cmp::Ordering; - - let f = |x: i32, y: i32| (x * x).partial_cmp(&y); - let xs = || [1, 2, 3, 4].iter().copied(); - let ys = || [1, 4, 16].iter().copied(); - - assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less)); - assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); - assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal)); - assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater)); - assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less)); - assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater)); - - let f = |x: f64, y: f64| (x * x).partial_cmp(&y); - let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied(); - let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied(); - - assert_eq!(xs().partial_cmp_by(ys(), f), None); - assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); -} - -#[test] -fn test_eq_by() { - let f = |x: i32, y: i32| x * x == y; - let xs = || [1, 2, 3, 4].iter().copied(); - let ys = || [1, 4, 9, 16].iter().copied(); - - assert!(xs().eq_by(ys(), f)); - assert!(!ys().eq_by(xs(), f)); - assert!(!xs().eq_by(xs(), f)); - assert!(!ys().eq_by(ys(), f)); - - assert!(!xs().take(3).eq_by(ys(), f)); - assert!(!xs().eq_by(ys().take(3), f)); - assert!(xs().take(3).eq_by(ys().take(3), f)); -} - -#[test] -fn test_iterator_nth() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().nth(i).unwrap(), &v[i]); - } - assert_eq!(v.iter().nth(v.len()), None); -} - -#[test] -fn test_iterator_nth_back() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]); - } - assert_eq!(v.iter().nth_back(v.len()), None); -} - -#[test] -fn test_iterator_advance_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter(); - assert_eq!(iter.advance_by(i), Ok(())); - assert_eq!(iter.next().unwrap(), &v[i]); - assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); - } - - assert_eq!(v.iter().advance_by(v.len()), Ok(())); - assert_eq!(v.iter().advance_by(100), Err(v.len())); -} - -#[test] -fn test_iterator_advance_back_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(i), Ok(())); - assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); - } - - assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); - assert_eq!(v.iter().advance_back_by(100), Err(v.len())); -} - -#[test] -fn test_iterator_rev_advance_back_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter().rev(); - assert_eq!(iter.advance_back_by(i), Ok(())); - assert_eq!(iter.next_back().unwrap(), &v[i]); - assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); - } - - assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); - assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len())); -} - -#[test] -fn test_iterator_last() { - let v: &[_] = &[0, 1, 2, 3, 4]; - assert_eq!(v.iter().last().unwrap(), &4); - assert_eq!(v[..1].iter().last().unwrap(), &0); -} - -#[test] -fn test_iterator_max() { - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().max(), Some(3)); - assert_eq!(v.iter().cloned().max(), Some(10)); - assert_eq!(v[..0].iter().cloned().max(), None); - assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8)); -} - -#[test] -fn test_iterator_min() { - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().min(), Some(0)); - assert_eq!(v.iter().cloned().min(), Some(0)); - assert_eq!(v[..0].iter().cloned().min(), None); - assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0)); -} - -#[test] -fn test_iterator_size_hint() { - let c = (0..).step_by(1); - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let v2 = &[10, 11, 12]; - let vi = v.iter(); - - assert_eq!((0..).size_hint(), (usize::MAX, None)); - assert_eq!(c.size_hint(), (usize::MAX, None)); - assert_eq!(vi.clone().size_hint(), (10, Some(10))); - - assert_eq!(c.clone().take(5).size_hint(), (5, Some(5))); - assert_eq!(c.clone().skip(5).size_hint().1, None); - assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); - assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None)); - assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); - assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None)); - assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None)); - assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); - assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None)); - assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); - assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None)); - assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); - - assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5))); - assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10))); - assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7))); - assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0))); - assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); - assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13))); - assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3))); - assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10))); - assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); -} - -#[test] -fn test_all() { - let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); - assert!(v.iter().all(|&x| x < 10)); - assert!(!v.iter().all(|&x| x % 2 == 0)); - assert!(!v.iter().all(|&x| x > 100)); - assert!(v[..0].iter().all(|_| panic!())); -} - -#[test] -fn test_any() { - let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); - assert!(v.iter().any(|&x| x < 10)); - assert!(v.iter().any(|&x| x % 2 == 0)); - assert!(!v.iter().any(|&x| x > 100)); - assert!(!v[..0].iter().any(|_| panic!())); -} - -#[test] -fn test_find() { - let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11]; - assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14); - assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3); - assert!(v.iter().find(|&&x| x % 12 == 0).is_none()); -} - -#[test] -fn test_try_find() { - let xs: &[isize] = &[]; - assert_eq!(xs.iter().try_find(testfn), Ok(None)); - let xs: &[isize] = &[1, 2, 3, 4]; - assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2))); - let xs: &[isize] = &[1, 3, 4]; - assert_eq!(xs.iter().try_find(testfn), Err(())); - - let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; - let mut iter = xs.iter(); - assert_eq!(iter.try_find(testfn), Ok(Some(&2))); - assert_eq!(iter.try_find(testfn), Err(())); - assert_eq!(iter.next(), Some(&5)); - - fn testfn(x: &&isize) -> Result<bool, ()> { - if **x == 2 { - return Ok(true); - } - if **x == 4 { - return Err(()); - } - Ok(false) - } -} - -#[test] -fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> { - let a = ["1", "2"]; - - let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> { - Ok(s.parse::<i32>()? == search) - }; - - let val = a.iter().try_find(|&&s| is_my_num(s, 2))?; - assert_eq!(val, Some(&"2")); - - Ok(()) -} - -#[test] -fn test_position() { - let v = &[1, 3, 9, 27, 103, 14, 11]; - assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5); - assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1); - assert!(v.iter().position(|x| *x % 12 == 0).is_none()); -} - -#[test] -fn test_count() { - let xs = &[1, 2, 2, 1, 5, 9, 0, 2]; - assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3); - assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1); - assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0); -} - -#[test] -fn test_max_by_key() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10); -} - -#[test] -fn test_max_by() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10); -} - -#[test] -fn test_min_by_key() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0); -} - -#[test] -fn test_min_by() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0); -} - -#[test] -fn test_by_ref() { - let mut xs = 0..10; - // sum the first five values - let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b); - assert_eq!(partial_sum, 10); - assert_eq!(xs.next(), Some(5)); -} - -#[test] -fn test_is_sorted() { - assert!([1, 2, 2, 9].iter().is_sorted()); - assert!(![1, 3, 2].iter().is_sorted()); - assert!([0].iter().is_sorted()); - assert!(std::iter::empty::<i32>().is_sorted()); - assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); - assert!([-2, -1, 0, 3].iter().is_sorted()); - assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); - assert!(!["c", "bb", "aaa"].iter().is_sorted()); - assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); -} - -#[test] -fn test_partition() { - fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) { - let i = xs.iter_mut().partition_in_place(p); - assert_eq!(expected, i); - assert!(xs[..i].iter().all(p)); - assert!(!xs[i..].iter().any(p)); - assert!(xs.iter().is_partitioned(p)); - if i == 0 || i == xs.len() { - assert!(xs.iter().rev().is_partitioned(p)); - } else { - assert!(!xs.iter().rev().is_partitioned(p)); - } - } - - check(&mut [], |_| true, 0); - check(&mut [], |_| false, 0); - - check(&mut [0], |_| true, 1); - check(&mut [0], |_| false, 0); - - check(&mut [-1, 1], |&x| x > 0, 1); - check(&mut [-1, 1], |&x| x < 0, 1); - - let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - check(xs, |_| true, 10); - check(xs, |_| false, 0); - check(xs, |&x| x % 2 == 0, 5); // evens - check(xs, |&x| x % 2 == 1, 5); // odds - check(xs, |&x| x % 3 == 0, 4); // multiple of 3 - check(xs, |&x| x % 4 == 0, 3); // multiple of 4 - check(xs, |&x| x % 5 == 0, 2); // multiple of 5 - check(xs, |&x| x < 3, 3); // small - check(xs, |&x| x > 6, 3); // large -} - -#[test] -fn test_iterator_rev_advance_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter().rev(); - assert_eq!(iter.advance_by(i), Ok(())); - assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); - } - - assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); - assert_eq!(v.iter().rev().advance_by(100), Err(v.len())); -} - -#[test] -fn test_find_map() { - let xs: &[isize] = &[]; - assert_eq!(xs.iter().find_map(half_if_even), None); - let xs: &[isize] = &[3, 5]; - assert_eq!(xs.iter().find_map(half_if_even), None); - let xs: &[isize] = &[4, 5]; - assert_eq!(xs.iter().find_map(half_if_even), Some(2)); - let xs: &[isize] = &[3, 6]; - assert_eq!(xs.iter().find_map(half_if_even), Some(3)); - - let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; - let mut iter = xs.iter(); - assert_eq!(iter.find_map(half_if_even), Some(1)); - assert_eq!(iter.find_map(half_if_even), Some(2)); - assert_eq!(iter.find_map(half_if_even), Some(3)); - assert_eq!(iter.next(), Some(&7)); - - fn half_if_even(x: &isize) -> Option<isize> { - if x % 2 == 0 { Some(x / 2) } else { None } - } -} - -#[test] -fn test_iterator_len() { - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().count(), 4); - assert_eq!(v[..10].iter().count(), 10); - assert_eq!(v[..0].iter().count(), 0); -} - -#[test] -fn test_collect() { - let a = vec![1, 2, 3, 4, 5]; - let b: Vec<isize> = a.iter().cloned().collect(); - assert!(a == b); -} diff --git a/library/core/tests/iter/traits/mod.rs b/library/core/tests/iter/traits/mod.rs deleted file mode 100644 index 80619f53f25f9..0000000000000 --- a/library/core/tests/iter/traits/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod accum; -mod double_ended; -mod iterator; -mod step; diff --git a/library/core/tests/iter/traits/step.rs b/library/core/tests/iter/traits/step.rs deleted file mode 100644 index 3d82a40cd2941..0000000000000 --- a/library/core/tests/iter/traits/step.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::iter::*; - -#[test] -fn test_steps_between() { - assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize)); - assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize)); - assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize)); - assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize)); - assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize)); - assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize)); - - // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms - - assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize)); - assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize)); - if cfg!(target_pointer_width = "64") { - assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX)); - } - assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None); - assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None); - assert_eq!( - Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,), - None, - ); -} - -#[test] -fn test_step_forward() { - assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8)); - assert_eq!(Step::forward_checked(252_u8, 200_usize), None); - assert_eq!(Step::forward_checked(0_u8, 256_usize), None); - assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8)); - assert_eq!(Step::forward_checked(-110_i8, 248_usize), None); - assert_eq!(Step::forward_checked(-126_i8, 256_usize), None); - - assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16)); - assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX)); - assert_eq!(Step::forward_checked(36_u16, 65500_usize), None); - assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16)); - assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16)); - assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None); - assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None); - - assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128)); - assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128)); - assert_eq!( - Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize), - Some(u128::MAX), - ); - assert_eq!( - Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize), - None - ); - assert_eq!( - Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize), - Some(i128::MAX), - ); - assert_eq!( - Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), - None - ); -} - -#[test] -fn test_step_backward() { - assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8)); - assert_eq!(Step::backward_checked(100_u8, 200_usize), None); - assert_eq!(Step::backward_checked(255_u8, 256_usize), None); - assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8)); - assert_eq!(Step::backward_checked(110_i8, 248_usize), None); - assert_eq!(Step::backward_checked(127_i8, 256_usize), None); - - assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16)); - assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16)); - assert_eq!(Step::backward_checked(10_u16, 11_usize), None); - assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16)); - assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16)); - assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None); - assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None); - - assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128)); - assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128)); - assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128)); - assert_eq!(Step::backward_checked(10_u128, 11_usize), None); - assert_eq!( - Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), - Some(i128::MIN) - ); -} diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 9763a2da34151..b0fceb9b2f669 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -561,13 +561,6 @@ pub fn home_dir() -> Option<PathBuf> { /// Returns the path of a temporary directory. /// -/// The temporary directory may be shared among users, or between processes -/// with different privileges; thus, the creation of any files or directories -/// in the temporary directory must use a secure method to create a uniquely -/// named file. Creating a file or directory with a fixed or predictable name -/// may result in "insecure temporary file" security vulnerabilities. Consider -/// using a crate that securely creates temporary files or directories. -/// /// # Unix /// /// Returns the value of the `TMPDIR` environment variable if it is @@ -587,10 +580,14 @@ pub fn home_dir() -> Option<PathBuf> { /// /// ```no_run /// use std::env; +/// use std::fs::File; /// -/// fn main() { +/// fn main() -> std::io::Result<()> { /// let mut dir = env::temp_dir(); -/// println!("Temporary directory: {}", dir.display()); +/// dir.push("foo.txt"); +/// +/// let f = File::create(dir)?; +/// Ok(()) /// } /// ``` #[stable(feature = "env", since = "1.0.0")] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 605d953f5da71..ca83c409822fc 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -486,27 +486,6 @@ impl<T: Error> Error for Box<T> { } } -#[stable(feature = "error_by_ref", since = "1.51.0")] -impl<'a, T: Error + ?Sized> Error for &'a T { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Error::description(&**self) - } - - #[allow(deprecated)] - fn cause(&self) -> Option<&dyn Error> { - Error::cause(&**self) - } - - fn source(&self) -> Option<&(dyn Error + 'static)> { - Error::source(&**self) - } - - fn backtrace(&self) -> Option<&Backtrace> { - Error::backtrace(&**self) - } -} - #[stable(feature = "fmt_error", since = "1.11.0")] impl Error for fmt::Error { #[allow(deprecated)] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index f51b2c2462166..c30458c0545d0 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -1,13 +1,12 @@ -//! Constants specific to the `f32` single-precision floating point type. +//! This module provides constants which are specific to the implementation +//! of the `f32` floating point data type. //! //! *[See also the `f32` primitive type](primitive@f32).* //! //! Mathematically significant numbers are provided in the `consts` sub-module. //! -//! For the constants defined directly in this module -//! (as distinct from those defined in the `consts` sub-module), -//! new code should instead use the associated constants -//! defined directly on the `f32` type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] @@ -21,11 +20,15 @@ use crate::intrinsics; use crate::sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::f32::{ - consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, - MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, -}; +pub use core::f32::consts; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f32::{DIGITS, EPSILON, MANTISSA_DIGITS, RADIX}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f32::{INFINITY, MAX_10_EXP, NAN, NEG_INFINITY}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f32::{MAX, MIN, MIN_POSITIVE}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f32::{MAX_EXP, MIN_10_EXP, MIN_EXP}; #[cfg(not(test))] #[lang = "f32_runtime"] diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 8c41e4486865c..f4cc53979d1a6 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -1,13 +1,12 @@ -//! Constants specific to the `f64` double-precision floating point type. +//! This module provides constants which are specific to the implementation +//! of the `f64` floating point data type. //! //! *[See also the `f64` primitive type](primitive@f64).* //! //! Mathematically significant numbers are provided in the `consts` sub-module. //! -//! For the constants defined directly in this module -//! (as distinct from those defined in the `consts` sub-module), -//! new code should instead use the associated constants -//! defined directly on the `f64` type. +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] @@ -21,11 +20,15 @@ use crate::intrinsics; use crate::sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::f64::{ - consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP, - MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX, -}; +pub use core::f64::consts; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f64::{DIGITS, EPSILON, MANTISSA_DIGITS, RADIX}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f64::{INFINITY, MAX_10_EXP, NAN, NEG_INFINITY}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f64::{MAX, MIN, MIN_POSITIVE}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::f64::{MAX_EXP, MIN_10_EXP, MIN_EXP}; #[cfg(not(test))] #[lang = "f64_runtime"] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 32f0f8a52f820..2eef4d58507c0 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -111,7 +111,6 @@ impl OsString { /// let os_string = OsString::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } } @@ -128,7 +127,6 @@ impl OsString { /// assert_eq!(os_string.as_os_str(), os_str); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn as_os_str(&self) -> &OsStr { self } @@ -147,7 +145,6 @@ impl OsString { /// assert_eq!(string, Ok(String::from("foo"))); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn into_string(self) -> Result<String, OsString> { self.inner.into_string().map_err(|buf| OsString { inner: buf }) } @@ -166,7 +163,6 @@ impl OsString { /// assert_eq!(&os_string, "foobar"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn push<T: AsRef<OsStr>>(&mut self, s: T) { self.inner.push_slice(&s.as_ref().inner) } @@ -193,7 +189,6 @@ impl OsString { /// assert_eq!(capacity, os_string.capacity()); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - #[inline] pub fn with_capacity(capacity: usize) -> OsString { OsString { inner: Buf::with_capacity(capacity) } } @@ -212,7 +207,6 @@ impl OsString { /// assert_eq!(&os_string, ""); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - #[inline] pub fn clear(&mut self) { self.inner.clear() } @@ -230,7 +224,6 @@ impl OsString { /// assert!(os_string.capacity() >= 10); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - #[inline] pub fn capacity(&self) -> usize { self.inner.capacity() } @@ -250,7 +243,6 @@ impl OsString { /// assert!(s.capacity() >= 10); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } @@ -273,7 +265,6 @@ impl OsString { /// assert!(s.capacity() >= 10); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - #[inline] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } @@ -294,7 +285,6 @@ impl OsString { /// assert_eq!(3, s.capacity()); /// ``` #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")] - #[inline] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } @@ -352,7 +342,6 @@ impl From<String> for OsString { /// Converts a [`String`] into a [`OsString`]. /// /// The conversion copies the data, and includes an allocation on the heap. - #[inline] fn from(s: String) -> OsString { OsString { inner: Buf::from_string(s) } } @@ -419,7 +408,6 @@ impl fmt::Debug for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for OsString { - #[inline] fn eq(&self, other: &OsString) -> bool { &**self == &**other } @@ -427,7 +415,6 @@ impl PartialEq for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<str> for OsString { - #[inline] fn eq(&self, other: &str) -> bool { &**self == other } @@ -435,7 +422,6 @@ impl PartialEq<str> for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<OsString> for str { - #[inline] fn eq(&self, other: &OsString) -> bool { &**other == self } @@ -443,7 +429,6 @@ impl PartialEq<OsString> for str { #[stable(feature = "os_str_str_ref_eq", since = "1.29.0")] impl PartialEq<&str> for OsString { - #[inline] fn eq(&self, other: &&str) -> bool { **self == **other } @@ -451,7 +436,6 @@ impl PartialEq<&str> for OsString { #[stable(feature = "os_str_str_ref_eq", since = "1.29.0")] impl<'a> PartialEq<OsString> for &'a str { - #[inline] fn eq(&self, other: &OsString) -> bool { **other == **self } @@ -555,7 +539,6 @@ impl OsStr { /// assert_eq!(os_str.to_str(), Some("foo")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() } @@ -606,7 +589,6 @@ impl OsStr { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() } @@ -623,7 +605,6 @@ impl OsStr { /// assert_eq!(os_string, OsString::from("foo")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } } @@ -674,7 +655,6 @@ impl OsStr { /// ``` #[doc(alias = "length")] #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - #[inline] pub fn len(&self) -> usize { self.inner.inner.len() } @@ -716,7 +696,6 @@ impl OsStr { /// assert_eq!("grÜße, jÜrgen ❤", s); /// ``` #[unstable(feature = "osstring_ascii", issue = "70516")] - #[inline] pub fn make_ascii_lowercase(&mut self) { self.inner.make_ascii_lowercase() } @@ -742,7 +721,6 @@ impl OsStr { /// assert_eq!("GRüßE, JüRGEN ❤", s); /// ``` #[unstable(feature = "osstring_ascii", issue = "70516")] - #[inline] pub fn make_ascii_uppercase(&mut self) { self.inner.make_ascii_uppercase() } @@ -806,7 +784,6 @@ impl OsStr { /// assert!(!non_ascii.is_ascii()); /// ``` #[unstable(feature = "osstring_ascii", issue = "70516")] - #[inline] pub fn is_ascii(&self) -> bool { self.inner.is_ascii() } @@ -834,7 +811,6 @@ impl OsStr { #[stable(feature = "box_from_os_str", since = "1.17.0")] impl From<&OsStr> for Box<OsStr> { - #[inline] fn from(s: &OsStr) -> Box<OsStr> { let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; unsafe { Box::from_raw(rw) } @@ -856,7 +832,6 @@ impl From<Cow<'_, OsStr>> for Box<OsStr> { impl From<Box<OsStr>> for OsString { /// Converts a [`Box`]`<`[`OsStr`]`>` into a `OsString` without copying or /// allocating. - #[inline] fn from(boxed: Box<OsStr>) -> OsString { boxed.into_os_string() } @@ -865,7 +840,6 @@ impl From<Box<OsStr>> for OsString { #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From<OsString> for Box<OsStr> { /// Converts a [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating. - #[inline] fn from(s: OsString) -> Box<OsStr> { s.into_boxed_os_str() } @@ -951,7 +925,6 @@ impl<'a> From<Cow<'a, OsStr>> for OsString { #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box<OsStr> { - #[inline] fn default() -> Box<OsStr> { let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr; unsafe { Box::from_raw(rw) } @@ -1102,7 +1075,6 @@ impl OsStr { #[stable(feature = "rust1", since = "1.0.0")] impl Borrow<OsStr> for OsString { - #[inline] fn borrow(&self) -> &OsStr { &self[..] } @@ -1111,11 +1083,9 @@ impl Borrow<OsStr> for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for OsStr { type Owned = OsString; - #[inline] fn to_owned(&self) -> OsString { self.to_os_string() } - #[inline] fn clone_into(&self, target: &mut OsString) { self.inner.clone_into(&mut target.inner) } @@ -1123,7 +1093,6 @@ impl ToOwned for OsStr { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<OsStr> for OsStr { - #[inline] fn as_ref(&self) -> &OsStr { self } @@ -1154,14 +1123,12 @@ impl AsRef<OsStr> for String { } impl FromInner<Buf> for OsString { - #[inline] fn from_inner(buf: Buf) -> OsString { OsString { inner: buf } } } impl IntoInner<Buf> for OsString { - #[inline] fn into_inner(self) -> Buf { self.inner } @@ -1178,7 +1145,6 @@ impl AsInner<Slice> for OsStr { impl FromStr for OsString { type Err = core::convert::Infallible; - #[inline] fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(OsString::from(s)) } diff --git a/library/std/src/future.rs b/library/std/src/future.rs new file mode 100644 index 0000000000000..9d9c36e9afb0f --- /dev/null +++ b/library/std/src/future.rs @@ -0,0 +1,17 @@ +//! Asynchronous values. + +#[doc(inline)] +#[stable(feature = "futures_api", since = "1.36.0")] +pub use core::future::Future; + +#[doc(inline)] +#[unstable(feature = "gen_future", issue = "50547")] +pub use core::future::{from_generator, get_context, ResumeTy}; + +#[doc(inline)] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] +pub use core::future::{pending, ready, Pending, Ready}; + +#[doc(inline)] +#[unstable(feature = "into_future", issue = "67644")] +pub use core::future::IntoFuture; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 92c8b7c177477..15ef5d1619ba3 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -406,31 +406,23 @@ pub use core::cmp; pub use core::convert; #[stable(feature = "rust1", since = "1.0.0")] pub use core::default; -#[stable(feature = "futures_api", since = "1.36.0")] -pub use core::future; #[stable(feature = "rust1", since = "1.0.0")] pub use core::hash; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; #[stable(feature = "i128", since = "1.26.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::i16; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::i64; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::i8; #[stable(feature = "rust1", since = "1.0.0")] pub use core::intrinsics; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::isize; #[stable(feature = "rust1", since = "1.0.0")] pub use core::iter; @@ -451,22 +443,16 @@ pub use core::raw; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; #[stable(feature = "i128", since = "1.26.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::u128; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::u16; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::u64; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::u8; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] pub use core::usize; pub mod f32; @@ -507,6 +493,9 @@ pub mod task { pub use alloc::task::*; } +#[stable(feature = "futures_api", since = "1.36.0")] +pub mod future; + // Platform-abstraction modules #[macro_use] mod sys_common; diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index e466f3151524c..5a70aa070e870 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -282,10 +282,6 @@ macro_rules! eprintln { #[macro_export] #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { - // NOTE: We cannot use `concat!` to make a static string as a format argument - // of `eprintln!` because `file!` could contain a `{` or - // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` - // will be malformed. () => { $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()); }; diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 84449e4876718..d33b772633d29 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1610,11 +1610,11 @@ impl fmt::Display for Ipv6Addr { /// Write a colon-separated part of the address #[inline] fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { - if let Some((first, tail)) = chunk.split_first() { - write!(f, "{:x}", first)?; - for segment in tail { + if let Some(first) = chunk.first() { + fmt::LowerHex::fmt(first, f)?; + for segment in &chunk[1..] { f.write_char(':')?; - write!(f, "{:x}", segment)?; + fmt::LowerHex::fmt(segment, f)?; } } Ok(()) diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index ef0d4edc43473..44fb3adf07023 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -166,9 +166,6 @@ fn ipv6_addr_to_string() { // two runs of zeros, equal length assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - - // don't prefix `0x` to each segment in `dbg!`. - assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8))); } #[test] diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 0f568da459bef..d18b94b6c1aef 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -31,9 +31,9 @@ pub use core::panic::{Location, PanicInfo}; /// accessed later using [`PanicInfo::payload`]. /// /// See the [`panic!`] macro for more information about panicking. -#[stable(feature = "panic_any", since = "1.51.0")] +#[unstable(feature = "panic_any", issue = "78500")] #[inline] -pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! { +pub fn panic_any<M: Any + Send>(msg: M) -> ! { crate::panicking::begin_panic(msg); } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 1889e54933867..243761e389784 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -401,14 +401,12 @@ impl<'a> PrefixComponent<'a> { /// See [`Prefix`]'s documentation for more information on the different /// kinds of prefixes. #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn kind(&self) -> Prefix<'a> { self.parsed } /// Returns the raw [`OsStr`] slice for this prefix. #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn as_os_str(&self) -> &'a OsStr { self.raw } @@ -416,7 +414,6 @@ impl<'a> PrefixComponent<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> cmp::PartialEq for PrefixComponent<'a> { - #[inline] fn eq(&self, other: &PrefixComponent<'a>) -> bool { cmp::PartialEq::eq(&self.parsed, &other.parsed) } @@ -424,7 +421,6 @@ impl<'a> cmp::PartialEq for PrefixComponent<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> cmp::PartialOrd for PrefixComponent<'a> { - #[inline] fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option<cmp::Ordering> { cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed) } @@ -432,7 +428,6 @@ impl<'a> cmp::PartialOrd for PrefixComponent<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl cmp::Ord for PrefixComponent<'_> { - #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { cmp::Ord::cmp(&self.parsed, &other.parsed) } @@ -527,7 +522,6 @@ impl<'a> Component<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<OsStr> for Component<'_> { - #[inline] fn as_ref(&self) -> &OsStr { self.as_os_str() } @@ -535,7 +529,6 @@ impl AsRef<OsStr> for Component<'_> { #[stable(feature = "path_component_asref", since = "1.25.0")] impl AsRef<Path> for Component<'_> { - #[inline] fn as_ref(&self) -> &Path { self.as_os_str().as_ref() } @@ -757,7 +750,6 @@ impl<'a> Components<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<Path> for Components<'_> { - #[inline] fn as_ref(&self) -> &Path { self.as_path() } @@ -765,7 +757,6 @@ impl AsRef<Path> for Components<'_> { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<OsStr> for Components<'_> { - #[inline] fn as_ref(&self) -> &OsStr { self.as_path().as_os_str() } @@ -801,7 +792,6 @@ impl<'a> Iter<'a> { /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn as_path(&self) -> &'a Path { self.inner.as_path() } @@ -809,7 +799,6 @@ impl<'a> Iter<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<Path> for Iter<'_> { - #[inline] fn as_ref(&self) -> &Path { self.as_path() } @@ -817,7 +806,6 @@ impl AsRef<Path> for Iter<'_> { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<OsStr> for Iter<'_> { - #[inline] fn as_ref(&self) -> &OsStr { self.as_path().as_os_str() } @@ -827,7 +815,6 @@ impl AsRef<OsStr> for Iter<'_> { impl<'a> Iterator for Iter<'a> { type Item = &'a OsStr; - #[inline] fn next(&mut self) -> Option<&'a OsStr> { self.inner.next().map(Component::as_os_str) } @@ -835,7 +822,6 @@ impl<'a> Iterator for Iter<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> DoubleEndedIterator for Iter<'a> { - #[inline] fn next_back(&mut self) -> Option<&'a OsStr> { self.inner.next_back().map(Component::as_os_str) } @@ -949,7 +935,6 @@ impl FusedIterator for Components<'_> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a> cmp::PartialEq for Components<'a> { - #[inline] fn eq(&self, other: &Components<'a>) -> bool { Iterator::eq(self.clone(), other.clone()) } @@ -960,7 +945,6 @@ impl cmp::Eq for Components<'_> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a> cmp::PartialOrd for Components<'a> { - #[inline] fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> { Iterator::partial_cmp(self.clone(), other.clone()) } @@ -968,7 +952,6 @@ impl<'a> cmp::PartialOrd for Components<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl cmp::Ord for Components<'_> { - #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { Iterator::cmp(self.clone(), other.clone()) } @@ -1002,7 +985,6 @@ pub struct Ancestors<'a> { impl<'a> Iterator for Ancestors<'a> { type Item = &'a Path; - #[inline] fn next(&mut self) -> Option<Self::Item> { let next = self.next; self.next = next.and_then(Path::parent); @@ -1078,7 +1060,6 @@ pub struct PathBuf { } impl PathBuf { - #[inline] fn as_mut_vec(&mut self) -> &mut Vec<u8> { unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) } } @@ -1093,7 +1074,6 @@ impl PathBuf { /// let path = PathBuf::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn new() -> PathBuf { PathBuf { inner: OsString::new() } } @@ -1117,7 +1097,6 @@ impl PathBuf { /// /// [`with_capacity`]: OsString::with_capacity #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] pub fn with_capacity(capacity: usize) -> PathBuf { PathBuf { inner: OsString::with_capacity(capacity) } } @@ -1133,7 +1112,6 @@ impl PathBuf { /// assert_eq!(Path::new("/test"), p.as_path()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn as_path(&self) -> &Path { self } @@ -1337,14 +1315,12 @@ impl PathBuf { /// let os_str = p.into_os_string(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn into_os_string(self) -> OsString { self.inner } /// Converts this `PathBuf` into a [boxed](Box) [`Path`]. #[stable(feature = "into_boxed_path", since = "1.20.0")] - #[inline] pub fn into_boxed_path(self) -> Box<Path> { let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; unsafe { Box::from_raw(rw) } @@ -1354,7 +1330,6 @@ impl PathBuf { /// /// [`capacity`]: OsString::capacity #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] pub fn capacity(&self) -> usize { self.inner.capacity() } @@ -1363,7 +1338,6 @@ impl PathBuf { /// /// [`clear`]: OsString::clear #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] pub fn clear(&mut self) { self.inner.clear() } @@ -1372,7 +1346,6 @@ impl PathBuf { /// /// [`reserve`]: OsString::reserve #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } @@ -1381,7 +1354,6 @@ impl PathBuf { /// /// [`reserve_exact`]: OsString::reserve_exact #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } @@ -1390,7 +1362,6 @@ impl PathBuf { /// /// [`shrink_to_fit`]: OsString::shrink_to_fit #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } @@ -1399,7 +1370,6 @@ impl PathBuf { /// /// [`shrink_to`]: OsString::shrink_to #[unstable(feature = "shrink_to", issue = "56431")] - #[inline] pub fn shrink_to(&mut self, min_capacity: usize) { self.inner.shrink_to(min_capacity) } @@ -1430,7 +1400,6 @@ impl From<Box<Path>> for PathBuf { /// Converts a `Box<Path>` into a `PathBuf` /// /// This conversion does not allocate or copy memory. - #[inline] fn from(boxed: Box<Path>) -> PathBuf { boxed.into_path_buf() } @@ -1442,7 +1411,6 @@ impl From<PathBuf> for Box<Path> { /// /// This conversion currently should not allocate memory, /// but this behavior is not guaranteed on all platforms or in all future versions. - #[inline] fn from(p: PathBuf) -> Box<Path> { p.into_boxed_path() } @@ -1458,7 +1426,6 @@ impl Clone for Box<Path> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf { - #[inline] fn from(s: &T) -> PathBuf { PathBuf::from(s.as_ref().to_os_string()) } @@ -1480,7 +1447,6 @@ impl From<PathBuf> for OsString { /// Converts a `PathBuf` into a `OsString` /// /// This conversion does not allocate or copy memory. - #[inline] fn from(path_buf: PathBuf) -> OsString { path_buf.inner } @@ -1491,7 +1457,6 @@ impl From<String> for PathBuf { /// Converts a `String` into a `PathBuf` /// /// This conversion does not allocate or copy memory. - #[inline] fn from(s: String) -> PathBuf { PathBuf::from(OsString::from(s)) } @@ -1501,7 +1466,6 @@ impl From<String> for PathBuf { impl FromStr for PathBuf { type Err = core::convert::Infallible; - #[inline] fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(PathBuf::from(s)) } @@ -1546,7 +1510,6 @@ impl ops::Deref for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl Borrow<Path> for PathBuf { - #[inline] fn borrow(&self) -> &Path { self.deref() } @@ -1554,7 +1517,6 @@ impl Borrow<Path> for PathBuf { #[stable(feature = "default_for_pathbuf", since = "1.17.0")] impl Default for PathBuf { - #[inline] fn default() -> Self { PathBuf::new() } @@ -1635,11 +1597,9 @@ impl From<&Path> for Rc<Path> { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for Path { type Owned = PathBuf; - #[inline] fn to_owned(&self) -> PathBuf { self.to_path_buf() } - #[inline] fn clone_into(&self, target: &mut PathBuf) { self.inner.clone_into(&mut target.inner); } @@ -1647,7 +1607,6 @@ impl ToOwned for Path { #[stable(feature = "rust1", since = "1.0.0")] impl cmp::PartialEq for PathBuf { - #[inline] fn eq(&self, other: &PathBuf) -> bool { self.components() == other.components() } @@ -1665,7 +1624,6 @@ impl cmp::Eq for PathBuf {} #[stable(feature = "rust1", since = "1.0.0")] impl cmp::PartialOrd for PathBuf { - #[inline] fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> { self.components().partial_cmp(other.components()) } @@ -1673,7 +1631,6 @@ impl cmp::PartialOrd for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl cmp::Ord for PathBuf { - #[inline] fn cmp(&self, other: &PathBuf) -> cmp::Ordering { self.components().cmp(other.components()) } @@ -1681,7 +1638,6 @@ impl cmp::Ord for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<OsStr> for PathBuf { - #[inline] fn as_ref(&self) -> &OsStr { &self.inner[..] } @@ -1789,7 +1745,6 @@ impl Path { /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn as_os_str(&self) -> &OsStr { &self.inner } @@ -1811,7 +1766,6 @@ impl Path { /// assert_eq!(path.to_str(), Some("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() } @@ -1837,7 +1791,6 @@ impl Path { /// Had `path` contained invalid unicode, the `to_string_lossy` call might /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() } @@ -1901,7 +1854,6 @@ impl Path { /// /// [`is_absolute`]: Path::is_absolute #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn is_relative(&self) -> bool { !self.is_absolute() } @@ -1927,7 +1879,6 @@ impl Path { /// assert!(Path::new("/etc/passwd").has_root()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn has_root(&self) -> bool { self.components().has_root() } @@ -1990,7 +1941,6 @@ impl Path { /// /// [`parent`]: Path::parent #[stable(feature = "path_ancestors", since = "1.28.0")] - #[inline] pub fn ancestors(&self) -> Ancestors<'_> { Ancestors { next: Some(&self) } } @@ -2315,7 +2265,6 @@ impl Path { /// assert_eq!(it.next(), None) /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn iter(&self) -> Iter<'_> { Iter { inner: self.components() } } @@ -2335,7 +2284,6 @@ impl Path { /// println!("{}", path.display()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] pub fn display(&self) -> Display<'_> { Display { path: self } } @@ -2357,7 +2305,6 @@ impl Path { /// println!("{:?}", metadata.file_type()); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] pub fn metadata(&self) -> io::Result<fs::Metadata> { fs::metadata(self) } @@ -2376,7 +2323,6 @@ impl Path { /// println!("{:?}", metadata.file_type()); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> { fs::symlink_metadata(self) } @@ -2395,7 +2341,6 @@ impl Path { /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] pub fn canonicalize(&self) -> io::Result<PathBuf> { fs::canonicalize(self) } @@ -2413,7 +2358,6 @@ impl Path { /// let path_link = path.read_link().expect("read_link call failed"); /// ``` #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] pub fn read_link(&self) -> io::Result<PathBuf> { fs::read_link(self) } @@ -2438,7 +2382,6 @@ impl Path { /// } /// ``` #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] pub fn read_dir(&self) -> io::Result<fs::ReadDir> { fs::read_dir(self) } @@ -2463,7 +2406,6 @@ impl Path { /// This is a convenience function that coerces errors to false. If you want to /// check errors, call [`fs::metadata`]. #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] pub fn exists(&self) -> bool { fs::metadata(self).is_ok() } @@ -2538,7 +2480,6 @@ impl Path { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<OsStr> for Path { - #[inline] fn as_ref(&self) -> &OsStr { &self.inner } @@ -2590,7 +2531,6 @@ impl fmt::Display for Display<'_> { #[stable(feature = "rust1", since = "1.0.0")] impl cmp::PartialEq for Path { - #[inline] fn eq(&self, other: &Path) -> bool { self.components().eq(other.components()) } @@ -2610,7 +2550,6 @@ impl cmp::Eq for Path {} #[stable(feature = "rust1", since = "1.0.0")] impl cmp::PartialOrd for Path { - #[inline] fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> { self.components().partial_cmp(other.components()) } @@ -2618,7 +2557,6 @@ impl cmp::PartialOrd for Path { #[stable(feature = "rust1", since = "1.0.0")] impl cmp::Ord for Path { - #[inline] fn cmp(&self, other: &Path) -> cmp::Ordering { self.components().cmp(other.components()) } @@ -2626,7 +2564,6 @@ impl cmp::Ord for Path { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<Path> for Path { - #[inline] fn as_ref(&self) -> &Path { self } @@ -2634,7 +2571,6 @@ impl AsRef<Path> for Path { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<Path> for OsStr { - #[inline] fn as_ref(&self) -> &Path { Path::new(self) } @@ -2642,7 +2578,6 @@ impl AsRef<Path> for OsStr { #[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")] impl AsRef<Path> for Cow<'_, OsStr> { - #[inline] fn as_ref(&self) -> &Path { Path::new(self) } @@ -2650,7 +2585,6 @@ impl AsRef<Path> for Cow<'_, OsStr> { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<Path> for OsString { - #[inline] fn as_ref(&self) -> &Path { Path::new(self) } @@ -2666,7 +2600,6 @@ impl AsRef<Path> for str { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<Path> for String { - #[inline] fn as_ref(&self) -> &Path { Path::new(self) } @@ -2684,7 +2617,6 @@ impl AsRef<Path> for PathBuf { impl<'a> IntoIterator for &'a PathBuf { type Item = &'a OsStr; type IntoIter = Iter<'a>; - #[inline] fn into_iter(self) -> Iter<'a> { self.iter() } @@ -2694,7 +2626,6 @@ impl<'a> IntoIterator for &'a PathBuf { impl<'a> IntoIterator for &'a Path { type Item = &'a OsStr; type IntoIter = Iter<'a>; - #[inline] fn into_iter(self) -> Iter<'a> { self.iter() } diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 724b5dcca6a36..f4c67b225e6e1 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -39,15 +39,6 @@ pub trait CommandExt { #[cfg(target_os = "vxworks")] id: u16, ) -> &mut process::Command; - /// Sets the supplementary group IDs for the calling process. Translates to - /// a `setgroups` call in the child process. - #[unstable(feature = "setgroups", issue = "38527", reason = "")] - fn groups( - &mut self, - #[cfg(not(target_os = "vxworks"))] groups: &[u32], - #[cfg(target_os = "vxworks")] groups: &[u16], - ) -> &mut process::Command; - /// Schedules a closure to be run just before the `exec` function is /// invoked. /// @@ -158,15 +149,6 @@ impl CommandExt for process::Command { self } - fn groups( - &mut self, - #[cfg(not(target_os = "vxworks"))] groups: &[u32], - #[cfg(target_os = "vxworks")] groups: &[u16], - ) -> &mut process::Command { - self.as_inner_mut().groups(groups); - self - } - unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static, diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index a96d4aa6a4555..372e5e6a5b367 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -87,7 +87,6 @@ pub struct Command { gid: Option<gid_t>, saw_nul: bool, closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>, - groups: Option<Box<[gid_t]>>, stdin: Option<Stdio>, stdout: Option<Stdio>, stderr: Option<Stdio>, @@ -149,7 +148,6 @@ impl Command { gid: None, saw_nul, closures: Vec::new(), - groups: None, stdin: None, stdout: None, stderr: None, @@ -185,9 +183,6 @@ impl Command { pub fn gid(&mut self, id: gid_t) { self.gid = Some(id); } - pub fn groups(&mut self, groups: &[gid_t]) { - self.groups = Some(Box::from(groups)); - } pub fn saw_nul(&self) -> bool { self.saw_nul @@ -231,10 +226,6 @@ impl Command { pub fn get_gid(&self) -> Option<gid_t> { self.gid } - #[allow(dead_code)] - pub fn get_groups(&self) -> Option<&[gid_t]> { - self.groups.as_deref() - } pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> { &mut self.closures diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 2746f87468dca..ddcb404c60ebc 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -183,26 +183,20 @@ impl Command { #[cfg(not(target_os = "l4re"))] { - if let Some(_g) = self.get_groups() { - //FIXME: Redox kernel does not support setgroups yet - #[cfg(not(target_os = "redox"))] - cvt(libc::setgroups(_g.len().try_into().unwrap(), _g.as_ptr()))?; - } if let Some(u) = self.get_gid() { cvt(libc::setgid(u as gid_t))?; } if let Some(u) = self.get_uid() { // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. We only drop groups - // if the current uid is 0 and we weren't given an explicit - // set of groups. If we don't call this, then even though our - // uid has dropped, we may still have groups that enable us to - // do super-user things. + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. //FIXME: Redox kernel does not support setgroups yet #[cfg(not(target_os = "redox"))] - if libc::getuid() == 0 && self.get_groups().is_none() { - cvt(libc::setgroups(0, ptr::null()))?; - } + let _ = libc::setgroups(0, ptr::null()); cvt(libc::setuid(u as uid_t))?; } } @@ -293,7 +287,6 @@ impl Command { || self.get_uid().is_some() || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() - || self.get_groups().is_some() { return Ok(None); } diff --git a/library/std/src/sys/unix/process/zircon.rs b/library/std/src/sys/unix/process/zircon.rs index 58427bb8b69d9..69ec275c2b318 100644 --- a/library/std/src/sys/unix/process/zircon.rs +++ b/library/std/src/sys/unix/process/zircon.rs @@ -1,6 +1,7 @@ #![allow(non_camel_case_types, unused)] use crate::convert::TryInto; +use crate::i64; use crate::io; use crate::mem::MaybeUninit; use crate::os::raw::c_char; diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index f43a19d91b657..2b1bc92dc84ae 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1020,60 +1020,6 @@ extern "system" { pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinka - pub fn CreateSymbolicLinkW( - lpSymlinkFileName: LPCWSTR, - lpTargetFileName: LPCWSTR, - dwFlags: DWORD, - ) -> BOOLEAN; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew - pub fn GetFinalPathNameByHandleW( - hFile: HANDLE, - lpszFilePath: LPCWSTR, - cchFilePath: DWORD, - dwFlags: DWORD, - ) -> DWORD; - - // >= Vista / Server 2003 - // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee - #[cfg(not(target_vendor = "uwp"))] - pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle - pub fn SetFileInformationByHandle( - hFile: HANDLE, - FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: LPVOID, - dwBufferSize: DWORD, - ) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw - pub fn SleepConditionVariableSRW( - ConditionVariable: PCONDITION_VARIABLE, - SRWLock: PSRWLOCK, - dwMilliseconds: DWORD, - Flags: ULONG, - ) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable - pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive - pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); - pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); - pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); - pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); - pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; - pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; } // Functions that aren't available on every version of Windows that we support, @@ -1081,26 +1027,70 @@ extern "system" { compat_fn! { "kernel32": - // >= Win10 1607 - // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription + pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, + _lpTargetFileName: LPCWSTR, + _dwFlags: DWORD) -> BOOLEAN { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + pub fn GetFinalPathNameByHandleW(_hFile: HANDLE, + _lpszFilePath: LPCWSTR, + _cchFilePath: DWORD, + _dwFlags: DWORD) -> DWORD { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + #[cfg(not(target_vendor = "uwp"))] + pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } pub fn SetThreadDescription(hThread: HANDLE, lpThreadDescription: LPCWSTR) -> HRESULT { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL } - - // >= Win8 / Server 2012 - // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime + pub fn SetFileInformationByHandle(_hFile: HANDLE, + _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, + _lpFileInformation: LPVOID, + _dwBufferSize: DWORD) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME) -> () { GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) } + pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, + SRWLock: PSRWLOCK, + dwMilliseconds: DWORD, + Flags: ULONG) -> BOOL { + panic!("condition variables not available") + } + pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE) + -> () { + panic!("condition variables not available") + } + pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE) + -> () { + panic!("condition variables not available") + } + pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN { + panic!("rwlocks not available") + } + pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN { + panic!("rwlocks not available") + } } - compat_fn! { "api-ms-win-core-synch-l1-2-0": - - // >= Windows 8 / Server 2012 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress pub fn WaitOnAddress( Address: LPVOID, CompareAddress: LPVOID, diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 72a0993d94ddf..d4cc56d4cb3ef 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -13,13 +13,20 @@ //! //! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy //! is that there are no guarantees of fairness. - -use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; +//! +//! The downside of this approach, however, is that SRWLock is not available on +//! Windows XP, so we continue to have a fallback implementation where +//! CriticalSection is used and we keep track of who's holding the mutex to +//! detect recursive locks. + +use crate::cell::{Cell, UnsafeCell}; +use crate::mem::{self, MaybeUninit}; +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; pub struct Mutex { - srwlock: UnsafeCell<c::SRWLOCK>, + // This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise. + lock: AtomicUsize, } // Windows SRW Locks are movable (while not borrowed). @@ -30,37 +37,104 @@ pub type MovableMutex = Mutex; unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} +struct Inner { + remutex: ReentrantMutex, + held: Cell<bool>, +} + +#[derive(Clone, Copy)] +enum Kind { + SRWLock, + CriticalSection, +} + #[inline] pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { - m.srwlock.get() + debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock)); + &m.lock as *const _ as *mut _ } impl Mutex { pub const fn new() -> Mutex { - Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) } + Mutex { + // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly + // initializing an SRWLOCK here. + lock: AtomicUsize::new(0), + } } #[inline] pub unsafe fn init(&mut self) {} - - #[inline] pub unsafe fn lock(&self) { - c::AcquireSRWLockExclusive(raw(self)); + match kind() { + Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), + Kind::CriticalSection => { + let inner = &*self.inner(); + inner.remutex.lock(); + if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); + panic!("cannot recursively lock a mutex"); + } + } + } } - - #[inline] pub unsafe fn try_lock(&self) -> bool { - c::TryAcquireSRWLockExclusive(raw(self)) != 0 + match kind() { + Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, + Kind::CriticalSection => { + let inner = &*self.inner(); + if !inner.remutex.try_lock() { + false + } else if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); + false + } else { + true + } + } + } } - - #[inline] pub unsafe fn unlock(&self) { - c::ReleaseSRWLockExclusive(raw(self)); + match kind() { + Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), + Kind::CriticalSection => { + let inner = &*(self.lock.load(Ordering::SeqCst) as *const Inner); + inner.held.set(false); + inner.remutex.unlock(); + } + } } - - #[inline] pub unsafe fn destroy(&self) { - // SRWLock does not need to be destroyed. + match kind() { + Kind::SRWLock => {} + Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { + 0 => {} + n => Box::from_raw(n as *mut Inner).remutex.destroy(), + }, + } } + + unsafe fn inner(&self) -> *const Inner { + match self.lock.load(Ordering::SeqCst) { + 0 => {} + n => return n as *const _, + } + let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; + inner.remutex.init(); + let inner = Box::into_raw(inner); + match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) { + Ok(_) => inner, + Err(n) => { + Box::from_raw(inner).remutex.destroy(); + n as *const _ + } + } + } +} + +fn kind() -> Kind { + if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection } } pub struct ReentrantMutex { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 3ff79eaea49ab..656d9669e81d2 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -25,7 +25,6 @@ #![feature(nll)] #![feature(available_concurrency)] #![feature(internal_output_capture)] -#![feature(option_unwrap_none)] #![feature(panic_unwind)] #![feature(staged_api)] #![feature(termination_trait_lib)] @@ -62,7 +61,6 @@ pub mod test { } use std::{ - collections::VecDeque, env, io, io::prelude::Write, panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo}, @@ -210,19 +208,9 @@ where use std::collections::{self, HashMap}; use std::hash::BuildHasherDefault; use std::sync::mpsc::RecvTimeoutError; - - struct RunningTest { - join_handle: Option<thread::JoinHandle<()>>, - } - // Use a deterministic hasher type TestMap = - HashMap<TestDesc, RunningTest, BuildHasherDefault<collections::hash_map::DefaultHasher>>; - - struct TimeoutEntry { - desc: TestDesc, - timeout: Instant, - } + HashMap<TestDesc, Instant, BuildHasherDefault<collections::hash_map::DefaultHasher>>; let tests_len = tests.len(); @@ -267,30 +255,23 @@ where }; let mut running_tests: TestMap = HashMap::default(); - let mut timeout_queue: VecDeque<TimeoutEntry> = VecDeque::new(); - fn get_timed_out_tests( - running_tests: &TestMap, - timeout_queue: &mut VecDeque<TimeoutEntry>, - ) -> Vec<TestDesc> { + fn get_timed_out_tests(running_tests: &mut TestMap) -> Vec<TestDesc> { let now = Instant::now(); - let mut timed_out = Vec::new(); - while let Some(timeout_entry) = timeout_queue.front() { - if now < timeout_entry.timeout { - break; - } - let timeout_entry = timeout_queue.pop_front().unwrap(); - if running_tests.contains_key(&timeout_entry.desc) { - timed_out.push(timeout_entry.desc); - } + let timed_out = running_tests + .iter() + .filter_map(|(desc, timeout)| if &now >= timeout { Some(desc.clone()) } else { None }) + .collect(); + for test in &timed_out { + running_tests.remove(test); } timed_out } - fn calc_timeout(timeout_queue: &VecDeque<TimeoutEntry>) -> Option<Duration> { - timeout_queue.front().map(|&TimeoutEntry { timeout: next_timeout, .. }| { + fn calc_timeout(running_tests: &TestMap) -> Option<Duration> { + running_tests.values().min().map(|next_timeout| { let now = Instant::now(); - if next_timeout >= now { next_timeout - now } else { Duration::new(0, 0) } + if *next_timeout >= now { *next_timeout - now } else { Duration::new(0, 0) } }) } @@ -299,8 +280,7 @@ where let test = remaining.pop().unwrap(); let event = TestEvent::TeWait(test.desc.clone()); notify_about_test_event(event)?; - run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No) - .unwrap_none(); + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No); let completed_test = rx.recv().unwrap(); let event = TestEvent::TeResult(completed_test); @@ -311,28 +291,19 @@ where while pending < concurrency && !remaining.is_empty() { let test = remaining.pop().unwrap(); let timeout = time::get_default_test_timeout(); - let desc = test.desc.clone(); + running_tests.insert(test.desc.clone(), timeout); - let event = TestEvent::TeWait(desc.clone()); + let event = TestEvent::TeWait(test.desc.clone()); notify_about_test_event(event)?; //here no pad - let join_handle = run_test( - opts, - !opts.run_tests, - test, - run_strategy, - tx.clone(), - Concurrent::Yes, - ); - running_tests.insert(desc.clone(), RunningTest { join_handle }); - timeout_queue.push_back(TimeoutEntry { desc, timeout }); + run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes); pending += 1; } let mut res; loop { - if let Some(timeout) = calc_timeout(&timeout_queue) { + if let Some(timeout) = calc_timeout(&running_tests) { res = rx.recv_timeout(timeout); - for test in get_timed_out_tests(&running_tests, &mut timeout_queue) { + for test in get_timed_out_tests(&mut running_tests) { let event = TestEvent::TeTimeout(test); notify_about_test_event(event)?; } @@ -352,16 +323,8 @@ where } } - let mut completed_test = res.unwrap(); - let running_test = running_tests.remove(&completed_test.desc).unwrap(); - if let Some(join_handle) = running_test.join_handle { - if let Err(_) = join_handle.join() { - if let TrOk = completed_test.result { - completed_test.result = - TrFailedMsg("panicked after reporting success".to_string()); - } - } - } + let completed_test = res.unwrap(); + running_tests.remove(&completed_test.desc); let event = TestEvent::TeResult(completed_test); notify_about_test_event(event)?; @@ -452,7 +415,7 @@ pub fn run_test( strategy: RunStrategy, monitor_ch: Sender<CompletedTest>, concurrency: Concurrent, -) -> Option<thread::JoinHandle<()>> { +) { let TestDescAndFn { desc, testfn } = test; // Emscripten can catch panics but other wasm targets cannot @@ -463,7 +426,7 @@ pub fn run_test( if force_ignore || desc.ignore || ignore_because_no_process_support { let message = CompletedTest::new(desc, TrIgnored, None, Vec::new()); monitor_ch.send(message).unwrap(); - return None; + return; } struct TestRunOpts { @@ -478,7 +441,7 @@ pub fn run_test( monitor_ch: Sender<CompletedTest>, testfn: Box<dyn FnOnce() + Send>, opts: TestRunOpts, - ) -> Option<thread::JoinHandle<()>> { + ) { let concurrency = opts.concurrency; let name = desc.name.clone(); @@ -506,10 +469,9 @@ pub fn run_test( let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32"); if concurrency == Concurrent::Yes && supports_threads { let cfg = thread::Builder::new().name(name.as_slice().to_owned()); - Some(cfg.spawn(runtest).unwrap()) + cfg.spawn(runtest).unwrap(); } else { runtest(); - None } } @@ -522,12 +484,10 @@ pub fn run_test( crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { bencher.run(harness) }); - None } StaticBenchFn(benchfn) => { // Benchmarks aren't expected to panic, so we run them all in-process. crate::bench::benchmark(desc, monitor_ch, opts.nocapture, benchfn); - None } DynTestFn(f) => { match strategy { @@ -539,7 +499,7 @@ pub fn run_test( monitor_ch, Box::new(move || __rust_begin_short_backtrace(f)), test_run_opts, - ) + ); } StaticTestFn(f) => run_test_inner( desc, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 6626fead774d6..c19bb536ce83c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -320,13 +320,6 @@ macro_rules! tool_check_step { cargo.arg("--all-targets"); } - // Enable internal lints for clippy and rustdoc - // NOTE: this intentionally doesn't enable lints for any other tools, - // see https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 - if $path == "src/tools/rustdoc" || $path == "src/tools/clippy" { - cargo.rustflag("-Zunstable-options"); - } - builder.info(&format!( "Checking stage{} {} artifacts ({} -> {})", builder.top_stage, diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh index a5f47ca78ff59..13b8ca91f890f 100755 --- a/src/ci/pgo.sh +++ b/src/ci/pgo.sh @@ -24,20 +24,6 @@ pgo_perf_benchmark ctfe-stress-4 cp -pri ../src/tools/cargo /tmp/cargo -# The Cargo repository does not have a Cargo.lock in it, as it relies on the -# lockfile already present in the rust-lang/rust monorepo. This decision breaks -# down when Cargo is built outside the monorepo though (like in this case), -# resulting in a build without any dependency locking. -# -# To ensure Cargo is built with locked dependencies even during PGO profiling -# the following command copies the monorepo's lockfile into the Cargo temporary -# directory. Cargo will *not* keep that lockfile intact, as it will remove all -# the dependencies Cargo itself doesn't rely on. Still, it will prevent -# building Cargo with arbitrary dependency versions. -# -# See #81378 for the bug that prompted adding this. -cp -p ../Cargo.lock /tmp/cargo - # Build cargo (with some flags) function pgo_cargo { RUSTC=./build/$PGO_HOST/stage2/bin/rustc \ diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1f9e7f8ae5cd4..916684baf855d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -5,7 +5,7 @@ use std::iter::once; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::Mutability; use rustc_metadata::creader::LoadedMacro; @@ -17,6 +17,7 @@ use rustc_span::Span; use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind}; use crate::core::DocContext; +use crate::doctree; use super::Clean; @@ -245,7 +246,11 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Struct { - struct_type: variant.ctor_kind, + struct_type: match variant.ctor_kind { + CtorKind::Fictive => doctree::Plain, + CtorKind::Fn => doctree::Tuple, + CtorKind::Const => doctree::Unit, + }, generics: (cx.tcx.generics_of(did), predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, @@ -257,6 +262,7 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Union { + struct_type: doctree::Plain, generics: (cx.tcx.generics_of(did), predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a116ed686d90e..3ddb2adbf0aa7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1096,10 +1096,7 @@ impl Clean<Item> for hir::TraitItem<'_> { AssocTypeItem(bounds.clean(cx), default.clean(cx)) } }; - let what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); - // Trait items always inherit the trait's visibility -- we don't want to show `pub`. - Item { visibility: Inherited, ..what_rustc_thinks } + Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx) }) } } @@ -1134,21 +1131,7 @@ impl Clean<Item> for hir::ImplItem<'_> { ) } }; - - let what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); - let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id)); - if let hir::ItemKind::Impl(impl_) = &parent_item.kind { - if impl_.of_trait.is_some() { - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - Item { visibility: Inherited, ..what_rustc_thinks } - } else { - what_rustc_thinks - } - } else { - panic!("found impl item with non-impl parent {:?}", parent_item); - } + Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx) }) } } @@ -1844,7 +1827,7 @@ impl Clean<Visibility> for ty::Visibility { impl Clean<VariantStruct> for rustc_hir::VariantData<'_> { fn clean(&self, cx: &DocContext<'_>) -> VariantStruct { VariantStruct { - struct_type: CtorKind::from_hir(self), + struct_type: doctree::struct_type_from_def(self), fields: self.fields().iter().map(|x| x.clean(cx)).collect(), fields_stripped: false, } @@ -1859,7 +1842,7 @@ impl Clean<Item> for ty::VariantDef { self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect(), ), CtorKind::Fictive => Variant::Struct(VariantStruct { - struct_type: CtorKind::Fictive, + struct_type: doctree::Plain, fields_stripped: false, fields: self .fields @@ -2013,12 +1996,13 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) { bounds: bounds.clean(cx), }), ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union { + struct_type: doctree::struct_type_from_def(&variant_data), generics: generics.clean(cx), fields: variant_data.fields().clean(cx), fields_stripped: false, }), ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct { - struct_type: CtorKind::from_hir(variant_data), + struct_type: doctree::struct_type_from_def(&variant_data), generics: generics.clean(cx), fields: variant_data.fields().clean(cx), fields_stripped: false, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c767b9dd85bf9..666b11b5f806d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -16,7 +16,7 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_feature::UnstableFeatures; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, Res}; +use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::Mutability; @@ -37,6 +37,7 @@ use crate::clean::inline; use crate::clean::types::Type::{QPath, ResolvedPath}; use crate::clean::Clean; use crate::core::DocContext; +use crate::doctree; use crate::formats::cache::cache; use crate::formats::item_type::ItemType; use crate::html::render::cache::ExternalLocation; @@ -1684,7 +1685,7 @@ impl Visibility { #[derive(Clone, Debug)] crate struct Struct { - crate struct_type: CtorKind, + crate struct_type: doctree::StructType, crate generics: Generics, crate fields: Vec<Item>, crate fields_stripped: bool, @@ -1692,6 +1693,7 @@ crate struct Struct { #[derive(Clone, Debug)] crate struct Union { + crate struct_type: doctree::StructType, crate generics: Generics, crate fields: Vec<Item>, crate fields_stripped: bool, @@ -1702,7 +1704,7 @@ crate struct Union { /// only as a variant in an enum. #[derive(Clone, Debug)] crate struct VariantStruct { - crate struct_type: CtorKind, + crate struct_type: doctree::StructType, crate fields: Vec<Item>, crate fields_stripped: bool, } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index fee1bf4c3a6a7..e43ea965c0423 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::convert::TryFrom; use std::ffi::OsStr; use std::fmt; @@ -103,8 +103,6 @@ crate struct Options { crate should_test: bool, /// List of arguments to pass to the test harness, if running tests. crate test_args: Vec<String>, - /// The working directory in which to run tests. - crate test_run_directory: Option<PathBuf>, /// Optional path to persist the doctest executables to, defaults to a /// temporary directory if not set. crate persist_doctests: Option<PathBuf>, @@ -177,7 +175,6 @@ impl fmt::Debug for Options { .field("lint_cap", &self.lint_cap) .field("should_test", &self.should_test) .field("test_args", &self.test_args) - .field("test_run_directory", &self.test_run_directory) .field("persist_doctests", &self.persist_doctests) .field("default_passes", &self.default_passes) .field("manual_passes", &self.manual_passes) @@ -222,7 +219,7 @@ crate struct RenderOptions { crate extern_html_root_urls: BTreeMap<String, String>, /// A map of the default settings (values are as for DOM storage API). Keys should lack the /// `rustdoc-` prefix. - crate default_settings: FxHashMap<String, String>, + crate default_settings: HashMap<String, String>, /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages. crate resource_suffix: String, /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by @@ -575,7 +572,6 @@ impl Options { let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some(); let static_root_path = matches.opt_str("static-root-path"); let generate_search_filter = !matches.opt_present("disable-per-crate-search"); - let test_run_directory = matches.opt_str("test-run-directory").map(PathBuf::from); let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let test_builder = matches.opt_str("test-builder").map(PathBuf::from); let codegen_options_strs = matches.opt_strs("C"); @@ -617,7 +613,6 @@ impl Options { display_warnings, show_coverage, crate_version, - test_run_directory, persist_doctests, runtool, runtool_args, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 30ff124dac60f..3de97f2dd2e59 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,5 +1,4 @@ use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{ColorConfig, ErrorReported}; use rustc_hir as hir; @@ -17,6 +16,7 @@ use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP}; use rustc_target::spec::TargetTriple; use tempfile::Builder as TempFileBuilder; +use std::collections::HashMap; use std::env; use std::io::{self, Write}; use std::panic; @@ -365,9 +365,6 @@ fn run_test( } else { cmd = Command::new(output_file); } - if let Some(run_directory) = options.test_run_directory { - cmd.current_dir(run_directory); - } match cmd.output() { Err(e) => return Err(TestFailure::ExecutionError(e)), @@ -426,7 +423,6 @@ crate fn make_test( use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::Handler; use rustc_parse::maybe_new_parser_from_source_str; - use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::source_map::FilePathMapping; @@ -463,7 +459,7 @@ crate fn make_test( }; loop { - match parser.parse_item(ForceCollect::No) { + match parser.parse_item() { Ok(Some(item)) => { if !found_main { if let ast::ItemKind::Fn(..) = item.kind { @@ -707,7 +703,7 @@ crate struct Collector { position: Span, source_map: Option<Lrc<SourceMap>>, filename: Option<PathBuf>, - visited_tests: FxHashMap<(String, usize), usize>, + visited_tests: HashMap<(String, usize), usize>, } impl Collector { @@ -731,7 +727,7 @@ impl Collector { position: DUMMY_SP, source_map, filename, - visited_tests: FxHashMap::default(), + visited_tests: HashMap::new(), } } @@ -1013,7 +1009,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { self.codes, self.collector.enable_per_target_ignores, Some(&crate::html::markdown::ExtraInfo::new( - self.tcx, + &self.tcx, hir_id, span_of_attrs(&attrs).unwrap_or(sp), )), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 645b2bb193ec2..f90623c03118b 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -1,5 +1,7 @@ //! This module is used to store stuff from Rust's AST in a more convenient //! manner (and with prettier names) before cleaning. +crate use self::StructType::*; + use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; @@ -32,3 +34,21 @@ impl Module<'hir> { } } } + +#[derive(Debug, Clone, Copy)] +crate enum StructType { + /// A braced struct + Plain, + /// A tuple struct + Tuple, + /// A unit struct + Unit, +} + +crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { + match *vdata { + hir::VariantData::Struct(..) => Plain, + hir::VariantData::Tuple(..) => Tuple, + hir::VariantData::Unit(..) => Unit, + } +} diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 6941fa064ec03..e84a9853d9b7c 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty; use rustc_span::edition::Edition; use crate::clean; @@ -12,9 +12,6 @@ use crate::formats::cache::{Cache, CACHE_KEY}; /// backend renderer has hooks for initialization, documenting an item, entering and exiting a /// module, and cleanup/finalizing output. crate trait FormatRenderer<'tcx>: Clone { - /// Gives a description of the renderer. Used for performance profiling. - fn descr() -> &'static str; - /// Sets up any state required for the renderer. When this is called the cache has already been /// populated. fn init( @@ -23,7 +20,7 @@ crate trait FormatRenderer<'tcx>: Clone { render_info: RenderInfo, edition: Edition, cache: &mut Cache, - tcx: TyCtxt<'tcx>, + tcx: ty::TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error>; /// Renders a single non-module item. This means no recursive sub-item rendering is required. @@ -41,14 +38,10 @@ crate trait FormatRenderer<'tcx>: Clone { fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>; /// Post processing hook for cleanup and dumping output to files. - /// - /// A handler is available if the renderer wants to report errors. - fn after_krate( - &mut self, - krate: &clean::Crate, - cache: &Cache, - diag: &rustc_errors::Handler, - ) -> Result<(), Error>; + fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error>; + + /// Called after everything else to write out errors. + fn after_run(&mut self, diag: &rustc_errors::Handler) -> Result<(), Error>; } /// Main method for rendering a crate. @@ -58,22 +51,18 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( render_info: RenderInfo, diag: &rustc_errors::Handler, edition: Edition, - tcx: TyCtxt<'tcx>, + tcx: ty::TyCtxt<'tcx>, ) -> Result<(), Error> { - let (krate, mut cache) = tcx.sess.time("create_format_cache", || { - Cache::from_krate( - render_info.clone(), - options.document_private, - &options.extern_html_root_urls, - &options.output, - krate, - ) - }); - let prof = &tcx.sess.prof; - - let (mut format_renderer, mut krate) = prof - .extra_verbose_generic_activity("create_renderer", T::descr()) - .run(|| T::init(krate, options, render_info, edition, &mut cache, tcx))?; + let (krate, mut cache) = Cache::from_krate( + render_info.clone(), + options.document_private, + &options.extern_html_root_urls, + &options.output, + krate, + ); + + let (mut format_renderer, mut krate) = + T::init(krate, options, render_info, edition, &mut cache, tcx)?; let cache = Arc::new(cache); // Freeze the cache now that the index has been built. Put an Arc into TLS for future @@ -90,7 +79,6 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( // Render the crate documentation let mut work = vec![(format_renderer.clone(), item)]; - let unknown = rustc_span::Symbol::intern("<unknown item>"); while let Some((mut cx, item)) = work.pop() { if item.is_mod() { // modules are special because they add a namespace. We also need to @@ -99,7 +87,6 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( if name.is_empty() { panic!("Unexpected module with empty name"); } - let _timer = prof.generic_activity_with_arg("render_mod_item", name.as_str()); cx.mod_item_in(&item, &name, &cache)?; let module = match *item.kind { @@ -113,10 +100,10 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( cx.mod_item_out(&name)?; } else if item.name.is_some() { - prof.generic_activity_with_arg("render_item", &*item.name.unwrap_or(unknown).as_str()) - .run(|| cx.item(item, &cache))?; + cx.item(item, &cache)?; } } - prof.extra_verbose_generic_activity("renderer_after_krate", T::descr()) - .run(|| format_renderer.after_krate(&krate, &cache, diag)) + + format_renderer.after_krate(&krate, &cache)?; + format_renderer.after_run(diag) } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index c6ff4b57a6e59..4458eea95f3e1 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,7 +1,6 @@ +use std::collections::HashMap; use std::path::PathBuf; -use rustc_data_structures::fx::FxHashMap; - use crate::externalfiles::ExternalHtml; use crate::html::escape::Escape; use crate::html::format::{Buffer, Print}; @@ -12,7 +11,7 @@ crate struct Layout { crate logo: String, crate favicon: String, crate external_html: ExternalHtml, - crate default_settings: FxHashMap<String, String>, + crate default_settings: HashMap<String, String>, crate krate: String, /// The given user css file which allow to customize the generated /// documentation theme. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7c8b76be374a8..cfa6cd96595d6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -620,7 +620,7 @@ crate fn find_testable_code<T: doctest::Tester>( tests: &mut T, error_codes: ErrorCodes, enable_per_target_ignores: bool, - extra_info: Option<&ExtraInfo<'_>>, + extra_info: Option<&ExtraInfo<'_, '_>>, ) { let mut parser = Parser::new(doc).into_offset_iter(); let mut prev_offset = 0; @@ -681,19 +681,19 @@ crate fn find_testable_code<T: doctest::Tester>( } } -crate struct ExtraInfo<'tcx> { +crate struct ExtraInfo<'a, 'b> { hir_id: Option<HirId>, item_did: Option<DefId>, sp: Span, - tcx: TyCtxt<'tcx>, + tcx: &'a TyCtxt<'b>, } -impl<'tcx> ExtraInfo<'tcx> { - crate fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> { +impl<'a, 'b> ExtraInfo<'a, 'b> { + crate fn new(tcx: &'a TyCtxt<'b>, hir_id: HirId, sp: Span) -> ExtraInfo<'a, 'b> { ExtraInfo { hir_id: Some(hir_id), item_did: None, sp, tcx } } - crate fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> { + crate fn new_did(tcx: &'a TyCtxt<'b>, did: DefId, sp: Span) -> ExtraInfo<'a, 'b> { ExtraInfo { hir_id: None, item_did: Some(did), sp, tcx } } @@ -775,7 +775,7 @@ impl LangString { string: &str, allow_error_code_check: ErrorCodes, enable_per_target_ignores: bool, - extra: Option<&ExtraInfo<'_>>, + extra: Option<&ExtraInfo<'_, '_>>, ) -> LangString { let allow_error_code_check = allow_error_code_check.as_bool(); let mut seen_rust_tags = false; @@ -1208,7 +1208,7 @@ crate struct RustCodeBlock { /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or /// untagged (and assumed to be rust). -crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeBlock> { +crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_, '_>) -> Vec<RustCodeBlock> { let mut code_blocks = vec![]; if md.is_empty() { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ef45c98e40629..03e091297e5b6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,10 +52,10 @@ use rustc_attr::{Deprecation, StabilityLevel}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; -use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; @@ -68,6 +68,7 @@ use serde::{Serialize, Serializer}; use crate::clean::{self, AttributesExt, GetDefId, RenderedLink, SelfTy, TypeKind}; use crate::config::{RenderInfo, RenderOptions}; use crate::docfs::{DocFS, PathError}; +use crate::doctree; use crate::error::Error; use crate::formats::cache::{cache, Cache}; use crate::formats::item_type::ItemType; @@ -383,17 +384,13 @@ crate fn initial_ids() -> Vec<String> { /// Generates the documentation for `crate` into the directory `dst` impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { - fn descr() -> &'static str { - "html" - } - fn init( mut krate: clean::Crate, options: RenderOptions, _render_info: RenderInfo, edition: Edition, cache: &mut Cache, - tcx: TyCtxt<'tcx>, + tcx: ty::TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); @@ -526,12 +523,17 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { Ok((cx, krate)) } - fn after_krate( - &mut self, - krate: &clean::Crate, - cache: &Cache, - diag: &rustc_errors::Handler, - ) -> Result<(), Error> { + fn after_run(&mut self, diag: &rustc_errors::Handler) -> Result<(), Error> { + Arc::get_mut(&mut self.shared).unwrap().fs.close(); + let nb_errors = self.errors.iter().map(|err| diag.struct_err(&err).emit()).count(); + if nb_errors > 0 { + Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) + } else { + Ok(()) + } + } + + fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> { let final_file = self.dst.join(&*krate.name.as_str()).join("all.html"); let settings_file = self.dst.join("settings.html"); let crate_name = krate.name; @@ -594,15 +596,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { &style_files, ); self.shared.fs.write(&settings_file, v.as_bytes())?; - - // Flush pending errors. - Arc::get_mut(&mut self.shared).unwrap().fs.close(); - let nb_errors = self.errors.iter().map(|err| diag.struct_err(&err).emit()).count(); - if nb_errors > 0 { - Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) - } else { - Ok(()) - } + Ok(()) } fn mod_item_in( @@ -2474,7 +2468,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: fn render_implementor( cx: &Context<'_>, implementor: &Impl, - trait_: &clean::Item, + parent: &clean::Item, w: &mut Buffer, implementor_dups: &FxHashMap<Symbol, (DefId, bool)>, aliases: &[String], @@ -2494,11 +2488,11 @@ fn render_implementor( w, cx, implementor, - trait_, + parent, AssocItemLink::Anchor(None), RenderMode::Normal, - trait_.stable_since(cx.tcx()).as_deref(), - trait_.const_stable_since(cx.tcx()).as_deref(), + implementor.impl_item.stable_since(cx.tcx()).as_deref(), + implementor.impl_item.const_stable_since(cx.tcx()).as_deref(), false, Some(use_absolute), false, @@ -2937,25 +2931,34 @@ fn render_stability_since_raw( containing_ver: Option<&str>, containing_const_ver: Option<&str>, ) { - let ver = ver.filter(|inner| !inner.is_empty()); - let const_ver = const_ver.filter(|inner| !inner.is_empty()); + let ver = ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None }); - match (ver, const_ver) { - (Some(v), Some(cv)) if const_ver != containing_const_ver => { - write!( - w, - "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>", - v, cv - ); - } - (Some(v), _) if ver != containing_ver => { - write!( - w, - "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", - v - ); + let const_ver = const_ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None }); + + if let Some(v) = ver { + if let Some(cv) = const_ver { + if const_ver != containing_const_ver { + write!( + w, + "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>", + v, cv + ); + } else if ver != containing_ver { + write!( + w, + "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", + v + ); + } + } else { + if ver != containing_ver { + write!( + w, + "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", + v + ); + } } - _ => {} } } @@ -3098,7 +3101,7 @@ fn item_struct( _ => None, }) .peekable(); - if let CtorKind::Fictive = s.struct_type { + if let doctree::Plain = s.struct_type { if fields.peek().is_some() { write!( w, @@ -3348,7 +3351,7 @@ fn render_struct( w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, - ty: CtorKind, + ty: doctree::StructType, fields: &[clean::Item], tab: &str, structhead: bool, @@ -3365,7 +3368,7 @@ fn render_struct( write!(w, "{}", g.print()) } match ty { - CtorKind::Fictive => { + doctree::Plain => { if let Some(g) = g { write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }) } @@ -3397,7 +3400,7 @@ fn render_struct( } write!(w, "}}"); } - CtorKind::Fn => { + doctree::Tuple => { write!(w, "("); for (i, field) in fields.iter().enumerate() { if i > 0 { @@ -3422,7 +3425,7 @@ fn render_struct( } write!(w, ";"); } - CtorKind::Const => { + doctree::Unit => { // Needed for PhantomData. if let Some(g) = g { write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false }) @@ -4457,7 +4460,7 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea let fields = get_struct_fields_name(&s.fields); if !fields.is_empty() { - if let CtorKind::Fictive = s.struct_type { + if let doctree::Plain = s.struct_type { sidebar.push_str(&format!( "<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\ <div class=\"sidebar-links\">{}</div>", diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bfd2141d9a174..7d05cb016b67c 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -5,11 +5,11 @@ use std::convert::From; use rustc_ast::ast; -use rustc_hir::def::CtorKind; use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_span::Pos; use crate::clean; +use crate::doctree; use crate::formats::item_type::ItemType; use crate::json::types::*; use crate::json::JsonRenderer; @@ -27,7 +27,7 @@ impl JsonRenderer<'_> { name: name.map(|sym| sym.to_string()), source: self.convert_span(source), visibility: self.convert_visibility(visibility), - docs: attrs.collapsed_doc_value(), + docs: attrs.collapsed_doc_value().unwrap_or_default(), links: attrs .links .into_iter() @@ -210,9 +210,9 @@ impl From<clean::Struct> for Struct { impl From<clean::Union> for Struct { fn from(struct_: clean::Union) -> Self { - let clean::Union { generics, fields, fields_stripped } = struct_; + let clean::Union { struct_type, generics, fields, fields_stripped } = struct_; Struct { - struct_type: StructType::Union, + struct_type: struct_type.into(), generics: generics.into(), fields_stripped, fields: ids(fields), @@ -221,12 +221,13 @@ impl From<clean::Union> for Struct { } } -impl From<CtorKind> for StructType { - fn from(struct_type: CtorKind) -> Self { +impl From<doctree::StructType> for StructType { + fn from(struct_type: doctree::StructType) -> Self { + use doctree::StructType::*; match struct_type { - CtorKind::Fictive => StructType::Plain, - CtorKind::Fn => StructType::Tuple, - CtorKind::Const => StructType::Unit, + Plain => StructType::Plain, + Tuple => StructType::Tuple, + Unit => StructType::Unit, } } } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 512c9124727ef..df7ab9b7361a0 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -13,7 +13,7 @@ use std::path::PathBuf; use std::rc::Rc; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty; use rustc_session::Session; use rustc_span::edition::Edition; @@ -26,7 +26,7 @@ use crate::html::render::cache::ExternalLocation; #[derive(Clone)] crate struct JsonRenderer<'tcx> { - tcx: TyCtxt<'tcx>, + tcx: ty::TyCtxt<'tcx>, /// A mapping of IDs that contains all local items for this crate which gets output as a top /// level field of the JSON blob. index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>, @@ -125,17 +125,13 @@ impl JsonRenderer<'_> { } impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { - fn descr() -> &'static str { - "json" - } - fn init( krate: clean::Crate, options: RenderOptions, _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, - tcx: TyCtxt<'tcx>, + tcx: ty::TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error> { debug!("Initializing json renderer"); Ok(( @@ -203,12 +199,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { Ok(()) } - fn after_krate( - &mut self, - krate: &clean::Crate, - cache: &Cache, - _diag: &rustc_errors::Handler, - ) -> Result<(), Error> { + fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> { debug!("Done with crate"); let mut index = (*self.index).clone().into_inner(); index.extend(self.get_trait_items(cache)); @@ -245,7 +236,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { ) }) .collect(), - format_version: 2, + format_version: 1, }; let mut p = self.out_path.clone(); p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); @@ -254,4 +245,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { serde_json::ser::to_writer(&file, &output).unwrap(); Ok(()) } + + fn after_run(&mut self, _diag: &rustc_errors::Handler) -> Result<(), Error> { + Ok(()) + } } diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs index 66cf12954dd0b..9335fe9be1a4b 100644 --- a/src/librustdoc/json/types.rs +++ b/src/librustdoc/json/types.rs @@ -68,9 +68,8 @@ pub struct Item { /// By default all documented items are public, but you can tell rustdoc to output private items /// so this field is needed to differentiate. pub visibility: Visibility, - /// The full markdown docstring of this item. Absent if there is no documentation at all, - /// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`). - pub docs: Option<String>, + /// The full markdown docstring of this item. + pub docs: String, /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs pub links: FxHashMap<String, Id>, /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) @@ -270,7 +269,6 @@ pub enum StructType { Plain, Tuple, Unit, - Union, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c61cbf78f771a..719aca612f50d 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -18,7 +18,6 @@ #![feature(str_split_once)] #![feature(iter_intersperse)] #![recursion_limit = "256"] -#![deny(rustc::internal)] #[macro_use] extern crate lazy_static; @@ -66,7 +65,7 @@ use std::process; use rustc_driver::abort_on_err; use rustc_errors::ErrorReported; use rustc_interface::interface; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; use rustc_session::getopts; use rustc_session::{early_error, early_warn}; @@ -168,14 +167,6 @@ fn opts() -> Vec<RustcOptGroup> { stable("test-args", |o| { o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") }), - unstable("test-run-directory", |o| { - o.optopt( - "", - "test-run-directory", - "The working directory in which to run tests", - "PATH", - ) - }), stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")), stable("markdown-css", |o| { o.optmulti( @@ -480,7 +471,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( render_info: config::RenderInfo, diag: &rustc_errors::Handler, edition: rustc_span::edition::Edition, - tcx: TyCtxt<'tcx>, + tcx: ty::TyCtxt<'tcx>, ) -> MainResult { match formats::run_format::<T>(krate, renderopts, render_info, &diag, edition, tcx) { Ok(_) => Ok(()), @@ -548,7 +539,7 @@ fn main_options(options: config::Options) -> MainResult { sess.fatal("Compilation failed, aborting rustdoc"); } - let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut(); + let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); global_ctxt.enter(|tcx| { let (mut krate, render_info, render_opts) = sess.time("run_global_ctxt", || { diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 9516130034b59..554392c213e24 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> { if let Some(dox) = &item.attrs.collapsed_doc_value() { let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); - let extra = crate::html::markdown::ExtraInfo::new_did(self.cx.tcx, item.def_id, sp); + let extra = crate::html::markdown::ExtraInfo::new_did(&self.cx.tcx, item.def_id, sp); for code_block in markdown::rust_code_blocks(&dox, &extra) { self.check_rust_syntax(&item, &dox, code_block); } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 002d8938f694d..2694450a520c9 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -13,7 +13,6 @@ use rustc_hir::def::{ PerNS, }; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, ty}; use rustc_resolve::ParentScope; use rustc_session::lint::{ @@ -86,7 +85,7 @@ impl Res { } } - fn name(self, tcx: TyCtxt<'_>) -> String { + fn name(self, tcx: ty::TyCtxt<'_>) -> String { match self { Res::Def(_, id) => tcx.item_name(id).to_string(), Res::Primitive(prim) => prim.as_str().to_string(), @@ -866,11 +865,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly let self_name = self_id.and_then(|self_id| { + use ty::TyKind; if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) { // using `ty.to_string()` (or any variant) has issues with raw idents let ty = self.cx.tcx.type_of(self_id); let name = match ty.kind() { - ty::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()), + TyKind::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()), other if other.is_primitive() => Some(ty.to_string()), _ => None, }; diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff deleted file mode 100644 index 54dd545dfb9a6..0000000000000 --- a/src/test/mir-opt/inline/cycle.f.Inline.diff +++ /dev/null @@ -1,42 +0,0 @@ -- // MIR for `f` before Inline -+ // MIR for `f` after Inline - - fn f(_1: impl Fn()) -> () { - debug g => _1; // in scope 0 at $DIR/cycle.rs:5:6: 5:7 - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:5:20: 5:20 - let _2: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 - let mut _3: &impl Fn(); // in scope 0 at $DIR/cycle.rs:6:5: 6:6 - let mut _4: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 - - bb0: { - StorageLive(_2); // scope 0 at $DIR/cycle.rs:6:5: 6:8 - StorageLive(_3); // scope 0 at $DIR/cycle.rs:6:5: 6:6 - _3 = &_1; // scope 0 at $DIR/cycle.rs:6:5: 6:6 - StorageLive(_4); // scope 0 at $DIR/cycle.rs:6:5: 6:8 - _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:6:5: 6:8 - // mir::Constant - // + span: $DIR/cycle.rs:6:5: 6:6 - // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as std::ops::FnOnce<()>>::Output {<impl Fn() as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) } - } - - bb1: { - StorageDead(_4); // scope 0 at $DIR/cycle.rs:6:7: 6:8 - StorageDead(_3); // scope 0 at $DIR/cycle.rs:6:7: 6:8 - StorageDead(_2); // scope 0 at $DIR/cycle.rs:6:8: 6:9 - _0 = const (); // scope 0 at $DIR/cycle.rs:5:20: 7:2 - drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/cycle.rs:7:1: 7:2 - } - - bb2: { - return; // scope 0 at $DIR/cycle.rs:7:2: 7:2 - } - - bb3 (cleanup): { - drop(_1) -> bb4; // scope 0 at $DIR/cycle.rs:7:1: 7:2 - } - - bb4 (cleanup): { - resume; // scope 0 at $DIR/cycle.rs:5:1: 7:2 - } - } - diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff deleted file mode 100644 index 46f5e5e20655b..0000000000000 --- a/src/test/mir-opt/inline/cycle.g.Inline.diff +++ /dev/null @@ -1,25 +0,0 @@ -- // MIR for `g` before Inline -+ // MIR for `g` after Inline - - fn g() -> () { - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8 - let _1: (); // in scope 0 at $DIR/cycle.rs:12:5: 12:12 - - bb0: { - StorageLive(_1); // scope 0 at $DIR/cycle.rs:12:5: 12:12 - _1 = f::<fn() {main}>(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12 - // mir::Constant - // + span: $DIR/cycle.rs:12:5: 12:6 - // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) } - // mir::Constant - // + span: $DIR/cycle.rs:12:7: 12:11 - // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) } - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/cycle.rs:12:12: 12:13 - _0 = const (); // scope 0 at $DIR/cycle.rs:11:8: 13:2 - return; // scope 0 at $DIR/cycle.rs:13:2: 13:2 - } - } - diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff deleted file mode 100644 index c8d1448d949d4..0000000000000 --- a/src/test/mir-opt/inline/cycle.main.Inline.diff +++ /dev/null @@ -1,25 +0,0 @@ -- // MIR for `main` before Inline -+ // MIR for `main` after Inline - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11 - let _1: (); // in scope 0 at $DIR/cycle.rs:17:5: 17:9 - - bb0: { - StorageLive(_1); // scope 0 at $DIR/cycle.rs:17:5: 17:9 - _1 = f::<fn() {g}>(g) -> bb1; // scope 0 at $DIR/cycle.rs:17:5: 17:9 - // mir::Constant - // + span: $DIR/cycle.rs:17:5: 17:6 - // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) } - // mir::Constant - // + span: $DIR/cycle.rs:17:7: 17:8 - // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) } - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/cycle.rs:17:9: 17:10 - _0 = const (); // scope 0 at $DIR/cycle.rs:16:11: 18:2 - return; // scope 0 at $DIR/cycle.rs:18:2: 18:2 - } - } - diff --git a/src/test/mir-opt/inline/cycle.rs b/src/test/mir-opt/inline/cycle.rs deleted file mode 100644 index 9e8950d8a3d61..0000000000000 --- a/src/test/mir-opt/inline/cycle.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-wasm32-bare compiled with panic=abort by default - -// EMIT_MIR cycle.f.Inline.diff -#[inline(always)] -fn f(g: impl Fn()) { - g(); -} - -// EMIT_MIR cycle.g.Inline.diff -#[inline(always)] -fn g() { - f(main); -} - -// EMIT_MIR cycle.main.Inline.diff -fn main() { - f(g); -} diff --git a/src/test/mir-opt/inline/inline-cycle-generic.rs b/src/test/mir-opt/inline/inline-cycle-generic.rs deleted file mode 100644 index 24b4f37939ad1..0000000000000 --- a/src/test/mir-opt/inline/inline-cycle-generic.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Check that inliner handles various forms of recursion and doesn't fall into -// an infinite inlining cycle. The particular outcome of inlining is not -// crucial otherwise. -// -// Regression test for issue #78573. - -// EMIT_MIR inline_cycle_generic.main.Inline.diff -fn main() { - <C as Call>::call(); -} - -pub trait Call { - fn call(); -} - -pub struct A; -pub struct B<T>(T); -pub struct C; - -impl Call for A { - #[inline] - fn call() { - <B<C> as Call>::call() - } -} - - -impl<T: Call> Call for B<T> { - #[inline] - fn call() { - <T as Call>::call() - } -} - -impl Call for C { - #[inline] - fn call() { - <B<A> as Call>::call() - } -} diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index 4bda9ae383c22..db504b416fe1d 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -40,7 +40,7 @@ fn foo(_1: T, _2: &i32) -> i32 { _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageLive(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 _10 = _8; // scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _0 = (*_10); // scope 3 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff deleted file mode 100644 index 9709f27377920..0000000000000 --- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff +++ /dev/null @@ -1,29 +0,0 @@ -- // MIR for `main` before Inline -+ // MIR for `main` after Inline - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11 - let _1: (); // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ } -+ } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 -- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline-cycle-generic.rs:9:5: 9:24 - // mir::Constant -- // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22 -- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) } -+ // + span: $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(Scalar(<ZST>)) } - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:24: 9:25 - _0 = const (); // scope 0 at $DIR/inline-cycle-generic.rs:8:11: 10:2 - return; // scope 0 at $DIR/inline-cycle-generic.rs:10:2: 10:2 - } - } - diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs new file mode 100644 index 0000000000000..78361c336607c --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.rs @@ -0,0 +1,69 @@ +// compile-flags: -O -Zunsound-mir-opts +// EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff +fn simple_opt() -> u64 { + let x = 5; + let y = &x; + let z = *y; + z +} + +// EMIT_MIR inst_combine_deref.deep_opt.InstCombine.diff +fn deep_opt() -> (u64, u64, u64) { + let x1 = 1; + let x2 = 2; + let x3 = 3; + let y1 = &x1; + let y2 = &x2; + let y3 = &x3; + let z1 = *y1; + let z2 = *y2; + let z3 = *y3; + (z1, z2, z3) +} + +struct S { + a: u64, + b: u64, +} + +// EMIT_MIR inst_combine_deref.opt_struct.InstCombine.diff +fn opt_struct(s: S) -> u64 { + let a = &s.a; + let b = &s.b; + let x = *a; + *b + x +} + +// EMIT_MIR inst_combine_deref.dont_opt.InstCombine.diff +// do not optimize a sequence looking like this: +// _1 = &_2; +// _1 = _3; +// _4 = *_1; +// as the _1 = _3 assignment makes it not legal to replace the last statement with _4 = _2 +fn dont_opt() -> u64 { + let y = 5; + let _ref = &y; + let x = 5; + let mut _1 = &x; + _1 = _ref; + let _4 = *_1; + 0 +} + +// EMIT_MIR inst_combine_deref.do_not_miscompile.InstCombine.diff +fn do_not_miscompile() { + let x = 42; + let a = 99; + let mut y = &x; + let z = &mut y; + *z = &a; + assert!(*y == 99); +} + +fn main() { + simple_opt(); + deep_opt(); + opt_struct(S { a: 0, b: 1 }); + dont_opt(); + do_not_miscompile(); +} diff --git a/src/test/rustdoc-ui/run-directory.correct.stdout b/src/test/rustdoc-ui/run-directory.correct.stdout deleted file mode 100644 index e9b2754794a78..0000000000000 --- a/src/test/rustdoc-ui/run-directory.correct.stdout +++ /dev/null @@ -1,6 +0,0 @@ - -running 1 test -test $DIR/run-directory.rs - foo (line 10) ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - diff --git a/src/test/rustdoc-ui/run-directory.incorrect.stdout b/src/test/rustdoc-ui/run-directory.incorrect.stdout deleted file mode 100644 index 97a5dbc5c0cd1..0000000000000 --- a/src/test/rustdoc-ui/run-directory.incorrect.stdout +++ /dev/null @@ -1,6 +0,0 @@ - -running 1 test -test $DIR/run-directory.rs - foo (line 19) ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - diff --git a/src/test/rustdoc-ui/run-directory.rs b/src/test/rustdoc-ui/run-directory.rs deleted file mode 100644 index 78431c0e80b59..0000000000000 --- a/src/test/rustdoc-ui/run-directory.rs +++ /dev/null @@ -1,23 +0,0 @@ -// this test asserts that the cwd of doctest invocations is set correctly. - -// revisions: correct incorrect -// check-pass -// [correct]compile-flags:--test --test-run-directory={{src-base}} -// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" -// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" - -/// ``` -/// assert_eq!( -/// std::fs::read_to_string("run-directory.rs").unwrap(), -/// include_str!("run-directory.rs"), -/// ); -/// ``` -#[cfg(correct)] -pub fn foo() {} - -/// ``` -/// assert!(std::fs::read_to_string("run-directory.rs").is_err()); -/// ``` -#[cfg(incorrect)] -pub fn foo() {} diff --git a/src/test/rustdoc/implementor-stable-version.rs b/src/test/rustdoc/implementor-stable-version.rs deleted file mode 100644 index 0a065d8095bf2..0000000000000 --- a/src/test/rustdoc/implementor-stable-version.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![crate_name = "foo"] - -#![feature(staged_api)] - -#[stable(feature = "bar", since = "OLD 1.0")] -pub trait Bar {} - -#[stable(feature = "baz", since = "OLD 1.0")] -pub trait Baz {} - -pub struct Foo; - -// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0' -#[stable(feature = "foobar", since = "NEW 2.0")] -impl Bar for Foo {} - -// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0' -#[stable(feature = "foobaz", since = "OLD 1.0")] -impl Baz for Foo {} diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs index 9a22903a94cc8..841702987ef7c 100644 --- a/src/test/rustdoc/reexport-check.rs +++ b/src/test/rustdoc/reexport-check.rs @@ -4,7 +4,7 @@ extern crate reexport_check; // @!has 'foo/index.html' '//code' 'pub use self::i32;' -// @has 'foo/index.html' '//tr[@class="deprecated module-item"]' 'i32' +// @has 'foo/index.html' '//tr[@class="module-item"]' 'i32' // @has 'foo/i32/index.html' #[allow(deprecated, deprecated_in_future)] pub use std::i32; diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs index beb638406c4be..59427693c5a5d 100644 --- a/src/test/rustdoc/visibility.rs +++ b/src/test/rustdoc/visibility.rs @@ -42,35 +42,3 @@ mod a { struct FooBPriv; } } - -// @has 'foo/trait.PubTrait.html' '//pre' 'pub trait PubTrait' -// -// @has 'foo/trait.PubTrait.html' '//pre' 'type Type;' -// @!has 'foo/trait.PubTrait.html' '//pre' 'pub type Type;' -// -// @has 'foo/trait.PubTrait.html' '//pre' 'const CONST: usize;' -// @!has 'foo/trait.PubTrait.html' '//pre' 'pub const CONST: usize;' -// -// @has 'foo/trait.PubTrait.html' '//pre' 'fn function();' -// @!has 'foo/trait.PubTrait.html' '//pre' 'pub fn function();' - -pub trait PubTrait { - type Type; - const CONST: usize; - fn function(); -} - -// @has 'foo/struct.FooPublic.html' '//code' 'type Type' -// @!has 'foo/struct.FooPublic.html' '//code' 'pub type Type' -// -// @has 'foo/struct.FooPublic.html' '//code' 'const CONST: usize' -// @!has 'foo/struct.FooPublic.html' '//code' 'pub const CONST: usize' -// -// @has 'foo/struct.FooPublic.html' '//code' 'fn function()' -// @!has 'foo/struct.FooPublic.html' '//code' 'pub fn function()' - -impl PubTrait for FooPublic { - type Type = usize; - const CONST: usize = 0; - fn function() {} -} diff --git a/src/test/ui-fulldeps/lint-tool-test.stderr b/src/test/ui-fulldeps/lint-tool-test.stderr index 2260477a91d39..5e1cb4fb843fd 100644 --- a/src/test/ui-fulldeps/lint-tool-test.stderr +++ b/src/test/ui-fulldeps/lint-tool-test.stderr @@ -1,4 +1,4 @@ -warning: lint name `test_lint` is deprecated and may not have an effect in the future. +warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:9:23 | LL | #![cfg_attr(foo, warn(test_lint))] @@ -6,13 +6,13 @@ LL | #![cfg_attr(foo, warn(test_lint))] | = note: `#[warn(renamed_and_removed_lints)]` on by default -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. +warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` -warning: lint name `test_group` is deprecated and may not have an effect in the future. +warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:29:9 | LL | #[allow(test_group)] @@ -26,19 +26,19 @@ LL | #[deny(this_lint_does_not_exist)] | = note: `#[warn(unknown_lints)]` on by default -warning: lint name `test_lint` is deprecated and may not have an effect in the future. +warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:9:23 | LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. +warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` -warning: lint name `test_group` is deprecated and may not have an effect in the future. +warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:29:9 | LL | #[allow(test_group)] @@ -52,13 +52,13 @@ LL | #![plugin(lint_tool_test)] | = note: `#[warn(deprecated)]` on by default -warning: lint name `test_lint` is deprecated and may not have an effect in the future. +warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:9:23 | LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. +warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:13:9 | LL | #![deny(clippy_group)] @@ -90,7 +90,7 @@ LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]` -warning: lint name `test_group` is deprecated and may not have an effect in the future. +warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore --> $DIR/lint-tool-test.rs:29:9 | LL | #[allow(test_group)] diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 02342af8dc53e..9c29a5f2337cd 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 235f39c567b8e..cccd51985dc83 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/attributes/key-value-non-ascii.rs b/src/test/ui/attributes/key-value-non-ascii.rs deleted file mode 100644 index 91c917e7db56f..0000000000000 --- a/src/test/ui/attributes/key-value-non-ascii.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_dummy = b"ffi.rs"] //~ ERROR byte constant must be ASCII -fn main() {} diff --git a/src/test/ui/attributes/key-value-non-ascii.stderr b/src/test/ui/attributes/key-value-non-ascii.stderr deleted file mode 100644 index 3e082139f895b..0000000000000 --- a/src/test/ui/attributes/key-value-non-ascii.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte - --> $DIR/key-value-non-ascii.rs:3:19 - | -LL | #[rustc_dummy = b"ffi.rs"] - | ^ - -error: aborting due to previous error - diff --git a/src/test/ui/check-static-immutable-mut-slices.rs b/src/test/ui/check-static-immutable-mut-slices.rs index 8f9680778aa03..3be02f6a0f674 100644 --- a/src/test/ui/check-static-immutable-mut-slices.rs +++ b/src/test/ui/check-static-immutable-mut-slices.rs @@ -1,6 +1,6 @@ // Checks that immutable static items can't have mutable slices static TEST: &'static mut [isize] = &mut []; -//~^ ERROR mutable references are not allowed +//~^ ERROR mutable references are not allowed in statics pub fn main() { } diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr index a32a94c1315ab..9ffbb483d139d 100644 --- a/src/test/ui/check-static-immutable-mut-slices.stderr +++ b/src/test/ui/check-static-immutable-mut-slices.stderr @@ -1,8 +1,8 @@ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable references are not allowed in statics --> $DIR/check-static-immutable-mut-slices.rs:3:37 | LL | static TEST: &'static mut [isize] = &mut []; - | ^^^^^^^ + | ^^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to previous error diff --git a/src/test/ui/closures/local-type-mix.rs b/src/test/ui/closures/local-type-mix.rs deleted file mode 100644 index 006e6f490f06b..0000000000000 --- a/src/test/ui/closures/local-type-mix.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Check that using the parameter name in its type does not ICE. -// edition:2018 - -#![feature(async_closure)] - -fn main() { - let _ = |x: x| x; //~ ERROR expected type - let _ = |x: bool| -> x { x }; //~ ERROR expected type - let _ = async move |x: x| x; //~ ERROR expected type - let _ = async move |x: bool| -> x { x }; //~ ERROR expected type -} - -fn foo(x: x) {} //~ ERROR expected type -fn foo_ret(x: bool) -> x {} //~ ERROR expected type - -async fn async_foo(x: x) {} //~ ERROR expected type -async fn async_foo_ret(x: bool) -> x {} //~ ERROR expected type diff --git a/src/test/ui/closures/local-type-mix.stderr b/src/test/ui/closures/local-type-mix.stderr deleted file mode 100644 index 68c320a065d57..0000000000000 --- a/src/test/ui/closures/local-type-mix.stderr +++ /dev/null @@ -1,51 +0,0 @@ -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:7:17 - | -LL | let _ = |x: x| x; - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:8:26 - | -LL | let _ = |x: bool| -> x { x }; - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:9:28 - | -LL | let _ = async move |x: x| x; - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:10:37 - | -LL | let _ = async move |x: bool| -> x { x }; - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:13:11 - | -LL | fn foo(x: x) {} - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:14:24 - | -LL | fn foo_ret(x: bool) -> x {} - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:16:23 - | -LL | async fn async_foo(x: x) {} - | ^ not a type - -error[E0573]: expected type, found local variable `x` - --> $DIR/local-type-mix.rs:17:36 - | -LL | async fn async_foo_ret(x: bool) -> x {} - | ^ not a type - -error: aborting due to 8 previous errors - -For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/command/command-setgroups.rs b/src/test/ui/command/command-setgroups.rs deleted file mode 100644 index 28f2bfdd3a776..0000000000000 --- a/src/test/ui/command/command-setgroups.rs +++ /dev/null @@ -1,26 +0,0 @@ -// run-pass -// ignore-windows - this is a unix-specific test -// ignore-cloudabi -// ignore-emscripten -// ignore-sgx - -#![feature(rustc_private)] -#![feature(setgroups)] - -extern crate libc; -use std::process::Command; -use std::os::unix::process::CommandExt; - -fn main() { - #[cfg(unix)] - run() -} - -#[cfg(unix)] -fn run() { - let max_ngroups = unsafe { libc::sysconf(libc::_SC_NGROUPS_MAX) }; - let max_ngroups = max_ngroups as u32 + 1; - let vec: Vec<u32> = (0..max_ngroups).collect(); - let p = Command::new("/bin/id").groups(&vec[..]).spawn(); - assert!(p.is_err()); -} diff --git a/src/test/ui/const_prop/inline_spans_lint_attribute.rs b/src/test/ui/const_prop/inline_spans_lint_attribute.rs deleted file mode 100644 index 656ff02dc67ef..0000000000000 --- a/src/test/ui/const_prop/inline_spans_lint_attribute.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Must be build-pass, because check-pass will not run const prop and thus not emit the lint anyway. -// build-pass -// compile-flags: -Zmir-opt-level=2 - -#![deny(warnings)] - -fn main() { - #[allow(arithmetic_overflow)] - let _ = add(u8::MAX, 1); -} - -#[inline(always)] -fn add(x: u8, y: u8) -> u8 { - x + y -} diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index 9b3f735b1f849..f36ebf38db4fe 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -6,4 +6,6 @@ fn main() { &{ [1, 2, 3][4] }; //~^ WARN operation will panic + //~| WARN reaching this expression at runtime will panic or abort + //~| WARN erroneous constant used [const_err] } diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index f96b8d48b3e7c..5916ea6d323e6 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -10,5 +10,25 @@ note: the lint level is defined here LL | #![warn(const_err, unconditional_panic)] | ^^^^^^^^^^^^^^^^^^^ -warning: 1 warning emitted +warning: reaching this expression at runtime will panic or abort + --> $DIR/array-literal-index-oob.rs:7:8 + | +LL | &{ [1, 2, 3][4] }; + | ---^^^^^^^^^^^^-- + | | + | indexing out of bounds: the len is 3 but the index is 4 + | +note: the lint level is defined here + --> $DIR/array-literal-index-oob.rs:4:9 + | +LL | #![warn(const_err, unconditional_panic)] + | ^^^^^^^^^ + +warning: erroneous constant used + --> $DIR/array-literal-index-oob.rs:7:5 + | +LL | &{ [1, 2, 3][4] }; + | ^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: 3 warnings emitted diff --git a/src/test/ui/consts/const-address-of-mut.stderr b/src/test/ui/consts/const-address-of-mut.stderr index 60cdcc7df7449..ec2dac5a7d16f 100644 --- a/src/test/ui/consts/const-address-of-mut.stderr +++ b/src/test/ui/consts/const-address-of-mut.stderr @@ -1,29 +1,20 @@ -error[E0658]: raw mutable references are not allowed in constants +error[E0764]: raw mutable references are not allowed in constants --> $DIR/const-address-of-mut.rs:3:32 | LL | const A: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^ `&raw mut` is only allowed in `const fn` -error[E0658]: raw mutable references are not allowed in statics +error[E0764]: raw mutable references are not allowed in statics --> $DIR/const-address-of-mut.rs:5:33 | LL | static B: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^ `&raw mut` is only allowed in `const fn` -error[E0658]: raw mutable references are not allowed in statics +error[E0764]: raw mutable references are not allowed in statics --> $DIR/const-address-of-mut.rs:7:37 | LL | static mut C: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^ `&raw mut` is only allowed in `const fn` error[E0658]: raw mutable references are not allowed in constant functions --> $DIR/const-address-of-mut.rs:11:13 @@ -36,4 +27,5 @@ LL | let y = &raw mut x; error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.rs b/src/test/ui/consts/const-eval/const-eval-query-stack.rs index 39803c8f257e0..8a6f7de1c9fbd 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.rs +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.rs @@ -1,5 +1,4 @@ -//~ERROR constructed but no error reported -// compile-flags: -Ztreat-err-as-bug=2 +// compile-flags: -Ztreat-err-as-bug // build-fail // failure-status: 101 // rustc-env:RUST_BACKTRACE=1 @@ -16,11 +15,8 @@ #![allow(unconditional_panic)] -#[warn(const_err)] -const X: i32 = 1 / 0; //~WARN any use of this value will cause an error - fn main() { - let x: &'static i32 = &X; - //~^ ERROR evaluation of constant expression failed + let x: &'static i32 = &(1 / 0); + //~^ ERROR reaching this expression at runtime will panic or abort [const_err] println!("x={}", x); } diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index 0016d301e598c..8c57fd37e88f6 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -1,26 +1,18 @@ -warning: any use of this value will cause an error - --> $DIR/const-eval-query-stack.rs:20:16 +error: reaching this expression at runtime will panic or abort + --> $DIR/const-eval-query-stack.rs:19:28 | -LL | const X: i32 = 1 / 0; - | ---------------^^^^^- - | | - | attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/const-eval-query-stack.rs:19:8 +LL | let x: &'static i32 = &(1 / 0); + | -^^^^^^^ + | | + | dividing by zero | -LL | #[warn(const_err)] - | ^^^^^^^^^ + = note: `#[deny(const_err)]` on by default -error[E0080]: evaluation of constant expression failed - --> $DIR/const-eval-query-stack.rs:23:27 - | -LL | let x: &'static i32 = &X; - | ^- - | | - | referenced constant has errors query stack during panic: -#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` -#1 [optimized_mir] optimizing MIR for `main` -#2 [collect_and_partition_mono_items] collect_and_partition_mono_items +#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]` +#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` +#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` +#3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` +#4 [optimized_mir] optimizing MIR for `main` +#5 [collect_and_partition_mono_items] collect_and_partition_mono_items end of query stack diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr index ec229d7f53a0f..771d368d78391 100644 --- a/src/test/ui/consts/const-eval/issue-65394.stderr +++ b/src/test/ui/consts/const-eval/issue-65394.stderr @@ -1,11 +1,8 @@ -error[E0658]: mutable references are not allowed in constants +error[E0764]: mutable references are not allowed in constants --> $DIR/issue-65394.rs:8:13 | LL | let r = &mut x; - | ^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/issue-65394.rs:7:9 @@ -18,5 +15,5 @@ LL | }; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0493, E0658. +Some errors have detailed explanations: E0493, E0764. For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr index 1cd1be5309b90..ce83d8e9bb0c9 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -1,21 +1,38 @@ -warning: any use of this value will cause an error - --> $DIR/promoted_errors.rs:13:5 - | -LL | 0 - 1 - | ^^^^^ - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow - | inside `overflow` at $DIR/promoted_errors.rs:13:5 - | inside `X` at $DIR/promoted_errors.rs:31:29 -... -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:12:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:20 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:14:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:41 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:9 @@ -23,18 +40,41 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^ -warning: any use of this value will cause an error - --> $DIR/promoted_errors.rs:31:28 +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:26:14 | -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); - | | ^^^^^^^^^^^ referenced constant has errors -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero -warning: 2 warnings emitted +warning: 10 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr index ca62e21b61385..2c66b175cfc2b 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -1,21 +1,32 @@ -warning: any use of this value will cause an error - --> $DIR/promoted_errors.rs:17:5 - | -LL | 1 / 0 - | ^^^^^ - | | - | attempt to divide `1_i32` by zero - | inside `div_by_zero1` at $DIR/promoted_errors.rs:17:5 - | inside `X` at $DIR/promoted_errors.rs:33:29 -... -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:14:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:20 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:41 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:9 @@ -23,18 +34,41 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^ -warning: any use of this value will cause an error - --> $DIR/promoted_errors.rs:33:28 +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:26:14 | -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); - | | ^^^^^^^^^^^^^^^ referenced constant has errors -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero -warning: 2 warnings emitted +warning: 9 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr index 1cd1be5309b90..ce83d8e9bb0c9 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -1,21 +1,38 @@ -warning: any use of this value will cause an error - --> $DIR/promoted_errors.rs:13:5 - | -LL | 0 - 1 - | ^^^^^ - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow - | inside `overflow` at $DIR/promoted_errors.rs:13:5 - | inside `X` at $DIR/promoted_errors.rs:31:29 -... -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:12:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:20 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:14:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:41 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:9 @@ -23,18 +40,41 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^ -warning: any use of this value will cause an error - --> $DIR/promoted_errors.rs:31:28 +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:26:14 | -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); - | | ^^^^^^^^^^^ referenced constant has errors -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero -warning: 2 warnings emitted +warning: 10 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index a2136c8d09be4..142ce75eebc80 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -8,34 +8,21 @@ #![warn(const_err, arithmetic_overflow, unconditional_panic)] -// The only way to have promoteds that fail is in `const fn` called from `const`/`static`. -const fn overflow() -> u32 { - 0 - 1 - //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error -} -const fn div_by_zero1() -> i32 { - 1 / 0 - //[opt]~^ WARN any use of this value will cause an error -} -const fn div_by_zero2() -> i32 { - 1 / (1-1) -} -const fn div_by_zero3() -> i32 { - 1 / (false as i32) -} -const fn oob() -> i32 { - [1,2,3][4] -} - -const X: () = { - let _x: &'static u32 = &overflow(); - //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error - let _x: &'static i32 = &div_by_zero1(); - //[opt]~^ WARN any use of this value will cause an error - let _x: &'static i32 = &div_by_zero2(); - let _x: &'static i32 = &div_by_zero3(); - let _x: &'static i32 = &oob(); -}; - fn main() { + println!("{}", 0u32 - 1); + //[opt_with_overflow_checks,noopt]~^ WARN [arithmetic_overflow] + let _x = 0u32 - 1; + //~^ WARN [arithmetic_overflow] + println!("{}", 1 / (1 - 1)); + //~^ WARN [unconditional_panic] + //~| WARN panic or abort [const_err] + //~| WARN erroneous constant used [const_err] + let _x = 1 / (1 - 1); + //~^ WARN [unconditional_panic] + println!("{}", 1 / (false as u32)); + //~^ WARN [unconditional_panic] + //~| WARN panic or abort [const_err] + //~| WARN erroneous constant used [const_err] + let _x = 1 / (false as u32); + //~^ WARN [unconditional_panic] } diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr index dd5cadfe2951e..c0a320d46cbf9 100644 --- a/src/test/ui/consts/const-multi-ref.stderr +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -1,11 +1,8 @@ -error[E0658]: mutable references are not allowed in constants +error[E0764]: mutable references are not allowed in constants --> $DIR/const-multi-ref.rs:6:13 | LL | let p = &mut a; - | ^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability --> $DIR/const-multi-ref.rs:16:13 @@ -18,4 +15,5 @@ LL | let p = &a; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs index 24df647f05b7e..5819daa817af0 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs @@ -1,4 +1,3 @@ -// check-pass #![feature(const_mut_refs)] #![feature(const_fn)] #![feature(raw_ref_op)] @@ -23,7 +22,9 @@ const fn baz(foo: &mut Foo)-> *mut usize { const _: () = { foo().bar(); + //~^ ERROR mutable references are not allowed in constants baz(&mut foo()); + //~^ ERROR mutable references are not allowed in constants }; fn main() {} diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr new file mode 100644 index 0000000000000..2214ce6ee1c87 --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr @@ -0,0 +1,15 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_address_of.rs:24:5 + | +LL | foo().bar(); + | ^^^^^ `&mut` is only allowed in `const fn` + +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_address_of.rs:26:9 + | +LL | baz(&mut foo()); + | ^^^^^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs index 544458dfcd8bb..9099d5a1b8ea6 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs @@ -1,4 +1,3 @@ -// check-pass #![feature(const_mut_refs)] struct Foo { @@ -30,6 +29,9 @@ const fn bazz(foo: &mut Foo) -> usize { fn main() { let _: [(); foo().bar()] = [(); 1]; + //~^ ERROR mutable references are not allowed in constants let _: [(); baz(&mut foo())] = [(); 2]; + //~^ ERROR mutable references are not allowed in constants let _: [(); bazz(&mut foo())] = [(); 3]; + //~^ ERROR mutable references are not allowed in constants } diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr new file mode 100644 index 0000000000000..4ca7b128b7c4b --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr @@ -0,0 +1,21 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_refs.rs:31:17 + | +LL | let _: [(); foo().bar()] = [(); 1]; + | ^^^^^ `&mut` is only allowed in `const fn` + +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_refs.rs:33:21 + | +LL | let _: [(); baz(&mut foo())] = [(); 2]; + | ^^^^^^^^^^ `&mut` is only allowed in `const fn` + +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_refs.rs:35:22 + | +LL | let _: [(); bazz(&mut foo())] = [(); 3]; + | ^^^^^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs deleted file mode 100644 index 166ba20f124e6..0000000000000 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ /dev/null @@ -1,57 +0,0 @@ -#![feature(const_mut_refs)] -#![feature(const_fn)] -#![feature(raw_ref_op)] -#![feature(const_raw_ptr_deref)] - -const NULL: *mut i32 = std::ptr::null_mut(); -const A: *const i32 = &4; - -// It could be made sound to allow it to compile, -// but we do not want to allow this to compile, -// as that would be an enormous footgun in oli-obk's opinion. -const B: *mut i32 = &mut 4; //~ ERROR mutable references are not allowed - -// Ok, no actual mutable allocation exists -const B2: Option<&mut i32> = None; - -// Not ok, can't prove that no mutable allocation ends up in final value -const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR temporary value dropped while borrowed - -const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) } -const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed - -// Ok, because no references to mutable data exist here, since the `{}` moves -// its value and then takes a reference to that. -const C: *const i32 = &{ - let mut x = 42; - x += 3; - x -}; - -use std::cell::UnsafeCell; -struct NotAMutex<T>(UnsafeCell<T>); - -unsafe impl<T> Sync for NotAMutex<T> {} - -const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); -//~^ ERROR temporary value dropped while borrowed - -static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); -//~^ ERROR temporary value dropped while borrowed - -static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); -//~^ ERROR temporary value dropped while borrowed - -// `BAR` works, because `&42` promotes immediately instead of relying on -// the enclosing scope rule. -const BAR: NotAMutex<&i32> = NotAMutex(UnsafeCell::new(&42)); - -fn main() { - println!("{}", unsafe { *A }); - unsafe { *B = 4 } // Bad news - - unsafe { - **FOO.0.get() = 99; - assert_eq!(**FOO.0.get(), 99); - } -} diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr deleted file mode 100644 index cbae74cce6f6b..0000000000000 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ /dev/null @@ -1,60 +0,0 @@ -error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:12:21 - | -LL | const B: *mut i32 = &mut 4; - | ^^^^^^ - -error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:18:40 - | -LL | const B3: Option<&mut i32> = Some(&mut 42); - | ----------^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:21:42 - | -LL | const B4: Option<&mut i32> = helper(&mut 42); - | ------------^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:36:65 - | -LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); - | -------------------------------^^-- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a constant requires that borrow lasts for `'static` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:39:67 - | -LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); - | -------------------------------^^-- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a static requires that borrow lasts for `'static` - -error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:42:71 - | -LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); - | -------------------------------^^-- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary which is freed while still in use - | using this value as a static requires that borrow lasts for `'static` - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0716, E0764. -For more information about an error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs deleted file mode 100644 index 1e856ec0a0acc..0000000000000 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(const_mut_refs)] -#![feature(const_fn)] -#![feature(raw_ref_op)] -#![feature(const_raw_ptr_deref)] - -// This file checks that our dynamic checks catch things that the static checks miss. -// We do not have static checks for these, because we do not look into function bodies. -// We treat all functions as not returning a mutable reference, because there is no way to -// do that without causing the borrow checker to complain (see the B4/helper test in -// mut_ref_in_final.rs). - -const fn helper() -> Option<&'static mut i32> { unsafe { - // Undefined behaviour (integer as pointer), who doesn't love tests like this. - // This code never gets executed, because the static checks fail before that. - Some(&mut *(42 as *mut i32)) //~ ERROR any use of this value will cause an error -} } -// The error is an evaluation error and not a validation error, so the error is reported -// directly at the site where it occurs. -const A: Option<&mut i32> = helper(); - -const fn helper2() -> Option<&'static mut i32> { unsafe { - // Undefined behaviour (dangling pointer), who doesn't love tests like this. - // This code never gets executed, because the static checks fail before that. - Some(&mut *(&mut 42 as *mut i32)) -} } -const B: Option<&mut i32> = helper2(); //~ ERROR encountered dangling pointer in final constant - -fn main() {} diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr deleted file mode 100644 index 0bbf84b71bb68..0000000000000 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: any use of this value will cause an error - --> $DIR/mut_ref_in_final_dynamic_check.rs:15:10 - | -LL | Some(&mut *(42 as *mut i32)) - | ^^^^^^^^^^^^^^^^^^^^^^ - | | - | unable to turn bytes into a pointer - | inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:15:10 - | inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:19:29 -... -LL | const A: Option<&mut i32> = helper(); - | ------------------------------------- - | - = note: `#[deny(const_err)]` on by default - -error: encountered dangling pointer in final constant - --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1 - | -LL | const B: Option<&mut i32> = helper2(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 3eac61c0ce670..dc86e178a42c3 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -7,24 +7,19 @@ LL | const fn foo(&mut self, x: u32) { = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: mutable references are not allowed in constants +error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:16:5 | LL | s.foo(3); - | ^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^ `&mut` is only allowed in `const fn` -error[E0658]: mutable references are not allowed in constants +error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:22:13 | LL | let y = &mut x; - | ^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/issue-17718-const-bad-values.rs b/src/test/ui/consts/issue-17718-const-bad-values.rs index 62bbb3b569c37..49023f18ddbfb 100644 --- a/src/test/ui/consts/issue-17718-const-bad-values.rs +++ b/src/test/ui/consts/issue-17718-const-bad-values.rs @@ -1,9 +1,10 @@ const C1: &'static mut [usize] = &mut []; -//~^ ERROR: mutable references are not allowed +//~^ ERROR: mutable references are not allowed in constants static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; //~^ ERROR: constants cannot refer to statics //~| ERROR: constants cannot refer to statics +//~| ERROR: mutable references are not allowed in constants fn main() {} diff --git a/src/test/ui/consts/issue-17718-const-bad-values.stderr b/src/test/ui/consts/issue-17718-const-bad-values.stderr index ce60aaa0797f8..7c50978d4ebb8 100644 --- a/src/test/ui/consts/issue-17718-const-bad-values.stderr +++ b/src/test/ui/consts/issue-17718-const-bad-values.stderr @@ -1,8 +1,8 @@ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable references are not allowed in constants --> $DIR/issue-17718-const-bad-values.rs:1:34 | LL | const C1: &'static mut [usize] = &mut []; - | ^^^^^^^ + | ^^^^^^^ `&mut` is only allowed in `const fn` error[E0013]: constants cannot refer to statics --> $DIR/issue-17718-const-bad-values.rs:5:46 @@ -20,7 +20,13 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; | = help: consider extracting the value of the `static` to a `const`, and referring to that -error: aborting due to 3 previous errors +error[E0764]: mutable references are not allowed in constants + --> $DIR/issue-17718-const-bad-values.rs:5:41 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0013, E0764. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr new file mode 100644 index 0000000000000..fad8f011f75f5 --- /dev/null +++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr @@ -0,0 +1,19 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/projection_qualif.rs:10:27 + | +LL | let b: *mut u32 = &mut a; + | ^^^^^^ `&mut` is only allowed in `const fn` + +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/projection_qualif.rs:11:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + | + = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/write_to_mut_ref_dest.rs b/src/test/ui/consts/projection_qualif.rs similarity index 72% rename from src/test/ui/consts/write_to_mut_ref_dest.rs rename to src/test/ui/consts/projection_qualif.rs index d35df330bb8c3..5e2584a6e951a 100644 --- a/src/test/ui/consts/write_to_mut_ref_dest.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -7,7 +7,7 @@ use std::cell::Cell; const FOO: &u32 = { let mut a = 42; { - let b: *mut u32 = &mut a; //[stock]~ ERROR mutable references are not allowed in constants + let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants } &{a} diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr new file mode 100644 index 0000000000000..fad8f011f75f5 --- /dev/null +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -0,0 +1,19 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/projection_qualif.rs:10:27 + | +LL | let b: *mut u32 = &mut a; + | ^^^^^^ `&mut` is only allowed in `const fn` + +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/projection_qualif.rs:11:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + | + = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index 0d0c78b0fc260..1e4d8586b872c 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -44,11 +44,4 @@ fn main() { // We must not promote things with interior mutability. Not even if we "project it away". let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed - - // No promotion of fallible operations. - let _val: &'static _ = &(1/0); //~ ERROR temporary value dropped while borrowed - let _val: &'static _ = &(1/(1-1)); //~ ERROR temporary value dropped while borrowed - let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed - let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed - let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr index 108d0da7a674a..6e76d9ee6c165 100644 --- a/src/test/ui/consts/promote-not.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -65,7 +65,7 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).0; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` -... +LL | let _val: &'static _ = &(Cell::new(1), 2).1; LL | } | - temporary value is freed at the end of this statement @@ -76,64 +76,9 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:49:29 - | -LL | let _val: &'static _ = &(1/0); - | ---------- ^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:50:29 - | -LL | let _val: &'static _ = &(1/(1-1)); - | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:51:29 - | -LL | let _val: &'static _ = &(1%0); - | ---------- ^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -... -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:52:29 - | -LL | let _val: &'static _ = &(1%(1-1)); - | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | let _val: &'static _ = &([1,2,3][4]+1); -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:53:29 - | -LL | let _val: &'static _ = &([1,2,3][4]+1); - | ---------- ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` LL | } | - temporary value is freed at the end of this statement -error: aborting due to 13 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promoted_div_by_zero.rs b/src/test/ui/consts/promoted_div_by_zero.rs new file mode 100644 index 0000000000000..b4503f691ffd9 --- /dev/null +++ b/src/test/ui/consts/promoted_div_by_zero.rs @@ -0,0 +1,9 @@ +#![allow(unconditional_panic, const_err)] + +// run-fail +// error-pattern: attempt to divide by zero +// ignore-emscripten no processes + +fn main() { + let x = &(1 / (1 - 1)); +} diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index 580c6d62f10af..b6e7127a9b779 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -1,43 +1,28 @@ -// revisions: noopt opt opt_with_overflow_checks -//[noopt]compile-flags: -C opt-level=0 -//[opt]compile-flags: -O -//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O +// check-pass -// build-pass -#[allow(arithmetic_overflow)] +// compile-flags: -O -const fn assert_static<T>(_: &'static T) {} +fn foo(_: &'static [&'static str]) {} +fn bar(_: &'static [&'static str; 3]) {} +const fn baz_i32(_: &'static i32) {} +const fn baz_u32(_: &'static u32) {} const fn fail() -> i32 { 1/0 } const C: i32 = { // Promoted that fails to evaluate in dead code -- this must work // (for backwards compatibility reasons). if false { - assert_static(&fail()); + baz_i32(&fail()); } 42 }; fn main() { - assert_static(&["a", "b", "c"]); - assert_static(&["d", "e", "f"]); + foo(&["a", "b", "c"]); + bar(&["d", "e", "f"]); assert_eq!(C, 42); // make sure that these do not cause trouble despite overflowing - assert_static(&(0-1)); - assert_static(&-i32::MIN); - - // div-by-non-0 is okay - assert_static(&(1/1)); - assert_static(&(1%1)); - - // in-bounds array access is okay - assert_static(&([1,2,3][0] + 1)); - assert_static(&[[1,2][1]]); - - // Top-level projections are not part of the promoted, so no error here. - if false { - #[allow(unconditional_panic)] - assert_static(&[1,2,3][4]); - } + baz_u32(&(0-1)); + baz_i32(&-i32::MIN); } diff --git a/src/test/ui/consts/read_from_static_mut_ref.rs b/src/test/ui/consts/read_from_static_mut_ref.rs new file mode 100644 index 0000000000000..5faa983ab09f7 --- /dev/null +++ b/src/test/ui/consts/read_from_static_mut_ref.rs @@ -0,0 +1,9 @@ +// We are keeping this test in case we decide to allow mutable references in statics again +#![feature(const_mut_refs)] +#![allow(const_err)] + +static OH_NO: &mut i32 = &mut 42; +//~^ ERROR mutable references are not allowed in statics +fn main() { + assert_eq!(*OH_NO, 42); +} diff --git a/src/test/ui/consts/read_from_static_mut_ref.stderr b/src/test/ui/consts/read_from_static_mut_ref.stderr new file mode 100644 index 0000000000000..c936ac0b7d585 --- /dev/null +++ b/src/test/ui/consts/read_from_static_mut_ref.stderr @@ -0,0 +1,9 @@ +error[E0764]: mutable references are not allowed in statics + --> $DIR/read_from_static_mut_ref.rs:5:26 + | +LL | static OH_NO: &mut i32 = &mut 42; + | ^^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr index 8db75dd63cf2a..36c280ca5c607 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -1,9 +1,9 @@ -error[E0080]: could not evaluate static initializer - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 +error[E0764]: mutable references are not allowed in statics + --> $DIR/static_mut_containing_mut_ref2.rs:7:46 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index 61368546083db..2821d1a015435 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -5,7 +5,6 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//[mut_refs]~^ ERROR could not evaluate static initializer -//[stock]~^^ ERROR mutable references are not allowed in statics +//~^ ERROR mutable references are not allowed in statics fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr index 5cdcea2323109..36c280ca5c607 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,12 +1,9 @@ -error[E0658]: mutable references are not allowed in statics +error[E0764]: mutable references are not allowed in statics --> $DIR/static_mut_containing_mut_ref2.rs:7:46 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr b/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr deleted file mode 100644 index 3ee50907461ca..0000000000000 --- a/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: dereferencing raw pointers in constants is unstable - --> $DIR/write_to_mut_ref_dest.rs:11:18 - | -LL | unsafe { *b = 5; } - | ^^^^^^ - | - = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information - = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/write_to_mut_ref_dest.stock.stderr b/src/test/ui/consts/write_to_mut_ref_dest.stock.stderr deleted file mode 100644 index 2b6d1d3267b61..0000000000000 --- a/src/test/ui/consts/write_to_mut_ref_dest.stock.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: mutable references are not allowed in constants - --> $DIR/write_to_mut_ref_dest.rs:10:27 - | -LL | let b: *mut u32 = &mut a; - | ^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0658]: dereferencing raw pointers in constants is unstable - --> $DIR/write_to_mut_ref_dest.rs:11:18 - | -LL | unsafe { *b = 5; } - | ^^^^^^ - | - = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information - = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/write_to_static_via_mut_ref.rs b/src/test/ui/consts/write_to_static_via_mut_ref.rs deleted file mode 100644 index 665c305e9617f..0000000000000 --- a/src/test/ui/consts/write_to_static_via_mut_ref.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(const_mut_refs)] -#![allow(const_err)] - -static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable references are not allowed -fn main() { - assert_eq!(*OH_NO, 42); - *OH_NO = 43; //~ ERROR cannot assign to `*OH_NO`, as `OH_NO` is an immutable static -} diff --git a/src/test/ui/consts/write_to_static_via_mut_ref.stderr b/src/test/ui/consts/write_to_static_via_mut_ref.stderr deleted file mode 100644 index d19e998d61736..0000000000000 --- a/src/test/ui/consts/write_to_static_via_mut_ref.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/write_to_static_via_mut_ref.rs:4:26 - | -LL | static OH_NO: &mut i32 = &mut 42; - | ^^^^^^^ - -error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item - --> $DIR/write_to_static_via_mut_ref.rs:7:5 - | -LL | *OH_NO = 43; - | ^^^^^^^^^^^ cannot assign - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0594, E0764. -For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index c211ad1a2f8f6..262f7bc72c739 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -2,13 +2,12 @@ static X: i32 = 1; const C: i32 = 2; static mut M: i32 = 3; -const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed +const CR: &'static mut i32 = &mut C; //~ ERROR E0764 //~| WARN taking a mutable -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764 //~| ERROR cannot borrow - //~| ERROR mutable references are not allowed -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 //~| WARN taking a mutable -static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not +static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 7d959b6d148ed..ea591587e6daa 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -13,26 +13,17 @@ note: `const` item defined here LL | const C: i32 = 2; | ^^^^^^^^^^^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable references are not allowed in constants --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0658]: mutation through a reference is not allowed in statics +error[E0764]: mutable references are not allowed in statics --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:7:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0017.rs:7:39 @@ -41,7 +32,7 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:11:38 + --> $DIR/E0017.rs:10:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -54,19 +45,19 @@ note: `const` item defined here LL | const C: i32 = 2; | ^^^^^^^^^^^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:11:38 +error[E0764]: mutable references are not allowed in statics + --> $DIR/E0017.rs:10:38 | LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:13:52 +error[E0764]: mutable references are not allowed in statics + --> $DIR/E0017.rs:12:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 5 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0596, E0658, E0764. +Some errors have detailed explanations: E0596, E0764. For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index 6049d95f0d277..bb0c4979b9ac9 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -1,13 +1,12 @@ static X: i32 = 1; const C: i32 = 2; -const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed +const CR: &'static mut i32 = &mut C; //~ ERROR E0764 //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow - //~| ERROR E0658 - //~| ERROR mutable references are not allowed + //~| ERROR E0764 -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 //~| WARN taking a mutable fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index 4886a156d2ea5..73e0b139cd056 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -13,26 +13,17 @@ note: `const` item defined here LL | const C: i32 = 2; | ^^^^^^^^^^^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of constants +error[E0764]: mutable references are not allowed in constants --> $DIR/E0388.rs:4:30 | LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0658]: mutation through a reference is not allowed in statics +error[E0764]: mutable references are not allowed in statics --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0388.rs:6:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0388.rs:6:39 @@ -41,7 +32,7 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0388.rs:10:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -54,13 +45,13 @@ note: `const` item defined here LL | const C: i32 = 2; | ^^^^^^^^^^^^^^^^^ -error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0388.rs:10:38 +error[E0764]: mutable references are not allowed in statics + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ + | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 5 previous errors; 2 warnings emitted +error: aborting due to 4 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0596, E0658, E0764. +Some errors have detailed explanations: E0596, E0764. For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/extern/extern-compare-with-return-type.rs b/src/test/ui/extern/extern-compare-with-return-type.rs index 42693d3a061c8..1ddfc77a4c43a 100644 --- a/src/test/ui/extern/extern-compare-with-return-type.rs +++ b/src/test/ui/extern/extern-compare-with-return-type.rs @@ -1,5 +1,4 @@ // run-pass - // Tests that we can compare various kinds of extern fn signatures. #![allow(non_camel_case_types)] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.rs b/src/test/ui/feature-gates/feature-gate-cfg-version.rs index e35784a68d101..c29ef99945e71 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-version.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.rs @@ -1,9 +1,3 @@ -#[cfg(version(42))] //~ ERROR: expected a version literal -//~^ ERROR `cfg(version)` is experimental and subject to change -fn foo() {} -#[cfg(version(1.20))] //~ ERROR: expected a version literal -//~^ ERROR `cfg(version)` is experimental and subject to change -fn foo() -> bool { true } #[cfg(version("1.44"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn foo() -> bool { true } @@ -17,32 +11,30 @@ fn bar() -> bool { false } #[cfg(version(false))] //~ ERROR: expected a version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("foo"))] //~ WARNING: unknown version literal format +#[cfg(version("foo"))] //~ ERROR: invalid version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("999"))] //~ WARNING: unknown version literal format +#[cfg(version("999"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("-1"))] //~ WARNING: unknown version literal format +#[cfg(version("-1"))] //~ ERROR: invalid version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("65536"))] //~ WARNING: unknown version literal format +#[cfg(version("65536"))] //~ ERROR: invalid version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("0"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { true } -#[cfg(version("1.0"))] +#[cfg(version("0"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { true } -#[cfg(version("1.65536.2"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("1.20.0-stable"))] //~ WARNING: unknown version literal format + +#[cfg(version("1.65536.2"))] //~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() {} +fn version_check_bug() {} fn main() { + // This should fail but due to a bug in version_check `1.65536.2` is interpreted as `1.2`. + // See https://github.com/SergioBenitez/version_check/issues/11 + version_check_bug(); assert!(foo()); assert!(bar()); assert!(cfg!(version("1.42"))); //~ ERROR `cfg(version)` is experimental and subject to change diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr index ae899d409ecf9..bdf160b5a0270 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr @@ -1,36 +1,6 @@ error[E0658]: `cfg(version)` is experimental and subject to change --> $DIR/feature-gate-cfg-version.rs:1:7 | -LL | #[cfg(version(42))] - | ^^^^^^^^^^^ - | - = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - -error: expected a version literal - --> $DIR/feature-gate-cfg-version.rs:1:15 - | -LL | #[cfg(version(42))] - | ^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:4:7 - | -LL | #[cfg(version(1.20))] - | ^^^^^^^^^^^^^ - | - = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - -error: expected a version literal - --> $DIR/feature-gate-cfg-version.rs:4:15 - | -LL | #[cfg(version(1.20))] - | ^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:7:7 - | LL | #[cfg(version("1.44"))] | ^^^^^^^^^^^^^^^ | @@ -38,7 +8,7 @@ LL | #[cfg(version("1.44"))] = help: add `#![feature(cfg_version)]` to the crate attributes to enable error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:10:11 + --> $DIR/feature-gate-cfg-version.rs:4:11 | LL | #[cfg(not(version("1.44")))] | ^^^^^^^^^^^^^^^ @@ -47,7 +17,7 @@ LL | #[cfg(not(version("1.44")))] = help: add `#![feature(cfg_version)]` to the crate attributes to enable error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:14:7 + --> $DIR/feature-gate-cfg-version.rs:8:7 | LL | #[cfg(version("1.43", "1.44", "1.45"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,13 +26,13 @@ LL | #[cfg(version("1.43", "1.44", "1.45"))] = help: add `#![feature(cfg_version)]` to the crate attributes to enable error: expected single version literal - --> $DIR/feature-gate-cfg-version.rs:14:7 + --> $DIR/feature-gate-cfg-version.rs:8:7 | LL | #[cfg(version("1.43", "1.44", "1.45"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:17:7 + --> $DIR/feature-gate-cfg-version.rs:11:7 | LL | #[cfg(version(false))] | ^^^^^^^^^^^^^^ @@ -71,13 +41,13 @@ LL | #[cfg(version(false))] = help: add `#![feature(cfg_version)]` to the crate attributes to enable error: expected a version literal - --> $DIR/feature-gate-cfg-version.rs:17:15 + --> $DIR/feature-gate-cfg-version.rs:11:15 | LL | #[cfg(version(false))] | ^^^^^ error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:20:7 + --> $DIR/feature-gate-cfg-version.rs:14:7 | LL | #[cfg(version("foo"))] | ^^^^^^^^^^^^^^ @@ -85,14 +55,14 @@ LL | #[cfg(version("foo"))] = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:20:15 +error: invalid version literal + --> $DIR/feature-gate-cfg-version.rs:14:15 | LL | #[cfg(version("foo"))] | ^^^^^ error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:23:7 + --> $DIR/feature-gate-cfg-version.rs:17:7 | LL | #[cfg(version("999"))] | ^^^^^^^^^^^^^^ @@ -100,14 +70,8 @@ LL | #[cfg(version("999"))] = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:23:15 - | -LL | #[cfg(version("999"))] - | ^^^^^ - error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:26:7 + --> $DIR/feature-gate-cfg-version.rs:20:7 | LL | #[cfg(version("-1"))] | ^^^^^^^^^^^^^ @@ -115,14 +79,14 @@ LL | #[cfg(version("-1"))] = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:26:15 +error: invalid version literal + --> $DIR/feature-gate-cfg-version.rs:20:15 | LL | #[cfg(version("-1"))] | ^^^^ error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:29:7 + --> $DIR/feature-gate-cfg-version.rs:23:7 | LL | #[cfg(version("65536"))] | ^^^^^^^^^^^^^^^^ @@ -130,14 +94,14 @@ LL | #[cfg(version("65536"))] = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:29:15 +error: invalid version literal + --> $DIR/feature-gate-cfg-version.rs:23:15 | LL | #[cfg(version("65536"))] | ^^^^^^^ error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:32:7 + --> $DIR/feature-gate-cfg-version.rs:26:7 | LL | #[cfg(version("0"))] | ^^^^^^^^^^^^ @@ -145,23 +109,8 @@ LL | #[cfg(version("0"))] = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:32:15 - | -LL | #[cfg(version("0"))] - | ^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:35:7 - | -LL | #[cfg(version("1.0"))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:38:7 + --> $DIR/feature-gate-cfg-version.rs:30:7 | LL | #[cfg(version("1.65536.2"))] | ^^^^^^^^^^^^^^^^^^^^ @@ -169,29 +118,8 @@ LL | #[cfg(version("1.65536.2"))] = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:38:15 - | -LL | #[cfg(version("1.65536.2"))] - | ^^^^^^^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:41:7 - | -LL | #[cfg(version("1.20.0-stable"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:41:15 - | -LL | #[cfg(version("1.20.0-stable"))] - | ^^^^^^^^^^^^^^^ - error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:48:18 + --> $DIR/feature-gate-cfg-version.rs:40:18 | LL | assert!(cfg!(version("1.42"))); | ^^^^^^^^^^^^^^^ @@ -199,6 +127,6 @@ LL | assert!(cfg!(version("1.42"))); = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -error: aborting due to 19 previous errors; 7 warnings emitted +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr index 8abc4ccc9a5fa..051253cadc652 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr @@ -2,9 +2,7 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` --> $DIR/trait-path-expected-token.rs:8:33 | LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {} - | - ^ expected one of 7 possible tokens - | | - | maybe try to close unmatched angle bracket + | ^ expected one of 7 possible tokens warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/trait-path-expected-token.rs:1:12 diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs index 5e50c6b35c960..de61cfa1cf718 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs @@ -17,7 +17,7 @@ mod error2 { } fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} - //~^ ERROR: expected one of + //~^ ERROR: only types can be used in associated type constraints } fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr index 27e1a750b2131..a9ba8adcaba3f 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr @@ -6,13 +6,11 @@ LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {} | | | while parsing a const generic argument starting here -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-expressions.rs:19:36 +error: only types can be used in associated type constraints + --> $DIR/trait-path-expressions.rs:19:30 | LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} - | - ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^^^^^ warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/trait-path-expressions.rs:1:12 diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr index f6038566e5b5e..8a5e2c29c3665 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr @@ -28,9 +28,7 @@ error: expected one of `>`, a const expression, lifetime, or type, found `=` --> $DIR/trait-path-missing-gen_arg.rs:17:30 | LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {} - | - ^ expected one of `>`, a const expression, lifetime, or type - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `>`, a const expression, lifetime, or type warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/trait-path-missing-gen_arg.rs:1:12 diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs index eba30e1438f04..0bf48b1f41810 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs @@ -7,7 +7,7 @@ const _: () = { } fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} - //~^ ERROR: expected one of + //~^ ERROR: paths with multiple segments cannot be used in associated type constraints }; const _: () = { @@ -18,7 +18,7 @@ const _: () = { trait Z {} impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} - //~^ ERROR: expected one of + //~^ ERROR: qualified paths cannot be used in associated type constraints }; const _: () = { @@ -29,7 +29,7 @@ const _: () = { trait Z {} impl<T : X<X::Y<'a> = &'a u32>> Z for T {} - //~^ ERROR: expected one of + //~^ ERROR: paths with multiple segments cannot be used in associated type constraints }; fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr index c82953aaed7dd..4e2b84d018239 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr @@ -1,26 +1,22 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=` - --> $DIR/trait-path-segments.rs:9:36 +error: paths with multiple segments cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:9:31 | LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} - | - ^ expected one of 8 possible tokens - | | - | maybe try to close unmatched angle bracket + | ^^^^ -error: expected one of `,`, `::`, `:`, or `>`, found `=` - --> $DIR/trait-path-segments.rs:20:35 +error: qualified paths cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:20:16 | LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} - | - ^ expected one of `,`, `::`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^^^^^^^^^-^^^^^^^^ + | | + | not allowed in associated type constraints -error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=` - --> $DIR/trait-path-segments.rs:31:25 +error: paths with multiple segments cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:31:16 | LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {} - | - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^^^^^^^^ warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/trait-path-segments.rs:1:12 diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.rs b/src/test/ui/generic-associated-types/parse/trait-path-types.rs index 522b3edc638ea..6cdb501ec65fb 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-types.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.rs @@ -7,17 +7,17 @@ trait X { const _: () = { fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} - //~^ ERROR: expected one of + //~^ ERROR: only path types can be used in associated type constraints }; const _: () = { fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} - //~^ ERROR: expected one of + //~^ ERROR: only path types can be used in associated type constraints }; const _: () = { fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} - //~^ ERROR: expected one of + //~^ ERROR: only types can be used in associated type constraints }; fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr index ac791c224810e..f5be084613b4c 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr @@ -1,26 +1,20 @@ -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-types.rs:9:37 +error: only path types can be used in associated type constraints + --> $DIR/trait-path-types.rs:9:29 | LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} - | - ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^^^^^^^ -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-types.rs:14:37 +error: only path types can be used in associated type constraints + --> $DIR/trait-path-types.rs:14:29 | LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} - | - ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^^^^^^^ -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-types.rs:19:33 +error: only types can be used in associated type constraints + --> $DIR/trait-path-types.rs:19:30 | LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} - | -- ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^^ warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/trait-path-types.rs:1:12 diff --git a/src/test/ui/generic-associated-types/variance_constraints.rs b/src/test/ui/generic-associated-types/variance_constraints.rs deleted file mode 100644 index 36db80706b499..0000000000000 --- a/src/test/ui/generic-associated-types/variance_constraints.rs +++ /dev/null @@ -1,24 +0,0 @@ -// check-pass -// issue #69184 -#![feature(generic_associated_types)] -#![allow(incomplete_features)] - -trait A { - type B<'a>; - - fn make_b<'a>(&'a self) -> Self::B<'a>; -} - -struct S {} -impl A for S { - type B<'a> = &'a S; - fn make_b<'a>(&'a self) -> &'a Self { - self - } -} - -enum E<'a> { - S(<S as A>::B<'a>), -} - -fn main() {} diff --git a/src/test/ui/hygiene/no_implicit_prelude-2021.rs b/src/test/ui/hygiene/no_implicit_prelude-2021.rs deleted file mode 100644 index 0fe9ae56c6564..0000000000000 --- a/src/test/ui/hygiene/no_implicit_prelude-2021.rs +++ /dev/null @@ -1,9 +0,0 @@ -// check-pass -// edition:2021 - -#![no_implicit_prelude] - -fn main() { - assert!(true, "hoi"); - assert!(false, "hoi {}", 123); -} diff --git a/src/test/ui/issues/issue-1962.fixed b/src/test/ui/issues/issue-1962.fixed index 897fd172b29f3..b810a90ef37f9 100644 --- a/src/test/ui/issues/issue-1962.fixed +++ b/src/test/ui/issues/issue-1962.fixed @@ -3,8 +3,8 @@ fn main() { let mut i = 0; - 'a: loop { //~ ERROR denote infinite loops with `loop + loop { //~ ERROR denote infinite loops with `loop i += 1; - if i == 5 { break 'a; } + if i == 5 { break; } } } diff --git a/src/test/ui/issues/issue-1962.rs b/src/test/ui/issues/issue-1962.rs index 71e874100874f..00d2bbd28506e 100644 --- a/src/test/ui/issues/issue-1962.rs +++ b/src/test/ui/issues/issue-1962.rs @@ -3,8 +3,8 @@ fn main() { let mut i = 0; - 'a: while true { //~ ERROR denote infinite loops with `loop + while true { //~ ERROR denote infinite loops with `loop i += 1; - if i == 5 { break 'a; } + if i == 5 { break; } } } diff --git a/src/test/ui/issues/issue-1962.stderr b/src/test/ui/issues/issue-1962.stderr index 4c32a4cf3dd59..17142912696a7 100644 --- a/src/test/ui/issues/issue-1962.stderr +++ b/src/test/ui/issues/issue-1962.stderr @@ -1,8 +1,8 @@ error: denote infinite loops with `loop { ... }` --> $DIR/issue-1962.rs:6:5 | -LL | 'a: while true { - | ^^^^^^^^^^^^^^ help: use `loop` +LL | while true { + | ^^^^^^^^^^ help: use `loop` | = note: requested on the command line with `-D while-true` diff --git a/src/test/ui/issues/issue-27042.stderr b/src/test/ui/issues/issue-27042.stderr index 59ef28481d0e6..7dee1a6a5f044 100644 --- a/src/test/ui/issues/issue-27042.stderr +++ b/src/test/ui/issues/issue-27042.stderr @@ -4,7 +4,7 @@ warning: denote infinite loops with `loop { ... }` LL | / 'b: LL | | LL | | while true { break }; // but here we cite the whole loop - | |__________________^ help: use `loop` + | |____________________________^ help: use `loop` | = note: `#[warn(while_true)]` on by default diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 51486bc40de0c..b45c00f694321 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -1,8 +1,6 @@ fn main () { let sr: Vec<(u32, _, _) = vec![]; - //~^ ERROR expected one of - + //~^ ERROR only path types can be used in associated type constraints let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built - } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index acb44ce2c3545..a9b9bf06d7f42 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -1,14 +1,13 @@ -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/issue-34334.rs:2:29 +error: only path types can be used in associated type constraints + --> $DIR/issue-34334.rs:2:17 | LL | let sr: Vec<(u32, _, _) = vec![]; - | -- - ^ expected one of `,`, `:`, or `>` - | | | - | | maybe try to close unmatched angle bracket + | -- ^^^^^^^^^^^ + | | | while parsing the type for `sr` error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()` - --> $DIR/issue-34334.rs:5:87 + --> $DIR/issue-34334.rs:4:87 | LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); | ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>` diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs index 6ec6e7bdcb81e..273187a5a13be 100644 --- a/src/test/ui/issues/issue-46604.rs +++ b/src/test/ui/issues/issue-46604.rs @@ -1,4 +1,4 @@ -static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable references are not allowed +static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0764 fn write<T: AsRef<[u8]>>(buffer: T) { } fn main() { diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr index 7faa2d79ba483..5421721dec2e3 100644 --- a/src/test/ui/issues/issue-46604.stderr +++ b/src/test/ui/issues/issue-46604.stderr @@ -1,8 +1,8 @@ -error[E0764]: mutable references are not allowed in the final value of statics +error[E0764]: mutable references are not allowed in statics --> $DIR/issue-46604.rs:1:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:6:5 diff --git a/src/test/ui/label/label_misspelled.rs b/src/test/ui/label/label_misspelled.rs index e3180b06ecb2b..ebfd5642c9fa8 100644 --- a/src/test/ui/label/label_misspelled.rs +++ b/src/test/ui/label/label_misspelled.rs @@ -1,62 +1,18 @@ -#![warn(unused_labels)] - fn main() { - 'while_loop: while true { //~ WARN denote infinite loops with - //~^ WARN unused label - while_loop; - //~^ ERROR cannot find value `while_loop` in this scope - }; - 'while_let: while let Some(_) = Some(()) { - //~^ WARN unused label - while_let; - //~^ ERROR cannot find value `while_let` in this scope - } - 'for_loop: for _ in 0..3 { - //~^ WARN unused label - for_loop; - //~^ ERROR cannot find value `for_loop` in this scope - }; 'LOOP: loop { - //~^ WARN unused label LOOP; //~^ ERROR cannot find value `LOOP` in this scope }; -} - -fn foo() { - 'LOOP: loop { - break LOOP; - //~^ ERROR cannot find value `LOOP` in this scope - }; 'while_loop: while true { //~ WARN denote infinite loops with - break while_loop; + while_loop; //~^ ERROR cannot find value `while_loop` in this scope }; 'while_let: while let Some(_) = Some(()) { - break while_let; + while_let; //~^ ERROR cannot find value `while_let` in this scope } 'for_loop: for _ in 0..3 { - break for_loop; + for_loop; //~^ ERROR cannot find value `for_loop` in this scope }; } - -fn bar() { - let foo = (); - 'while_loop: while true { //~ WARN denote infinite loops with - //~^ WARN unused label - break foo; - //~^ ERROR `break` with value from a `while` loop - }; - 'while_let: while let Some(_) = Some(()) { - //~^ WARN unused label - break foo; - //~^ ERROR `break` with value from a `while` loop - } - 'for_loop: for _ in 0..3 { - //~^ WARN unused label - break foo; - //~^ ERROR `break` with value from a `for` loop - }; -} diff --git a/src/test/ui/label/label_misspelled.stderr b/src/test/ui/label/label_misspelled.stderr index b09695787a443..1368ca4126cdd 100644 --- a/src/test/ui/label/label_misspelled.stderr +++ b/src/test/ui/label/label_misspelled.stderr @@ -1,206 +1,47 @@ -error[E0425]: cannot find value `while_loop` in this scope - --> $DIR/label_misspelled.rs:6:9 - | -LL | 'while_loop: while true { - | ----------- a label with a similar name exists -LL | -LL | while_loop; - | ^^^^^^^^^^ not found in this scope - -error[E0425]: cannot find value `while_let` in this scope - --> $DIR/label_misspelled.rs:11:9 - | -LL | 'while_let: while let Some(_) = Some(()) { - | ---------- a label with a similar name exists -LL | -LL | while_let; - | ^^^^^^^^^ not found in this scope - -error[E0425]: cannot find value `for_loop` in this scope - --> $DIR/label_misspelled.rs:16:9 - | -LL | 'for_loop: for _ in 0..3 { - | --------- a label with a similar name exists -LL | -LL | for_loop; - | ^^^^^^^^ not found in this scope - error[E0425]: cannot find value `LOOP` in this scope - --> $DIR/label_misspelled.rs:21:9 + --> $DIR/label_misspelled.rs:3:9 | -LL | 'LOOP: loop { - | ----- a label with a similar name exists -LL | LL | LOOP; - | ^^^^ not found in this scope - -error[E0425]: cannot find value `LOOP` in this scope - --> $DIR/label_misspelled.rs:28:15 - | -LL | 'LOOP: loop { - | ----- a label with a similar name exists -LL | break LOOP; - | ^^^^ - | | - | not found in this scope - | help: use the similarly named label: `'LOOP` + | ^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'LOOP` error[E0425]: cannot find value `while_loop` in this scope - --> $DIR/label_misspelled.rs:32:15 + --> $DIR/label_misspelled.rs:7:9 | -LL | 'while_loop: while true { - | ----------- a label with a similar name exists -LL | break while_loop; - | ^^^^^^^^^^ - | | - | not found in this scope - | help: use the similarly named label: `'while_loop` +LL | while_loop; + | ^^^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'while_loop` error[E0425]: cannot find value `while_let` in this scope - --> $DIR/label_misspelled.rs:36:15 + --> $DIR/label_misspelled.rs:11:9 | -LL | 'while_let: while let Some(_) = Some(()) { - | ---------- a label with a similar name exists -LL | break while_let; - | ^^^^^^^^^ - | | - | not found in this scope - | help: use the similarly named label: `'while_let` +LL | while_let; + | ^^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'while_let` error[E0425]: cannot find value `for_loop` in this scope - --> $DIR/label_misspelled.rs:40:15 - | -LL | 'for_loop: for _ in 0..3 { - | --------- a label with a similar name exists -LL | break for_loop; - | ^^^^^^^^ - | | - | not found in this scope - | help: use the similarly named label: `'for_loop` - -warning: unused label - --> $DIR/label_misspelled.rs:4:5 - | -LL | 'while_loop: while true { - | ^^^^^^^^^^^ + --> $DIR/label_misspelled.rs:15:9 | -note: the lint level is defined here - --> $DIR/label_misspelled.rs:1:9 - | -LL | #![warn(unused_labels)] - | ^^^^^^^^^^^^^ +LL | for_loop; + | ^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'for_loop` warning: denote infinite loops with `loop { ... }` - --> $DIR/label_misspelled.rs:4:5 + --> $DIR/label_misspelled.rs:6:5 | LL | 'while_loop: while true { | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` | = note: `#[warn(while_true)]` on by default -warning: unused label - --> $DIR/label_misspelled.rs:9:5 - | -LL | 'while_let: while let Some(_) = Some(()) { - | ^^^^^^^^^^ - -warning: unused label - --> $DIR/label_misspelled.rs:14:5 - | -LL | 'for_loop: for _ in 0..3 { - | ^^^^^^^^^ - -warning: unused label - --> $DIR/label_misspelled.rs:19:5 - | -LL | 'LOOP: loop { - | ^^^^^ - -warning: denote infinite loops with `loop { ... }` - --> $DIR/label_misspelled.rs:31:5 - | -LL | 'while_loop: while true { - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` - -warning: unused label - --> $DIR/label_misspelled.rs:47:5 - | -LL | 'while_loop: while true { - | ^^^^^^^^^^^ - -warning: denote infinite loops with `loop { ... }` - --> $DIR/label_misspelled.rs:47:5 - | -LL | 'while_loop: while true { - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` - -warning: unused label - --> $DIR/label_misspelled.rs:52:5 - | -LL | 'while_let: while let Some(_) = Some(()) { - | ^^^^^^^^^^ - -warning: unused label - --> $DIR/label_misspelled.rs:57:5 - | -LL | 'for_loop: for _ in 0..3 { - | ^^^^^^^^^ - -error[E0571]: `break` with value from a `while` loop - --> $DIR/label_misspelled.rs:49:9 - | -LL | 'while_loop: while true { - | ----------------------- you can't `break` with a value in a `while` loop -LL | -LL | break foo; - | ^^^^^^^^^ can only break with a value inside `loop` or breakable block - | -help: use `break` on its own without a value inside this `while` loop - | -LL | break; - | ^^^^^ -help: alternatively, you might have meant to use the available loop label - | -LL | break 'while_loop; - | ^^^^^^^^^^^ - -error[E0571]: `break` with value from a `while` loop - --> $DIR/label_misspelled.rs:54:9 - | -LL | 'while_let: while let Some(_) = Some(()) { - | ---------------------------------------- you can't `break` with a value in a `while` loop -LL | -LL | break foo; - | ^^^^^^^^^ can only break with a value inside `loop` or breakable block - | -help: use `break` on its own without a value inside this `while` loop - | -LL | break; - | ^^^^^ -help: alternatively, you might have meant to use the available loop label - | -LL | break 'while_let; - | ^^^^^^^^^^ - -error[E0571]: `break` with value from a `for` loop - --> $DIR/label_misspelled.rs:59:9 - | -LL | 'for_loop: for _ in 0..3 { - | ------------------------ you can't `break` with a value in a `for` loop -LL | -LL | break foo; - | ^^^^^^^^^ can only break with a value inside `loop` or breakable block - | -help: use `break` on its own without a value inside this `for` loop - | -LL | break; - | ^^^^^ -help: alternatively, you might have meant to use the available loop label - | -LL | break 'for_loop; - | ^^^^^^^^^ - -error: aborting due to 11 previous errors; 10 warnings emitted +error: aborting due to 4 previous errors; 1 warning emitted -Some errors have detailed explanations: E0425, E0571. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/label/label_misspelled_2.rs b/src/test/ui/label/label_misspelled_2.rs deleted file mode 100644 index 55bbe6b30a593..0000000000000 --- a/src/test/ui/label/label_misspelled_2.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![warn(unused_labels)] - -fn main() { - 'a: for _ in 0..1 { - break 'a; - } - 'b: for _ in 0..1 { - break b; //~ ERROR cannot find value `b` in this scope - } - c: for _ in 0..1 { //~ ERROR malformed loop label - break 'c; - } - d: for _ in 0..1 { //~ ERROR malformed loop label - break d; //~ ERROR cannot find value `d` in this scope - } -} diff --git a/src/test/ui/label/label_misspelled_2.stderr b/src/test/ui/label/label_misspelled_2.stderr deleted file mode 100644 index 960646d9894d1..0000000000000 --- a/src/test/ui/label/label_misspelled_2.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: malformed loop label - --> $DIR/label_misspelled_2.rs:10:5 - | -LL | c: for _ in 0..1 { - | ^ help: use the correct loop label format: `'c` - -error: malformed loop label - --> $DIR/label_misspelled_2.rs:13:5 - | -LL | d: for _ in 0..1 { - | ^ help: use the correct loop label format: `'d` - -error[E0425]: cannot find value `b` in this scope - --> $DIR/label_misspelled_2.rs:8:15 - | -LL | 'b: for _ in 0..1 { - | -- a label with a similar name exists -LL | break b; - | ^ - | | - | not found in this scope - | help: use the similarly named label: `'b` - -error[E0425]: cannot find value `d` in this scope - --> $DIR/label_misspelled_2.rs:14:15 - | -LL | d: for _ in 0..1 { - | - a label with a similar name exists -LL | break d; - | ^ - | | - | not found in this scope - | help: use the similarly named label: `'d` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/lint/dead-code/const-and-self.rs b/src/test/ui/lint/dead-code/const-and-self.rs index 0bcdd6edf0d66..1a7b3f43cda14 100644 --- a/src/test/ui/lint/dead-code/const-and-self.rs +++ b/src/test/ui/lint/dead-code/const-and-self.rs @@ -1,6 +1,6 @@ // check-pass -#![warn(dead_code)] +#![deny(dead_code)] const TLC: usize = 4; @@ -28,27 +28,8 @@ impl Foo<Y> for X { } } -enum E { - A, - B, //~ WARN variant is never constructed: `B` - C, //~ WARN variant is never constructed: `C` -} - -type F = E; - -impl E { - fn check(&self) -> bool { - match self { - Self::A => true, - Self::B => false, - F::C => false, - } - } -} - fn main() { let s = [0,1,2,3]; s.doit(); X::foo(); - E::A.check(); } diff --git a/src/test/ui/lint/dead-code/const-and-self.stderr b/src/test/ui/lint/dead-code/const-and-self.stderr deleted file mode 100644 index c0e406189e8ab..0000000000000 --- a/src/test/ui/lint/dead-code/const-and-self.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: variant is never constructed: `B` - --> $DIR/const-and-self.rs:33:5 - | -LL | B, - | ^ - | -note: the lint level is defined here - --> $DIR/const-and-self.rs:3:9 - | -LL | #![warn(dead_code)] - | ^^^^^^^^^ - -warning: variant is never constructed: `C` - --> $DIR/const-and-self.rs:34:5 - | -LL | C, - | ^ - -warning: 2 warnings emitted - diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index 540e076c7e4c6..3973af540c81f 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -109,8 +109,14 @@ LL | VEC.push(0); note: mutable reference created due to call to this method --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | -LL | pub fn push(&mut self, value: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / pub fn push(&mut self, value: T) { +LL | | // This will panic or abort if we would allocate > isize::MAX bytes +LL | | // or if the length increment would overflow for zero-sized types. +LL | | if self.len == self.buf.capacity() { +... | +LL | | } +LL | | } + | |_____^ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:31:1 | diff --git a/src/test/ui/lint/lint-removed-cmdline.stderr b/src/test/ui/lint/lint-removed-cmdline.stderr index fc2ba92479cc6..1c45c38774e5a 100644 --- a/src/test/ui/lint/lint-removed-cmdline.stderr +++ b/src/test/ui/lint/lint-removed-cmdline.stderr @@ -1,16 +1,16 @@ -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok` | = note: requested on the command line with `-D raw_pointer_derive` -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok` | = note: requested on the command line with `-D raw_pointer_derive` -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok` | = note: requested on the command line with `-D raw_pointer_derive` -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok` | = note: requested on the command line with `-D raw_pointer_derive` diff --git a/src/test/ui/lint/lint-removed.stderr b/src/test/ui/lint/lint-removed.stderr index dc0515b84820b..44480d84203bd 100644 --- a/src/test/ui/lint/lint-removed.stderr +++ b/src/test/ui/lint/lint-removed.stderr @@ -1,4 +1,4 @@ -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok` --> $DIR/lint-removed.rs:6:8 | LL | #[deny(raw_pointer_derive)] diff --git a/src/test/ui/lint/lint-unexported-no-mangle.stderr b/src/test/ui/lint/lint-unexported-no-mangle.stderr index 66d64e8937a2b..48d9b38a99b65 100644 --- a/src/test/ui/lint/lint-unexported-no-mangle.stderr +++ b/src/test/ui/lint/lint-unexported-no-mangle.stderr @@ -1,32 +1,32 @@ -warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported +warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported` | = note: requested on the command line with `-F private_no_mangle_fns` -warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported +warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported` | = note: requested on the command line with `-F private_no_mangle_statics` -warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported +warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported` | = note: requested on the command line with `-F private_no_mangle_fns` -warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported +warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported` | = note: requested on the command line with `-F private_no_mangle_statics` -warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported +warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported` | = note: requested on the command line with `-F private_no_mangle_fns` -warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported +warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported` | = note: requested on the command line with `-F private_no_mangle_statics` -warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported +warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported` | = note: requested on the command line with `-F private_no_mangle_fns` -warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported +warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported` | = note: requested on the command line with `-F private_no_mangle_statics` diff --git a/src/test/ui/loops/loop-break-value-no-repeat.stderr b/src/test/ui/loops/loop-break-value-no-repeat.stderr index 1c0d39a6e5ad7..ff93e9220e986 100644 --- a/src/test/ui/loops/loop-break-value-no-repeat.stderr +++ b/src/test/ui/loops/loop-break-value-no-repeat.stderr @@ -1,12 +1,10 @@ error[E0571]: `break` with value from a `for` loop --> $DIR/loop-break-value-no-repeat.rs:12:9 | -LL | for _ in &[1,2,3] { - | ----------------- you can't `break` with a value in a `for` loop LL | break 22 | ^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `for` loop +help: instead, use `break` on its own without a value inside this `for` loop | LL | break | ^^^^^ diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs index 51c9a36a03956..8a080cfdf494a 100644 --- a/src/test/ui/loops/loop-break-value.rs +++ b/src/test/ui/loops/loop-break-value.rs @@ -94,5 +94,6 @@ fn main() { 'LOOP: for _ in 0 .. 9 { break LOOP; //~^ ERROR cannot find value `LOOP` in this scope + //~| ERROR `break` with value from a `for` loop } } diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index adb099f9b1769..0237435c8b46a 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -1,13 +1,11 @@ error[E0425]: cannot find value `LOOP` in this scope --> $DIR/loop-break-value.rs:95:15 | -LL | 'LOOP: for _ in 0 .. 9 { - | ----- a label with a similar name exists LL | break LOOP; | ^^^^ | | | not found in this scope - | help: use the similarly named label: `'LOOP` + | help: a label with a similar name exists: `'LOOP` warning: denote infinite loops with `loop { ... }` --> $DIR/loop-break-value.rs:26:5 @@ -20,44 +18,32 @@ LL | 'while_loop: while true { error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:28:9 | -LL | 'while_loop: while true { - | ----------------------- you can't `break` with a value in a `while` loop -LL | break; LL | break (); | ^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `while` loop +help: instead, use `break` on its own without a value inside this `while` loop | LL | break; | ^^^^^ -help: alternatively, you might have meant to use the available loop label - | -LL | break 'while_loop; - | ^^^^^^^^^^^ error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:30:13 | -LL | 'while_loop: while true { - | ----------------------- you can't `break` with a value in a `while` loop -... LL | break 'while_loop 123; | ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `while` loop +help: instead, use `break` on its own without a value inside this `while` loop | -LL | break 'while_loop; - | ^^^^^^^^^^^^^^^^^ +LL | break; + | ^^^^^ error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:38:12 | -LL | while let Some(_) = Some(()) { - | ---------------------------- you can't `break` with a value in a `while` loop LL | if break () { | ^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `while` loop +help: instead, use `break` on its own without a value inside this `while` loop | LL | if break { | ^^^^^ @@ -65,12 +51,10 @@ LL | if break { error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:43:9 | -LL | while let Some(_) = Some(()) { - | ---------------------------- you can't `break` with a value in a `while` loop LL | break None; | ^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `while` loop +help: instead, use `break` on its own without a value inside this `while` loop | LL | break; | ^^^^^ @@ -78,26 +62,21 @@ LL | break; error[E0571]: `break` with value from a `while` loop --> $DIR/loop-break-value.rs:49:13 | -LL | 'while_let_loop: while let Some(_) = Some(()) { - | --------------------------------------------- you can't `break` with a value in a `while` loop -LL | loop { LL | break 'while_let_loop "nope"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `while` loop +help: instead, use `break` on its own without a value inside this `while` loop | -LL | break 'while_let_loop; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | break; + | ^^^^^ error[E0571]: `break` with value from a `for` loop --> $DIR/loop-break-value.rs:56:9 | -LL | for _ in &[1,2,3] { - | ----------------- you can't `break` with a value in a `for` loop LL | break (); | ^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `for` loop +help: instead, use `break` on its own without a value inside this `for` loop | LL | break; | ^^^^^ @@ -105,13 +84,10 @@ LL | break; error[E0571]: `break` with value from a `for` loop --> $DIR/loop-break-value.rs:57:9 | -LL | for _ in &[1,2,3] { - | ----------------- you can't `break` with a value in a `for` loop -LL | break (); LL | break [()]; | ^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `for` loop +help: instead, use `break` on its own without a value inside this `for` loop | LL | break; | ^^^^^ @@ -119,16 +95,24 @@ LL | break; error[E0571]: `break` with value from a `for` loop --> $DIR/loop-break-value.rs:64:13 | -LL | 'for_loop: for _ in &[1,2,3] { - | ---------------------------- you can't `break` with a value in a `for` loop -... LL | break 'for_loop Some(17); | ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -help: use `break` on its own without a value inside this `for` loop +help: instead, use `break` on its own without a value inside this `for` loop + | +LL | break; + | ^^^^^ + +error[E0571]: `break` with value from a `for` loop + --> $DIR/loop-break-value.rs:95:9 + | +LL | break LOOP; + | ^^^^^^^^^^ can only break with a value inside `loop` or breakable block | -LL | break 'for_loop; - | ^^^^^^^^^^^^^^^ +help: instead, use `break` on its own without a value inside this `for` loop + | +LL | break; + | ^^^^^ error[E0308]: mismatched types --> $DIR/loop-break-value.rs:4:31 @@ -187,7 +171,7 @@ LL | break; | expected integer, found `()` | help: give it a value of the expected type: `break value` -error: aborting due to 17 previous errors; 1 warning emitted +error: aborting due to 18 previous errors; 1 warning emitted Some errors have detailed explanations: E0308, E0425, E0571. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mir/issue-80742.rs b/src/test/ui/mir/issue-80742.rs deleted file mode 100644 index c06d182fd567d..0000000000000 --- a/src/test/ui/mir/issue-80742.rs +++ /dev/null @@ -1,33 +0,0 @@ -// check-fail - -// This test used to cause an ICE in rustc_mir::interpret::step::eval_rvalue_into_place - -#![allow(incomplete_features)] -#![feature(const_evaluatable_checked)] -#![feature(const_generics)] - -use std::fmt::Debug; -use std::marker::PhantomData; -use std::mem::size_of; - -struct Inline<T> -where - [u8; size_of::<T>() + 1]: , -{ - _phantom: PhantomData<T>, - buf: [u8; size_of::<T>() + 1], -} - -impl<T> Inline<T> -where - [u8; size_of::<T>() + 1]: , -{ - pub fn new(val: T) -> Inline<T> { - todo!() - } -} - -fn main() { - let dst = Inline::<dyn Debug>::new(0); //~ ERROR - //~^ ERROR -} diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr deleted file mode 100644 index 26f9c786ba13b..0000000000000 --- a/src/test/ui/mir/issue-80742.stderr +++ /dev/null @@ -1,70 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | -LL | intrinsics::size_of::<T>() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | size_of called on unsized type `dyn Debug` - | inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL - | - ::: $DIR/issue-80742.rs:23:10 - | -LL | [u8; size_of::<T>() + 1]: , - | -------------- inside `Inline::<dyn Debug>::{constant#0}` at $DIR/issue-80742.rs:23:10 - -error[E0599]: no function or associated item named `new` found for struct `Inline<dyn Debug>` in the current scope - --> $DIR/issue-80742.rs:31:36 - | -LL | / struct Inline<T> -LL | | where -LL | | [u8; size_of::<T>() + 1]: , -LL | | { -LL | | _phantom: PhantomData<T>, -LL | | buf: [u8; size_of::<T>() + 1], -LL | | } - | |_- function or associated item `new` not found for this -... -LL | let dst = Inline::<dyn Debug>::new(0); - | ^^^ function or associated item not found in `Inline<dyn Debug>` - | - ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL - | -LL | pub trait Debug { - | --------------- doesn't satisfy `dyn Debug: Sized` - | - = note: the method `new` exists but the following trait bounds were not satisfied: - `dyn Debug: Sized` - -error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | -LL | intrinsics::size_of::<T>() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | size_of called on unsized type `dyn Debug` - | inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL - | - ::: $DIR/issue-80742.rs:15:10 - | -LL | [u8; size_of::<T>() + 1]: , - | -------------- inside `Inline::<dyn Debug>::{constant#0}` at $DIR/issue-80742.rs:15:10 - -error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time - --> $DIR/issue-80742.rs:31:15 - | -LL | struct Inline<T> - | - required by this bound in `Inline` -... -LL | let dst = Inline::<dyn Debug>::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `dyn Debug` -help: consider relaxing the implicit `Sized` restriction - | -LL | struct Inline<T: ?Sized> - | ^^^^^^^^ - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0080, E0277, E0599. -For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr index 1683841e9d781..051896cb89c8f 100644 --- a/src/test/ui/never_type/issue-52443.stderr +++ b/src/test/ui/never_type/issue-52443.stderr @@ -39,14 +39,11 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ -error[E0658]: mutable references are not allowed in constants +error[E0764]: mutable references are not allowed in constants --> $DIR/issue-52443.rs:9:21 | LL | [(); { for _ in 0usize.. {}; 0}]; - | ^^^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^ `&mut` is only allowed in `const fn` error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants --> $DIR/issue-52443.rs:9:21 @@ -56,5 +53,5 @@ LL | [(); { for _ in 0usize.. {}; 0}]; error: aborting due to 6 previous errors; 1 warning emitted -Some errors have detailed explanations: E0015, E0308, E0658, E0744. +Some errors have detailed explanations: E0015, E0308, E0744, E0764. For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs deleted file mode 100644 index da95c1bfa2709..0000000000000 --- a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs +++ /dev/null @@ -1,23 +0,0 @@ -struct Foo<T1, T2> { - _a : T1, - _b : T2, -} - -fn test1<T>(arg : T) { - let v : Vec<(u32,_) = vec![]; - //~^ ERROR: expected one of - //~| ERROR: type annotations needed -} - -fn test2<T1, T2>(arg1 : T1, arg2 : T2) { - let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2}; - //~^ ERROR: expected one of -} - -fn test3<'a>(arg : &'a u32) { - let v : Vec<'a = vec![]; - //~^ ERROR: expected one of - //~| ERROR: type annotations needed for `Vec<T>` -} - -fn main() {} diff --git a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr deleted file mode 100644 index ae53334f5e02a..0000000000000 --- a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:23 - | -LL | let v : Vec<(u32,_) = vec![]; - | - - ^ expected one of `,`, `:`, or `>` - | | | - | | maybe try to close unmatched angle bracket - | while parsing the type for `v` - -error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `{` - --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:13:32 - | -LL | let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2}; - | --- ^ expected one of 7 possible tokens - | | - | while parsing the type for `foo` - -error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:18 - | -LL | let v : Vec<'a = vec![]; - | - -- ^ expected one of `,`, `:`, or `>` - | | | - | | maybe try to close unmatched angle bracket - | while parsing the type for `v` - -error[E0282]: type annotations needed for `Vec<T>` - --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25 - | -LL | let v : Vec<(u32,_) = vec![]; - | - ^^^^^^ cannot infer type for type parameter `T` - | | - | consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0282]: type annotations needed for `Vec<T>` - --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:20 - | -LL | let v : Vec<'a = vec![]; - | - ^^^^^^ cannot infer type for type parameter `T` - | | - | consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/parser/nested-missing-closing-angle-bracket.rs b/src/test/ui/parser/nested-missing-closing-angle-bracket.rs deleted file mode 100644 index 84ffdd176aea0..0000000000000 --- a/src/test/ui/parser/nested-missing-closing-angle-bracket.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let v : Vec::<Vec<(u32,_,_)> = vec![vec![]]; - //~^ ERROR: expected one of -} diff --git a/src/test/ui/parser/nested-missing-closing-angle-bracket.stderr b/src/test/ui/parser/nested-missing-closing-angle-bracket.stderr deleted file mode 100644 index b85bc02568c77..0000000000000 --- a/src/test/ui/parser/nested-missing-closing-angle-bracket.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `,` or `>`, found `;` - --> $DIR/nested-missing-closing-angle-bracket.rs:2:46 - | -LL | let v : Vec::<Vec<(u32,_,_)> = vec![vec![]]; - | - while parsing the type for `v` ^ expected one of `,` or `>` - -error: aborting due to previous error - diff --git a/src/test/ui/proc-macro/issue-81007-item-attrs.rs b/src/test/ui/proc-macro/issue-81007-item-attrs.rs deleted file mode 100644 index ea27d54ee4148..0000000000000 --- a/src/test/ui/proc-macro/issue-81007-item-attrs.rs +++ /dev/null @@ -1,31 +0,0 @@ -// check-pass -// edition:2018 -// compile-flags: -Z span-debug -// aux-build:test-macros.rs - -#![feature(rustc_attrs)] - -#![no_std] // Don't load unnecessary hygiene information from std -extern crate std; - -#[macro_use] extern crate test_macros; - -macro_rules! capture_item { - ($item:item) => { - #[print_attr] - $item - } -} - -capture_item! { - /// A doc comment - struct Foo {} -} - -capture_item! { - #[rustc_dummy] - /// Another comment comment - struct Bar {} -} - -fn main() {} diff --git a/src/test/ui/proc-macro/issue-81007-item-attrs.stdout b/src/test/ui/proc-macro/issue-81007-item-attrs.stdout deleted file mode 100644 index 6f880a1202170..0000000000000 --- a/src/test/ui/proc-macro/issue-81007-item-attrs.stdout +++ /dev/null @@ -1,99 +0,0 @@ -PRINT-ATTR INPUT (DISPLAY): #[doc = r" A doc comment"] struct Foo { } -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Punct { - ch: '#', - spacing: Alone, - span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "doc", - span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0), - }, - Punct { - ch: '=', - spacing: Alone, - span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0), - }, - Literal { - kind: StrRaw(0), - symbol: " A doc comment", - suffix: None, - span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0), - }, - ], - span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0), - }, - Ident { - ident: "struct", - span: $DIR/issue-81007-item-attrs.rs:22:5: 22:11 (#0), - }, - Ident { - ident: "Foo", - span: $DIR/issue-81007-item-attrs.rs:22:12: 22:15 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [], - span: $DIR/issue-81007-item-attrs.rs:22:16: 22:18 (#0), - }, -] -PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[doc = r" Another comment comment"] struct Bar { } -PRINT-ATTR INPUT (DEBUG): TokenStream [ - Punct { - ch: '#', - spacing: Alone, - span: $DIR/issue-81007-item-attrs.rs:26:5: 26:6 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "rustc_dummy", - span: $DIR/issue-81007-item-attrs.rs:26:7: 26:18 (#0), - }, - ], - span: $DIR/issue-81007-item-attrs.rs:26:6: 26:19 (#0), - }, - Punct { - ch: '#', - spacing: Alone, - span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "doc", - span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0), - }, - Punct { - ch: '=', - spacing: Alone, - span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0), - }, - Literal { - kind: StrRaw(0), - symbol: " Another comment comment", - suffix: None, - span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0), - }, - ], - span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0), - }, - Ident { - ident: "struct", - span: $DIR/issue-81007-item-attrs.rs:28:5: 28:11 (#0), - }, - Ident { - ident: "Bar", - span: $DIR/issue-81007-item-attrs.rs:28:12: 28:15 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [], - span: $DIR/issue-81007-item-attrs.rs:28:16: 28:18 (#0), - }, -] diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs index b7178c2b52bfb..65e0d79308ca3 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.rs +++ b/src/test/ui/unsafe/ranged_ints2_const.rs @@ -18,9 +18,3 @@ const fn bar() -> NonZero<u32> { let y = unsafe { &mut x.0 }; //~ ERROR mutable references unsafe { NonZero(1) } } - -const fn boo() -> NonZero<u32> { - let mut x = unsafe { NonZero(1) }; - unsafe { let y = &mut x.0; } //~ ERROR mutable references - unsafe { NonZero(1) } -} diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr index a0dc950e76dd1..5ce4296458e6d 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.stderr +++ b/src/test/ui/unsafe/ranged_ints2_const.stderr @@ -16,15 +16,6 @@ LL | let y = unsafe { &mut x.0 }; = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/ranged_ints2_const.rs:24:22 - | -LL | unsafe { let y = &mut x.0; } - | ^^^^^^^^ - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2_const.rs:11:13 | @@ -33,7 +24,7 @@ LL | let y = &mut x.0; | = note: mutating layout constrained fields cannot statically be checked for valid values -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/tools/cargo b/src/tools/cargo index 783bc43c660bf..a73e5b7d567c3 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 783bc43c660bf39c1e562c8c429b32078ad3099b +Subproject commit a73e5b7d567c3036b296fc6b33ed52c5edcd882e diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 3a754f4991782..f518da55cd76f 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -12,7 +12,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_parse::maybe_new_parser_from_source_str; -use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::edition::Edition; @@ -484,7 +483,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let mut relevant_main_found = false; loop { - match parser.parse_item(ForceCollect::No) { + match parser.parse_item() { Ok(Some(item)) => match &item.kind { // Tests with one of these items are ignored ItemKind::Static(..) diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index bbcea387de2cb..1c5ab2874b048 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -533,7 +533,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { } // check for never_loop - if let ExprKind::Loop(ref block, _, _, _) = expr.kind { + if let ExprKind::Loop(ref block, _, _) = expr.kind { match never_loop_block(block, expr.hir_id) { NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"), NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (), @@ -543,7 +543,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { // check for `loop { if let {} else break }` that could be `while let` // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) - if let ExprKind::Loop(ref block, _, LoopSource::Loop, _) = expr.kind { + if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind { // also check for empty `loop {}` statements, skipping those in #[panic_handler] if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) { let msg = "empty `loop {}` wastes CPU cycles"; @@ -738,7 +738,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Assign(ref e1, ref e2, _) | ExprKind::AssignOp(_, ref e1, ref e2) | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id), - ExprKind::Loop(ref b, _, _, _) => { + ExprKind::Loop(ref b, _, _) => { // Break can come from the inner loop so remove them. absorb_break(&never_loop_block(b, main_loop_id)) }, @@ -1314,7 +1314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { // Non-determinism may occur ... don't give a lint - ExprKind::Loop(..) | ExprKind::Match(..) => self.should_lint = false, + ExprKind::Loop(_, _, _) | ExprKind::Match(_, _, _) => self.should_lint = false, ExprKind::Block(block, _) => self.visit_block(block), _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 603071a5f4ac4..a971d041ca661 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -221,7 +221,7 @@ where { if let ast::ExprKind::While(_, loop_block, label) | ast::ExprKind::ForLoop(_, _, loop_block, label) - | ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind + | ast::ExprKind::Loop(loop_block, label) = &expr.kind { func(loop_block, label.as_ref()); } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index d5b1767e945b9..24da056770c9d 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -325,7 +325,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut | ExprKind::Field(ref e, _) | ExprKind::AddrOf(_, _, ref e) | ExprKind::Box(ref e) => check_expr(cx, e, bindings), - ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => check_block(cx, block, bindings), + ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, _, _) => check_block(cx, block, bindings), // ExprKind::Call // ExprKind::MethodCall ExprKind::Array(v) | ExprKind::Tup(v) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index ca60d335262b3..43afa65de3e55 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -317,7 +317,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = cast_pat; self.visit_expr(expr); }, - ExprKind::Loop(ref body, _, desugaring, _) => { + ExprKind::Loop(ref body, _, desugaring) => { let body_pat = self.next("body"); let des = loop_desugaring_name(desugaring); let label_pat = self.next("label"); diff --git a/src/tools/clippy/clippy_lints/src/utils/higher.rs b/src/tools/clippy/clippy_lints/src/utils/higher.rs index 42ab9a1e7d247..9b3585865da32 100644 --- a/src/tools/clippy/clippy_lints/src/utils/higher.rs +++ b/src/tools/clippy/clippy_lints/src/utils/higher.rs @@ -142,7 +142,7 @@ pub fn for_loop<'tcx>( if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind; if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind; if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(); - if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind; + if let hir::ExprKind::Loop(ref block, _, _) = arms[0].body.kind; if block.expr.is_none(); if let [ _, _, ref let_stmt, ref body ] = *block.stmts; if let hir::StmtKind::Local(ref local) = let_stmt.kind; @@ -158,7 +158,7 @@ pub fn for_loop<'tcx>( /// `while cond { body }` becomes `(cond, body)`. pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> { if_chain! { - if let hir::ExprKind::Loop(block, _, hir::LoopSource::While, _) = &expr.kind; + if let hir::ExprKind::Loop(block, _, hir::LoopSource::While) = &expr.kind; if let hir::Block { expr: Some(expr), .. } = &**block; if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind; if let hir::ExprKind::DropTemps(cond) = &cond.kind; diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index 6066383f2ef42..10120a8805db2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -123,7 +123,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r)) }, (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node, - (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => { + (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => { lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name) }, (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => { @@ -560,7 +560,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Lit(ref l) => { l.node.hash(&mut self.s); }, - ExprKind::Loop(ref b, ref i, ..) => { + ExprKind::Loop(ref b, ref i, _) => { self.hash_block(b); if let Some(i) = *i { self.hash_name(i.ident.name); diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index f361db6b147da..3429317498ed6 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -1,4 +1,4 @@ -error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 +error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::unstable_as_slice)] @@ -6,73 +6,73 @@ LL | #[warn(clippy::unstable_as_slice)] | = note: `-D renamed-and-removed-lints` implied by `-D warnings` -error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 +error: lint `clippy::unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` --> $DIR/deprecated.rs:2:8 | LL | #[warn(clippy::unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr +error: lint `clippy::misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` --> $DIR/deprecated.rs:3:8 | LL | #[warn(clippy::misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint +error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint` --> $DIR/deprecated.rs:4:8 | LL | #[warn(clippy::unused_collect)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::invalid_ref` has been removed: superseded by rustc lint `invalid_value` +error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value`` --> $DIR/deprecated.rs:5:8 | LL | #[warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::into_iter_on_array` has been removed: this lint has been uplifted to rustc and is now called `array_into_iter` +error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter`` --> $DIR/deprecated.rs:6:8 | LL | #[warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_label` has been removed: this lint has been uplifted to rustc and is now called `unused_labels` +error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels`` --> $DIR/deprecated.rs:7:8 | LL | #[warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018 +error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018` --> $DIR/deprecated.rs:8:8 | LL | #[warn(clippy::regex_macro)] | ^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::drop_bounds` has been removed: this lint has been uplifted to rustc and is now called `drop_bounds` +error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds`` --> $DIR/deprecated.rs:9:8 | LL | #[warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::temporary_cstring_as_ptr` has been removed: this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr` +error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`` --> $DIR/deprecated.rs:10:8 | LL | #[warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::panic_params` has been removed: this lint has been uplifted to rustc and is now called `panic_fmt` +error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt`` --> $DIR/deprecated.rs:11:8 | LL | #[warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unknown_clippy_lints` has been removed: this lint has been integrated into the `unknown_lints` rustc lint +error: lint `clippy::unknown_clippy_lints` has been removed: `this lint has been integrated into the `unknown_lints` rustc lint` --> $DIR/deprecated.rs:12:8 | LL | #[warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 +error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::unstable_as_slice)] diff --git a/src/tools/clippy/tests/ui/deprecated_old.stderr b/src/tools/clippy/tests/ui/deprecated_old.stderr index b8550078c4600..2fe1facf0c72d 100644 --- a/src/tools/clippy/tests/ui/deprecated_old.stderr +++ b/src/tools/clippy/tests/ui/deprecated_old.stderr @@ -1,4 +1,4 @@ -error: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 +error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated_old.rs:1:8 | LL | #[warn(unstable_as_slice)] @@ -6,19 +6,19 @@ LL | #[warn(unstable_as_slice)] | = note: `-D renamed-and-removed-lints` implied by `-D warnings` -error: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 +error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` --> $DIR/deprecated_old.rs:2:8 | LL | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ -error: lint `misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr +error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` --> $DIR/deprecated_old.rs:3:8 | LL | #[warn(misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 +error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated_old.rs:1:8 | LL | #[warn(unstable_as_slice)] diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 6ec292aba6495..29131f686a9dc 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -149,22 +149,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> { } } - let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str())); - - let args = match args { - Some(args) => args, - None => { - print_err( - &format!( - "Invalid arguments to shlex::split: `{}`", - cap.name("args").unwrap().as_str() - ), - lineno, - ); - errors = true; - continue; - } - }; + let args = cap.name("args").map_or(vec![], |m| shlex::split(m.as_str()).unwrap()); if !cmd.validate(&args, commands.len(), lineno) { errors = true; diff --git a/src/tools/miri b/src/tools/miri index de0800e83b4e1..1cf1a2e40a686 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit de0800e83b4e15cf3c6aa8f15f8328e86a95d955 +Subproject commit 1cf1a2e40a6867948db84f806085a875fbefce3c