diff options
438 files changed, 6022 insertions, 2636 deletions
diff --git a/Cargo.lock b/Cargo.lock index 43da32df5d9..6f95dae42a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -576,7 +576,7 @@ dependencies = [ name = "clippy" version = "0.1.58" dependencies = [ - "cargo_metadata 0.12.0", + "cargo_metadata 0.14.0", "clippy_lints", "clippy_utils", "compiletest_rs", @@ -588,7 +588,7 @@ dependencies = [ "regex", "rustc-workspace-hack", "rustc_tools_util 0.2.0", - "semver 0.11.0", + "semver 1.0.3", "serde", "syn", "tempfile", @@ -613,7 +613,7 @@ dependencies = [ name = "clippy_lints" version = "0.1.58" dependencies = [ - "cargo_metadata 0.12.0", + "cargo_metadata 0.14.0", "clippy_utils", "if_chain", "itertools 0.10.1", @@ -621,7 +621,7 @@ dependencies = [ "quine-mc_cluskey", "regex-syntax", "rustc-semver", - "semver 0.11.0", + "semver 1.0.3", "serde", "serde_json", "toml", @@ -710,9 +710,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca" +checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83" dependencies = [ "diff", "filetime", @@ -1900,9 +1900,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_ast/README.md b/compiler/rustc_ast/README.md index dd407dba1f4..b2b90fed033 100644 --- a/compiler/rustc_ast/README.md +++ b/compiler/rustc_ast/README.md @@ -1,6 +1,5 @@ The `rustc_ast` crate contains those things concerned purely with syntax -– that is, the AST ("abstract syntax tree"), parser, pretty-printer, -lexer, macro expander, and utilities for traversing ASTs. +– that is, the AST ("abstract syntax tree"), along with some definitions for tokens and token streams, data structures/traits for mutating ASTs, and shared definitions for other AST-related parts of the compiler (like the lexer and macro-expansion). For more information about how these things work in rustc, see the rustc dev guide: diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index e3c610585d9..b9db2a7e089 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -1,4 +1,4 @@ -//! The Rust parser and macro expander. +//! The Rust Abstract Syntax Tree (AST). //! //! # Note //! @@ -16,6 +16,7 @@ #![feature(nll)] #![feature(min_specialization)] #![recursion_limit = "256"] +#![feature(slice_internals)] #[macro_use] extern crate rustc_macros; @@ -25,6 +26,7 @@ pub mod util { pub mod comments; pub mod literal; pub mod parser; + pub mod unicode; } pub mod ast; diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs new file mode 100644 index 00000000000..f009f7b300c --- /dev/null +++ b/compiler/rustc_ast/src/util/unicode.rs @@ -0,0 +1,35 @@ +pub const TEXT_FLOW_CONTROL_CHARS: &[char] = &[ + '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', + '\u{2069}', +]; + +#[inline] +pub fn contains_text_flow_control_chars(s: &str) -> bool { + // Char - UTF-8 + // U+202A - E2 80 AA + // U+202B - E2 80 AB + // U+202C - E2 80 AC + // U+202D - E2 80 AD + // U+202E - E2 80 AE + // U+2066 - E2 81 A6 + // U+2067 - E2 81 A7 + // U+2068 - E2 81 A8 + // U+2069 - E2 81 A9 + let mut bytes = s.as_bytes(); + loop { + match core::slice::memchr::memchr(0xE2, &bytes) { + Some(idx) => { + // bytes are valid UTF-8 -> E2 must be followed by two bytes + let ch = &bytes[idx..idx + 3]; + match ch { + [_, 0x80, 0xAA..=0xAE] | [_, 0x81, 0xA6..=0xA9] => break true, + _ => {} + } + bytes = &bytes[idx + 3..]; + } + None => { + break false; + } + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index dca9c1f04d3..bedd3523d89 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -1,7 +1,6 @@ use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, AttributePlace}; -use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -53,15 +52,10 @@ pub trait ArgAttributesExt { } fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool { - // LLVM prior to version 12 has known miscompiles in the presence of - // noalias attributes (see #54878). Only enable mutable noalias by - // default for versions we believe to be safe. - cx.tcx - .sess - .opts - .debugging_opts - .mutable_noalias - .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0)) + // LLVM prior to version 12 had known miscompiles in the presence of + // noalias attributes (see #54878), but we don't support earlier + // versions at all anymore. We now enable mutable noalias by default. + cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true) } impl ArgAttributesExt for ArgAttributes { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0707faf610c..6c74163fb49 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -731,7 +731,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { - if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() { + if !self.fptoint_sat_broken_in_llvm() { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); @@ -743,7 +743,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { - if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() { + if !self.fptoint_sat_broken_in_llvm() { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index cda766039c1..1dba264a961 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -134,9 +134,6 @@ pub unsafe fn create_module( let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); let mut target_data_layout = sess.target.data_layout.clone(); - if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" { - target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", ""); - } if llvm_util::get_version() < (13, 0, 0) { if sess.target.arch == "powerpc64" { target_data_layout = target_data_layout.replace("-S128", ""); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8f4d79e7147..64fedb7bc1a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -76,6 +76,27 @@ mod value; #[derive(Clone)] pub struct LlvmCodegenBackend(()); +struct TimeTraceProfiler { + enabled: bool, +} + +impl TimeTraceProfiler { + fn new(enabled: bool) -> Self { + if enabled { + unsafe { llvm::LLVMTimeTraceProfilerInitialize() } + } + TimeTraceProfiler { enabled } + } +} + +impl Drop for TimeTraceProfiler { + fn drop(&mut self) { + if self.enabled { + unsafe { llvm::LLVMTimeTraceProfilerFinishThread() } + } + } +} + impl ExtraBackendMethods for LlvmCodegenBackend { fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm { ModuleLlvm::new_metadata(tcx, mod_name) @@ -119,6 +140,34 @@ impl ExtraBackendMethods for LlvmCodegenBackend { fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> { llvm_util::tune_cpu(sess) } + + fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + std::thread::spawn(move || { + let _profiler = TimeTraceProfiler::new(time_trace); + f() + }) + } + + fn spawn_named_thread<F, T>( + time_trace: bool, + name: String, + f: F, + ) -> std::io::Result<std::thread::JoinHandle<T>> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + std::thread::Builder::new().name(name).spawn(move || { + let _profiler = TimeTraceProfiler::new(time_trace); + f() + }) + } } impl WriteBackendMethods for LlvmCodegenBackend { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 21d2388fc30..749eec459ac 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1737,6 +1737,8 @@ extern "C" { pub fn LLVMTimeTraceProfilerInitialize(); + pub fn LLVMTimeTraceProfilerFinishThread(); + pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char); pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index baa257069aa..c3e7e7169a9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -113,11 +113,6 @@ unsafe fn configure_llvm(sess: &Session) { } if sess.opts.debugging_opts.llvm_time_trace { - // time-trace is not thread safe and running it in parallel will cause seg faults. - if !sess.opts.debugging_opts.no_parallel_llvm { - bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm") - } - llvm::LLVMTimeTraceProfilerInitialize(); } @@ -180,6 +175,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> { ("aarch64", "dpb2") => vec!["ccdp"], ("aarch64", "frintts") => vec!["fptoint"], ("aarch64", "fcma") => vec!["complxnum"], + ("aarch64", "pmuv3") => vec!["perfmon"], (_, s) => vec![s], } } @@ -405,11 +401,6 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> { // -Ctarget-features features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); - // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12. - if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") { - features.push("+outline-atomics".to_string()); - } - features } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index da34612ce76..b2edc6c0183 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -310,6 +310,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub no_landing_pads: bool, pub save_temps: bool, pub fewer_names: bool, + pub time_trace: bool, pub exported_symbols: Option<Arc<ExportedSymbols>>, pub opts: Arc<config::Options>, pub crate_types: Vec<CrateType>, @@ -1039,6 +1040,7 @@ fn start_executing_work<B: ExtraBackendMethods>( no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort, fewer_names: sess.fewer_names(), save_temps: sess.opts.cg.save_temps, + time_trace: sess.opts.debugging_opts.llvm_time_trace, opts: Arc::new(sess.opts.clone()), prof: sess.prof.clone(), exported_symbols, @@ -1198,7 +1200,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // Each LLVM module is automatically sent back to the coordinator for LTO if // necessary. There's already optimizations in place to avoid sending work // back to the coordinator if LTO isn't requested. - return thread::spawn(move || { + return B::spawn_thread(cgcx.time_trace, move || { let mut worker_id_counter = 0; let mut free_worker_ids = Vec::new(); let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| { @@ -1615,59 +1617,57 @@ fn start_executing_work<B: ExtraBackendMethods>( pub struct WorkerFatalError; fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) { - let builder = thread::Builder::new().name(work.short_description()); - builder - .spawn(move || { - // Set up a destructor which will fire off a message that we're done as - // we exit. - struct Bomb<B: ExtraBackendMethods> { - coordinator_send: Sender<Box<dyn Any + Send>>, - result: Option<Result<WorkItemResult<B>, FatalError>>, - worker_id: usize, - } - impl<B: ExtraBackendMethods> Drop for Bomb<B> { - fn drop(&mut self) { - let worker_id = self.worker_id; - let msg = match self.result.take() { - Some(Ok(WorkItemResult::Compiled(m))) => { - Message::Done::<B> { result: Ok(m), worker_id } - } - Some(Ok(WorkItemResult::NeedsLink(m))) => { - Message::NeedsLink::<B> { module: m, worker_id } - } - Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { - Message::NeedsFatLTO::<B> { result: m, worker_id } - } - Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => { - Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id } - } - Some(Err(FatalError)) => { - Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id } - } - None => Message::Done::<B> { result: Err(None), worker_id }, - }; - drop(self.coordinator_send.send(Box::new(msg))); - } + B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { + // Set up a destructor which will fire off a message that we're done as + // we exit. + struct Bomb<B: ExtraBackendMethods> { + coordinator_send: Sender<Box<dyn Any + Send>>, + result: Option<Result<WorkItemResult<B>, FatalError>>, + worker_id: usize, + } + impl<B: ExtraBackendMethods> Drop for Bomb<B> { + fn drop(&mut self) { + let worker_id = self.worker_id; + let msg = match self.result.take() { + Some(Ok(WorkItemResult::Compiled(m))) => { + Message::Done::<B> { result: Ok(m), worker_id } + } + Some(Ok(WorkItemResult::NeedsLink(m))) => { + Message::NeedsLink::<B> { module: m, worker_id } + } + Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { + Message::NeedsFatLTO::<B> { result: m, worker_id } + } + Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => { + Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id } + } + Some(Err(FatalError)) => { + Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id } + } + None => Message::Done::<B> { result: Err(None), worker_id }, + }; + drop(self.coordinator_send.send(Box::new(msg))); } + } - let mut bomb = Bomb::<B> { - coordinator_send: cgcx.coordinator_send.clone(), - result: None, - worker_id: cgcx.worker, - }; + let mut bomb = Bomb::<B> { + coordinator_send: cgcx.coordinator_send.clone(), + result: None, + worker_id: cgcx.worker, + }; - // Execute the work itself, and if it finishes successfully then flag - // ourselves as a success as well. - // - // Note that we ignore any `FatalError` coming out of `execute_work_item`, - // as a diagnostic was already sent off to the main thread - just - // surface that there was an error in this worker. - bomb.result = { - let _prof_timer = work.start_profiling(&cgcx); - Some(execute_work_item(&cgcx, work)) - }; - }) - .expect("failed to spawn thread"); + // Execute the work itself, and if it finishes successfully then flag + // ourselves as a success as well. + // + // Note that we ignore any `FatalError` coming out of `execute_work_item`, + // as a diagnostic was already sent off to the main thread - just + // surface that there was an error in this worker. + bomb.result = { + let _prof_timer = work.start_profiling(&cgcx); + Some(execute_work_item(&cgcx, work)) + }; + }) + .expect("failed to spawn thread"); } enum SharedEmitterMessage { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 297dcde99b3..a9471f7b771 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -832,7 +832,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(rcvalle): Add support for generalized identifiers. // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers. let typeid = typeid_for_fnabi(bx.tcx(), fn_abi); - let typeid_metadata = bx.typeid_metadata(typeid.clone()); + let typeid_metadata = bx.typeid_metadata(typeid); // Test whether the function pointer is associated with the type identifier. let cond = bx.type_test(fn_ptr, typeid_metadata); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 1cd400eecfb..1ef863e84af 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -250,7 +250,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // is associated with a type identifier). if cx.tcx().sess.is_sanitizer_cfi_enabled() { let typeid = typeid_for_fnabi(cx.tcx(), fn_abi); - bx.type_metadata(llfn, typeid.clone()); + bx.type_metadata(llfn, typeid); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index fe7f6288adb..2c96987d339 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -125,7 +125,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let count = self.codegen_operand(&mut bx, count).immediate(); let pointee_layout = dst_val .layout - .pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO) + .pointee_info_at(&bx, rustc_target::abi::Size::ZERO) .expect("Expected pointer"); let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes())); diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index dbffb266be8..caeeb23feb4 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -36,7 +36,6 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("thumb-mode", Some(sym::arm_target_feature)), ]; -// Commented features are not available in LLVM 10.0, or have since been renamed const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ // FEAT_AdvSimd ("neon", Some(sym::aarch64_target_feature)), @@ -67,13 +66,13 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ // FEAT_DIT ("dit", Some(sym::aarch64_target_feature)), // FEAT_FLAGM - // ("flagm", Some(sym::aarch64_target_feature)), + ("flagm", Some(sym::aarch64_target_feature)), // FEAT_SSBS ("ssbs", Some(sym::aarch64_target_feature)), // FEAT_SB ("sb", Some(sym::aarch64_target_feature)), // FEAT_PAUTH - // ("pauth", Some(sym::aarch64_target_feature)), + ("pauth", Some(sym::aarch64_target_feature)), // FEAT_DPB ("dpb", Some(sym::aarch64_target_feature)), // FEAT_DPB2 @@ -93,11 +92,11 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ // FEAT_I8MM ("i8mm", Some(sym::aarch64_target_feature)), // FEAT_F32MM - // ("f32mm", Some(sym::aarch64_target_feature)), + ("f32mm", Some(sym::aarch64_target_feature)), // FEAT_F64MM - // ("f64mm", Some(sym::aarch64_target_feature)), + ("f64mm", Some(sym::aarch64_target_feature)), // FEAT_BF16 - // ("bf16", Some(sym::aarch64_target_feature)), + ("bf16", Some(sym::aarch64_target_feature)), // FEAT_RAND ("rand", Some(sym::aarch64_target_feature)), // FEAT_BTI @@ -116,13 +115,23 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("sha3", Some(sym::aarch64_target_feature)), // FEAT_SM3 & FEAT_SM4 ("sm4", Some(sym::aarch64_target_feature)), + // FEAT_PAN + ("pan", Some(sym::aarch64_target_feature)), + // FEAT_LOR + ("lor", Some(sym::aarch64_target_feature)), + // FEAT_VHE + ("vh", Some(sym::aarch64_target_feature)), + // FEAT_PMUv3 + ("pmuv3", Some(sym::aarch64_target_feature)), + // FEAT_SPE + ("spe", Some(sym::aarch64_target_feature)), ("v8.1a", Some(sym::aarch64_target_feature)), ("v8.2a", Some(sym::aarch64_target_feature)), ("v8.3a", Some(sym::aarch64_target_feature)), ("v8.4a", Some(sym::aarch64_target_feature)), ("v8.5a", Some(sym::aarch64_target_feature)), - // ("v8.6a", Some(sym::aarch64_target_feature)), - // ("v8.7a", Some(sym::aarch64_target_feature)), + ("v8.6a", Some(sym::aarch64_target_feature)), + ("v8.7a", Some(sym::aarch64_target_feature)), ]; const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 8fef8314a5c..9c8bc3b2109 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -142,4 +142,26 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se ) -> TargetMachineFactoryFn<Self>; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>; + + fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + std::thread::spawn(f) + } + + fn spawn_named_thread<F, T>( + _time_trace: bool, + name: String, + f: F, + ) -> std::io::Result<std::thread::JoinHandle<T>> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + std::thread::Builder::new().name(name).spawn(f) + } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 38576230883..fcce829eba4 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -94,11 +94,10 @@ where } } - fn address_of_allows_mutation(&self, mt: mir::Mutability, place: mir::Place<'tcx>) -> bool { - match mt { - mir::Mutability::Mut => true, - mir::Mutability::Not => self.shared_borrow_allows_mutation(place), - } + fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool { + // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that + // it might allow mutation until resolution of #56604. + true } fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { @@ -110,6 +109,15 @@ where } } + /// `&` only allow mutation if the borrowed place is `!Freeze`. + /// + /// This assumes that it is UB to take the address of a struct field whose type is + /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of + /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will + /// have to check the type of the borrowed **local** instead of the borrowed **place** + /// below. See [rust-lang/unsafe-code-guidelines#134]. + /// + /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool { !place .ty(self.ccx.body, self.ccx.tcx) diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 724e3f7fed3..42ce849c64d 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -487,9 +487,9 @@ E0785: include_str!("./error_codes/E0785.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard -// E0019, merged into E0015 -// E0035, merged into E0087/E0089 -// E0036, merged into E0087/E0089 +// E0019, // merged into E0015 +// E0035, // merged into E0087/E0089 +// E0036, // merged into E0087/E0089 // E0068, // E0085, // E0086, @@ -504,8 +504,8 @@ E0785: include_str!("./error_codes/E0785.md"), // E0134, // E0135, // E0141, -// E0153, unused error code -// E0157, unused error code +// E0153, // unused error code +// E0157, // unused error code // E0159, // use of trait `{}` as struct constructor // E0163, // merged into E0071 // E0167, @@ -573,24 +573,24 @@ E0785: include_str!("./error_codes/E0785.md"), // between structures with the same definition // E0385, // {} in an aliasable location // E0402, // cannot use an outer type parameter in this context -// E0406, merged into 420 -// E0410, merged into 408 -// E0413, merged into 530 -// E0414, merged into 530 -// E0417, merged into 532 -// E0418, merged into 532 -// E0419, merged into 531 -// E0420, merged into 532 -// E0421, merged into 531 -// E0427, merged into 530 +// E0406, // merged into 420 +// E0410, // merged into 408 +// E0413, // merged into 530 +// E0414, // merged into 530 +// E0417, // merged into 532 +// E0418, // merged into 532 +// E0419, // merged into 531 +// E0420, // merged into 532 +// E0421, // merged into 531 +// E0427, // merged into 530 // E0456, // plugin `..` is not available for triple `..` E0457, // plugin `..` only found in rlib format, but must be available... E0460, // found possibly newer version of crate `..` E0461, // couldn't find crate `..` with expected target triple .. E0462, // found staticlib `..` instead of rlib or dylib E0465, // multiple .. candidates for `..` found -// E0467, removed -// E0470, removed +// E0467, // removed +// E0470, // removed // E0471, // constant evaluation error (in pattern) E0472, // llvm_asm! is unsupported on this target // E0473, // dereference of reference outside its lifetime @@ -610,8 +610,7 @@ E0785: include_str!("./error_codes/E0785.md"), E0490, // a value of type `..` is borrowed for too long E0514, // metadata version mismatch E0519, // local crate and dependency have same (crate-name, disambiguator) - // two dependencies have same (crate-name, disambiguator) but different SVH - E0523, + E0523, // two dependencies have same (crate-name, disambiguator) but different SVH // E0526, // shuffle indices are not constant // E0540, // multiple rustc_deprecated attributes // E0548, // replaced with a generic attribute input check @@ -638,7 +637,7 @@ E0785: include_str!("./error_codes/E0785.md"), E0711, // a feature has been declared with conflicting stability attributes E0717, // rustc_promotable without stability attribute // E0721, // `await` keyword -// E0723, unstable feature in `const` context +// E0723, // unstable feature in `const` context E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 0d7a2afb636..941d957103c 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -297,6 +297,8 @@ declare_features! ( (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None), /// Allows panicking during const eval (producing compile-time errors). (accepted, const_panic, "1.57.0", Some(51999), None), + /// Lessens the requirements for structs to implement `Unsize`. + (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 2bbfb561ba5..1c6f1344e8a 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -101,9 +101,13 @@ impl Feature { } } +// See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more +// documentation about handling feature gates. +// // If you change this, please modify `src/doc/unstable-book` as well. // -// Don't ever remove anything from this list; move them to `removed.rs`. +// Don't ever remove anything from this list; move them to `accepted.rs` if +// accepted or `removed.rs` if removed. // // The version numbers here correspond to the version in which the current status // was set. This is most important for knowing when a particular feature became @@ -589,9 +593,6 @@ declare_features! ( /// Allows `extern "C-cmse-nonsecure-call" fn()`. (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None), - /// Lessens the requirements for structs to implement `Unsize`. - (active, relaxed_struct_unsize, "1.51.0", Some(81793), None), - /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), @@ -688,6 +689,9 @@ declare_features! ( /// not changed from prior instances of the same struct (RFC #2528) (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None), + /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. + (active, doc_auto_cfg, "1.58.0", Some(43781), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 1b35c4032f4..ac57796763f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -7,7 +7,10 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::SubregionOrigin; -use rustc_errors::{struct_span_err, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; +use rustc_hir::{GenericParamKind, Ty}; +use rustc_middle::ty::Region; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when both the concerned regions are anonymous. @@ -160,11 +163,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } }; - let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); + let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); - e.span_label(span_1, main_label); - e.span_label(span_2, String::new()); - e.span_label(span, span_label); + err.span_label(span_1, main_label); + err.span_label(span_2, String::new()); + err.span_label(span, span_label); + + self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err); if let Some(t) = future_return_type { let snip = self @@ -178,14 +183,87 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { (_, "") => None, _ => Some(s), }) - .unwrap_or("{unnamed_type}".to_string()); + .unwrap_or_else(|| "{unnamed_type}".to_string()); - e.span_label( + err.span_label( t.span, &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip), ); } - e.emit(); + err.emit(); Some(ErrorReported) } + + fn suggest_adding_lifetime_params( + &self, + sub: Region<'tcx>, + ty_sup: &Ty<'_>, + ty_sub: &Ty<'_>, + err: &mut DiagnosticBuilder<'_>, + ) { + if let ( + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, + ) = (ty_sub, ty_sup) + { + if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() { + if let Some(anon_reg) = self.tcx().is_suitable_region(sub) { + let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id); + if let hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Fn(_, ref generics, ..), + .. + }) = self.tcx().hir().get(hir_id) + { + let (suggestion_param_name, introduce_new) = generics + .params + .iter() + .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok()) + .map(|name| (name, false)) + .unwrap_or_else(|| ("'a".to_string(), true)); + + let mut suggestions = vec![ + if let hir::LifetimeName::Underscore = lifetime_sub.name { + (lifetime_sub.span, suggestion_param_name.clone()) + } else { + ( + lifetime_sub.span.shrink_to_hi(), + suggestion_param_name.clone() + " ", + ) + }, + if let hir::LifetimeName::Underscore = lifetime_sup.name { + (lifetime_sup.span, suggestion_param_name.clone()) + } else { + ( + lifetime_sup.span.shrink_to_hi(), + suggestion_param_name.clone() + " ", + ) + }, + ]; + + if introduce_new { + let new_param_suggestion = match &generics.params { + [] => (generics.span, format!("<{}>", suggestion_param_name)), + [first, ..] => ( + first.span.shrink_to_lo(), + format!("{}, ", suggestion_param_name), + ), + }; + + suggestions.push(new_param_suggestion); + } + + err.multipart_suggestion( + "consider introducing a named lifetime parameter", + suggestions, + Applicability::MaybeIncorrect, + ); + err.note( + "each elided lifetime in input position becomes a distinct lifetime", + ); + } + } + } + } + } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6b905f67e68..9dae978dcde 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1252,16 +1252,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tainted_by_errors_flag.set(true) } - /// Process the region constraints and report any errors that + /// Process the region constraints and return any any errors that /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use /// `resolve_vars_if_possible` as well as `fully_resolve`. - pub fn resolve_regions_and_report_errors( + pub fn resolve_regions( &self, region_context: DefId, outlives_env: &OutlivesEnvironment<'tcx>, mode: RegionckMode, - ) { + ) -> Vec<RegionResolutionError<'tcx>> { let (var_infos, data) = { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; @@ -1287,6 +1287,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); assert!(old_value.is_none()); + errors + } + + /// Process the region constraints and report any errors that + /// result. After this, no more unification operations should be + /// done -- or the compiler will panic -- but it is legal to use + /// `resolve_vars_if_possible` as well as `fully_resolve`. + pub fn resolve_regions_and_report_errors( + &self, + region_context: DefId, + outlives_env: &OutlivesEnvironment<'tcx>, + mode: RegionckMode, + ) { + let errors = self.resolve_regions(region_context, outlives_env, mode); + if !self.is_tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 6fd0a5b95f9..4c936dec6f2 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -16,9 +16,9 @@ use self::TargetLint::*; -use crate::hidden_unicode_codepoints::UNICODE_TEXT_FLOW_CHARS; use crate::levels::{is_known_lint_tool, LintLevelsBuilder}; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; +use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; @@ -602,7 +602,7 @@ pub trait LintContext: Sized { let spans: Vec<_> = content .char_indices() .filter_map(|(i, c)| { - UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| { + TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { let lo = span.lo() + BytePos(2 + i as u32); (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) }) diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index 1bcdcb806fc..fde84be9a7c 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -1,4 +1,5 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; +use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; use rustc_ast as ast; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_span::{BytePos, Span, Symbol}; @@ -37,11 +38,6 @@ declare_lint! { declare_lint_pass!(HiddenUnicodeCodepoints => [TEXT_DIRECTION_CODEPOINT_IN_LITERAL]); -crate const UNICODE_TEXT_FLOW_CHARS: &[char] = &[ - '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', - '\u{2069}', -]; - impl HiddenUnicodeCodepoints { fn lint_text_direction_codepoint( &self, @@ -57,7 +53,7 @@ impl HiddenUnicodeCodepoints { .as_str() .char_indices() .filter_map(|(i, c)| { - UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| { + TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { let lo = span.lo() + BytePos(i as u32 + padding); (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) }) @@ -131,7 +127,7 @@ impl HiddenUnicodeCodepoints { impl EarlyLintPass for HiddenUnicodeCodepoints { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { if let ast::AttrKind::DocComment(_, comment) = attr.kind { - if comment.as_str().contains(UNICODE_TEXT_FLOW_CHARS) { + if contains_text_flow_control_chars(&comment.as_str()) { self.lint_text_direction_codepoint(cx, comment, attr.span, 0, false, "doc comment"); } } @@ -142,7 +138,7 @@ impl EarlyLintPass for HiddenUnicodeCodepoints { let (text, span, padding) = match &expr.kind { ast::ExprKind::Lit(ast::Lit { token, kind, span }) => { let text = token.symbol; - if !text.as_str().contains(UNICODE_TEXT_FLOW_CHARS) { + if !contains_text_flow_control_chars(&text.as_str()) { return; } let padding = match kind { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b83d04f3dc2..c1a53c34b7a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3054,6 +3054,7 @@ declare_lint_pass! { BREAK_WITH_LABEL_AND_LOOP, UNUSED_ATTRIBUTES, NON_EXHAUSTIVE_OMITTED_PATTERNS, + TEXT_DIRECTION_CODEPOINT_IN_COMMENT, DEREF_INTO_DYN_SUPERTRAIT, ] } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 32b866e81b1..ddbc3c59128 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -75,6 +75,10 @@ extern "C" void LLVMTimeTraceProfilerInitialize() { /* ProcName */ "rustc"); } +extern "C" void LLVMTimeTraceProfilerFinishThread() { + timeTraceProfilerFinishThread(); +} + extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { StringRef FN(FileName); std::error_code EC; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index bbd30c9327a..8db2291dfcf 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -236,7 +236,7 @@ use std::fmt::Write as _; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; use std::{cmp, fmt, fs}; -use tracing::{debug, info, warn}; +use tracing::{debug, info}; #[derive(Clone)] crate struct CrateLocator<'a> { @@ -549,7 +549,7 @@ impl<'a> CrateLocator<'a> { } } Err(err) => { - warn!("no metadata found: {}", err); + info!("no metadata found: {}", err); continue; } }; diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 42683dac426..1260c691e78 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -632,11 +632,11 @@ fn tooltip<'tcx>( for statement in statements { let source_range = source_range_no_file(tcx, &statement.source_info.span); text.push(format!( - "\n{}{}: {}: {}", + "\n{}{}: {}: {:?}", TOOLTIP_INDENT, source_range, statement_kind_name(&statement), - format!("{:?}", statement) + statement )); } if let Some(term) = terminator { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8ec5f4c7978..b87e23af72b 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -3060,9 +3060,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // LLVM's definition of `noalias` is based solely on memory // dependencies rather than pointer equality // - // Due to miscompiles in LLVM < 12, we apply a separate NoAliasMutRef attribute - // for UniqueBorrowed arguments, so that the codegen backend can decide - // whether or not to actually emit the attribute. + // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute + // for UniqueBorrowed arguments, so that the codegen backend can decide whether + // or not to actually emit the attribute. It can also be controlled with the + // `-Zmutable-noalias` debugging option. let no_alias = match kind { PointerKind::Shared | PointerKind::UniqueBorrowed => false, PointerKind::UniqueOwned => true, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b11a54d5dcb..742005e245f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -744,6 +744,7 @@ pub trait PrettyPrinter<'tcx>: p!(print_def_path(did, substs)); if !substs.as_closure().is_valid() { p!(" closure_substs=(unavailable)"); + p!(write(" substs={:?}", substs)); } else { p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); p!( diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 158ba1b9425..d38b567a958 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -3,25 +3,14 @@ use super::*; use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{ParamEnv, TyCtxt}; -use rustc_span::DUMMY_SP; - -pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>; /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points /// to a given local. /// -/// The `K` parameter determines what kind of borrows are tracked. By default, -/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows -/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead. -/// /// At present, this is used as a very limited form of alias analysis. For example, /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for -/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a -/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a -/// function call or inline assembly. -pub struct MaybeBorrowedLocals<K = AnyBorrow> { - kind: K, +/// immovable generators. +pub struct MaybeBorrowedLocals { ignore_borrow_on_drop: bool, } @@ -29,29 +18,11 @@ impl MaybeBorrowedLocals { /// A dataflow analysis that records whether a pointer or reference exists that may alias the /// given local. pub fn all_borrows() -> Self { - MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false } - } -} - -impl MaybeMutBorrowedLocals<'mir, 'tcx> { - /// A dataflow analysis that records whether a pointer or reference exists that may *mutably* - /// alias the given local. - /// - /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of - /// types with interior mutability. - pub fn mut_borrows_only( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Self { - MaybeBorrowedLocals { - kind: MutBorrow { body, tcx, param_env }, - ignore_borrow_on_drop: false, - } + MaybeBorrowedLocals { ignore_borrow_on_drop: false } } } -impl<K> MaybeBorrowedLocals<K> { +impl MaybeBorrowedLocals { /// During dataflow analysis, ignore the borrow that may occur when a place is dropped. /// /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a @@ -69,21 +40,14 @@ impl<K> MaybeBorrowedLocals<K> { MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self } } - fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> { - TransferFunction { - kind: &self.kind, - trans, - ignore_borrow_on_drop: self.ignore_borrow_on_drop, - } + fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> { + TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop } } } -impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K> -where - K: BorrowAnalysisKind<'tcx>, -{ +impl AnalysisDomain<'tcx> for MaybeBorrowedLocals { type Domain = BitSet<Local>; - const NAME: &'static str = K::ANALYSIS_NAME; + const NAME: &'static str = "maybe_borrowed_locals"; fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { // bottom = unborrowed @@ -95,10 +59,7 @@ where } } -impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K> -where - K: BorrowAnalysisKind<'tcx>, -{ +impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals { type Idx = Local; fn statement_effect( @@ -131,16 +92,14 @@ where } /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. -struct TransferFunction<'a, T, K> { +struct TransferFunction<'a, T> { trans: &'a mut T, - kind: &'a K, ignore_borrow_on_drop: bool, } -impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K> +impl<T> Visitor<'tcx> for TransferFunction<'a, T> where T: GenKill<Local>, - K: BorrowAnalysisKind<'tcx>, { fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { self.super_statement(stmt, location); @@ -156,14 +115,14 @@ where self.super_rvalue(rvalue, location); match rvalue { - mir::Rvalue::AddressOf(mt, borrowed_place) => { - if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) { + mir::Rvalue::AddressOf(_mt, borrowed_place) => { + if !borrowed_place.is_indirect() { self.trans.gen(borrowed_place.local); } } - mir::Rvalue::Ref(_, kind, borrowed_place) => { - if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) { + mir::Rvalue::Ref(_, _kind, borrowed_place) => { + if !borrowed_place.is_indirect() { self.trans.gen(borrowed_place.local); } } @@ -211,64 +170,3 @@ where } } } - -pub struct AnyBorrow; - -pub struct MutBorrow<'mir, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, - param_env: ParamEnv<'tcx>, -} - -impl MutBorrow<'mir, 'tcx> { - /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`. - /// - /// This assumes that it is UB to take the address of a struct field whose type is - /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of - /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will - /// have to check the type of the borrowed **local** instead of the borrowed **place** - /// below. See [rust-lang/unsafe-code-guidelines#134]. - /// - /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 - fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool { - !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) - } -} - -pub trait BorrowAnalysisKind<'tcx> { - const ANALYSIS_NAME: &'static str; - - fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool; - fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool; -} - -impl BorrowAnalysisKind<'tcx> for AnyBorrow { - const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals"; - - fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool { - true - } - fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool { - true - } -} - -impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> { - const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals"; - - fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool { - match kind { - mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { - self.shared_borrow_allows_mutation(place) - } - } - } - - fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool { - match mt { - Mutability::Mut => true, - Mutability::Not => self.shared_borrow_allows_mutation(place), - } - } -} diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 474f4f2a79b..91dddc6cd55 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -22,7 +22,7 @@ mod init_locals; mod liveness; mod storage_liveness; -pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; +pub use self::borrowed_locals::MaybeBorrowedLocals; pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 2d27d085b48..28e5d76783a 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -11,8 +11,7 @@ use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; use crate::impls::{ - DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals, - MaybeUninitializedPlaces, + DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces, }; use crate::move_paths::{HasMoveData, MoveData}; use crate::move_paths::{LookupResult, MovePathIndex}; @@ -62,14 +61,6 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits); } - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() { - let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env) - .into_engine(tcx, body) - .iterate_to_fixpoint(); - - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed); - } - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() { let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); @@ -281,26 +272,6 @@ where } } -impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> { - fn peek_at( - &self, - tcx: TyCtxt<'tcx>, - place: mir::Place<'tcx>, - flow_state: &BitSet<Local>, - call: PeekCall, - ) { - info!(?place, "peek_at"); - let Some(local) = place.as_local() else { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); - return; - }; - - if !flow_state.contains(local) { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); - } - } -} - impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { fn peek_at( &self, diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 799b4e18c24..4392c02f874 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -67,7 +67,7 @@ crate fn dump_closure_profile(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx src_file.prefer_local(), line_nos ) { - eprintln!("Error writting to file {}", e.to_string()) + eprintln!("Error writing to file {}", e) } } } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 09a3d1b9028..cf35c3cd53b 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,6 +1,7 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream}; +use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; @@ -137,12 +138,8 @@ impl<'a> StringReader<'a> { // Opening delimiter of the length 2 is not included into the comment text. let content_start = start + BytePos(2); let content = self.str_from(content_start); - let span = self.mk_sp(start, self.pos); - const UNICODE_TEXT_FLOW_CHARS: &[char] = &[ - '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', - '\u{202C}', '\u{2069}', - ]; - if content.contains(UNICODE_TEXT_FLOW_CHARS) { + if contains_text_flow_control_chars(content) { + let span = self.mk_sp(start, self.pos); self.sess.buffer_lint_with_diagnostic( &TEXT_DIRECTION_CODEPOINT_IN_COMMENT, span, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 163acebccea..ff0d76e94fd 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -420,6 +420,10 @@ impl<'a> Resolver<'a> { err.span_label(span, label); if let Some((suggestions, msg, applicability)) = suggestion { + if suggestions.is_empty() { + err.help(&msg); + return err; + } err.multipart_suggestion(&msg, suggestions, applicability); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 23eb2d1aebb..5f3620b247e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2523,19 +2523,29 @@ impl<'a> Resolver<'a> { } else { ( format!("use of undeclared crate or module `{}`", ident), - self.find_similarly_named_module_or_crate( - ident.name, - &parent_scope.module, - ) - .map(|sugg| { - ( - vec![(ident.span, sugg.to_string())], + if ident.name == sym::alloc { + Some(( + vec![], String::from( - "there is a crate or module with a similar name", + "add `extern crate alloc` to use the `alloc` crate", ), Applicability::MaybeIncorrect, + )) + } else { + self.find_similarly_named_module_or_crate( + ident.name, + &parent_scope.module, ) - }), + .map(|sugg| { + ( + vec![(ident.span, sugg.to_string())], + String::from( + "there is a crate or module with a similar name", + ), + Applicability::MaybeIncorrect, + ) + }) + }, ) } } else { diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index f4567b33483..f1a5282b088 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -236,7 +236,7 @@ impl<'tcx> DumpVisitor<'tcx> { id, span, name: ident.to_string(), - qualname: format!("{}::{}", qualname, ident.to_string()), + qualname: format!("{}::{}", qualname, ident), value: typ, parent: None, children: vec![], @@ -889,7 +889,7 @@ impl<'tcx> DumpVisitor<'tcx> { // Rust uses the id of the pattern for var lookups, so we'll use it too. if !self.span.filter_generated(ident.span) { - let qualname = format!("{}${}", ident.to_string(), hir_id); + let qualname = format!("{}${}", ident, hir_id); let id = id_from_hir_id(hir_id, &self.save_ctxt); let span = self.span_from_span(ident.span); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index e894e46a301..3add3e86148 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1193,7 +1193,7 @@ options! { move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED], "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED], - "emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"), + "emit noalias metadata for mutable references (default: yes)"), new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED], "use new LLVM pass manager (default: no)"), nll_facts: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1b431589632..52e2a8f48e2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -549,6 +549,7 @@ symbols! { div_assign, doc, doc_alias, + doc_auto_cfg, doc_cfg, doc_cfg_hide, doc_keyword, @@ -1127,7 +1128,6 @@ symbols! { rustc_partition_reused, rustc_peek, rustc_peek_definite_init, - rustc_peek_indirectly_mutable, rustc_peek_liveness, rustc_peek_maybe_init, rustc_peek_maybe_uninit, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index d9eb299e2fd..4768c9e2db5 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -68,8 +68,10 @@ mod attr_impl { const NonNull = 1 << 3; const ReadOnly = 1 << 4; const InReg = 1 << 5; - // NoAlias on &mut arguments can only be used with LLVM >= 12 due to miscompiles - // in earlier versions. FIXME: Remove this distinction once possible. + // Due to past miscompiles in LLVM, we use a separate attribute for + // &mut arguments, so that the codegen backend can decide whether + // or not to actually emit the attribute. It can also be controlled + // with the `-Zmutable-noalias` debugging option. const NoAliasMutRef = 1 << 6; } } diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 2c71fb8afee..ca3550e9278 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -2,7 +2,7 @@ use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOption pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); - base.cpu = "apple-a12".to_string(); + base.cpu = "apple-a14".to_string(); base.max_atomic_width = Some(128); // FIXME: The leak sanitizer currently fails the tests, see #88132. diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs index 71ee6deb07f..a393858879b 100644 --- a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ pub fn target() -> Target { data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), options: TargetOptions { + features: "+outline-atomics".to_string(), max_atomic_width: Some(128), mcount: "\u{1}_mcount".to_string(), endian: Endian::Big, diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs index e05360ea45c..e75100f1435 100644 --- a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs @@ -12,6 +12,7 @@ pub fn target() -> Target { arch: "aarch64".to_string(), options: TargetOptions { abi: "ilp32".to_string(), + features: "+outline-atomics".to_string(), mcount: "\u{1}_mcount".to_string(), endian: Endian::Big, ..base diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs index c8d46adbfd9..850381f7fb0 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs @@ -7,6 +7,7 @@ pub fn target() -> Target { data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), options: TargetOptions { + features: "+outline-atomics".to_string(), mcount: "\u{1}_mcount".to_string(), max_atomic_width: Some(128), supported_sanitizers: SanitizerSet::ADDRESS diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs index 8522405f61f..1c931d5a705 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs @@ -8,6 +8,7 @@ pub fn target() -> Target { arch: "aarch64".to_string(), options: TargetOptions { abi: "ilp32".to_string(), + features: "+outline-atomics".to_string(), max_atomic_width: Some(128), mcount: "\u{1}_mcount".to_string(), ..super::linux_gnu_base::opts() diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs index 6a16b4ce419..0770f3496c2 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs @@ -9,6 +9,10 @@ pub fn target() -> Target { pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), - options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base }, + options: TargetOptions { + features: "+outline-atomics".to_string(), + mcount: "\u{1}_mcount".to_string(), + ..base + }, } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5d17693dc08..a9125b9fd22 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1838,7 +1838,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"), post.len() - 4, ) - } else if post.len() > 1 || (post.len() == 1 && post[0].contains("\n")) { + } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),) } else if post.len() == 1 { format!(": `{}`", post[0]) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 428873b8d3d..8f247184e88 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -748,6 +748,9 @@ fn vtable_trait_first_method_offset<'tcx>( ) -> usize { let (trait_to_be_found, trait_owning_vtable) = key; + // #90177 + let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found); + let vtable_segment_callback = { let mut vtable_base = 0; @@ -757,7 +760,7 @@ fn vtable_trait_first_method_offset<'tcx>( vtable_base += COMMON_VTABLE_ENTRIES.len(); } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - if trait_ref == trait_to_be_found { + if tcx.erase_regions(trait_ref) == trait_to_be_found_erased { return ControlFlow::Break(vtable_base); } vtable_base += util::count_own_vtable_entries(tcx, trait_ref); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index db8a6d96204..b8c66931cbe 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1734,7 +1734,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( ty: ret_type, }); - confirm_param_env_candidate(selcx, obligation, predicate, false) + confirm_param_env_candidate(selcx, obligation, predicate, true) } fn confirm_param_env_candidate<'cx, 'tcx>( @@ -1754,8 +1754,18 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ); let cache_projection = cache_entry.projection_ty; - let obligation_projection = obligation.predicate; let mut nested_obligations = Vec::new(); + let obligation_projection = obligation.predicate; + let obligation_projection = ensure_sufficient_stack(|| { + normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation_projection, + &mut nested_obligations, + ) + }); let cache_projection = if potentially_unnormalized_candidate { ensure_sufficient_stack(|| { normalize_with_depth_to( @@ -1771,6 +1781,8 @@ fn confirm_param_env_candidate<'cx, 'tcx>( cache_projection }; + debug!(?cache_projection, ?obligation_projection); + match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 84721922c8d..2f1f7971a79 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -620,23 +620,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("closure candidate for non-closure {:?}", obligation), }; + let obligation_predicate = obligation.predicate.to_poly_trait_ref(); + let Normalized { value: obligation_predicate, mut obligations } = + ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation_predicate, + ) + }); + let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); - let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { - normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_ref, - ) - }); + let Normalized { value: trait_ref, obligations: trait_ref_obligations } = + ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_ref, + ) + }); debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations"); + obligations.extend(trait_ref_obligations); obligations.extend(self.confirm_poly_trait_refs( obligation.cause.clone(), obligation.param_env, - obligation.predicate.to_poly_trait_ref(), + obligation_predicate, trait_ref, )?); @@ -948,52 +962,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tail_field_ty = tcx.type_of(tail_field.did); let mut unsizing_params = GrowableBitSet::new_empty(); - if tcx.features().relaxed_struct_unsize { - for arg in tail_field_ty.walk(tcx) { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.insert(i); - } - } - - // Ensure none of the other fields mention the parameters used - // in unsizing. - for field in prefix_fields { - for arg in tcx.type_of(field.did).walk(tcx) { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.remove(i); - } - } + for arg in tail_field_ty.walk(tcx) { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); } + } - if unsizing_params.is_empty() { - return Err(Unimplemented); - } - } else { - let mut found = false; - for arg in tail_field_ty.walk(tcx) { + // Ensure none of the other fields mention the parameters used + // in unsizing. + for field in prefix_fields { + for arg in tcx.type_of(field.did).walk(tcx) { if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.insert(i); - found = true; + unsizing_params.remove(i); } } - if !found { - return Err(Unimplemented); - } + } - // Ensure none of the other fields mention the parameters used - // in unsizing. - // FIXME(eddyb) cache this (including computing `unsizing_params`) - // by putting it in a query; it would only need the `DefId` as it - // looks at declared field types, not anything substituted. - for field in prefix_fields { - for arg in tcx.type_of(field.did).walk(tcx) { - if let Some(i) = maybe_unsizing_param_idx(arg) { - if unsizing_params.contains(i) { - return Err(Unimplemented); - } - } - } - } + if unsizing_params.is_empty() { + return Err(Unimplemented); } // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`. diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 5befe44802f..84327a2880e 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -344,7 +344,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "reorder the arguments: {}: `<{}>`", param_types_present .into_iter() - .map(|ord| format!("{}s", ord.to_string())) + .map(|ord| format!("{}s", ord)) .collect::<Vec<String>>() .join(", then "), ordered_params diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 230a576046a..86d4e4d2b11 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -103,7 +103,7 @@ macro_rules! ignore_err { }; } -trait OutlivesEnvironmentExt<'tcx> { +pub(crate) trait OutlivesEnvironmentExt<'tcx> { fn add_implied_bounds( &mut self, infcx: &InferCtxt<'a, 'tcx>, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 9c7b0b2cacb..774d8078e52 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -86,18 +86,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Intermediate format to store the hir_id pointing to the use that resulted in the /// corresponding place being captured and a String which contains the captured value's /// name (i.e: a.b.c) -type CapturesInfo = (Option<hir::HirId>, String); +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum UpvarMigrationInfo { + /// We previously captured all of `x`, but now we capture some sub-path. + CapturingPrecise { source_expr: Option<hir::HirId>, var_name: String }, + CapturingNothing { + // where the variable appears in the closure (but is not captured) + use_span: Span, + }, +} + +/// Reasons that we might issue a migration warning. +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct MigrationWarningReason { + /// When we used to capture `x` in its entirety, we implemented the auto-trait(s) + /// in this vec, but now we don't. + auto_traits: Vec<&'static str>, + + /// When we used to capture `x` in its entirety, we would execute some destructors + /// at a different time. + drop_order: bool, +} + +impl MigrationWarningReason { + fn migration_message(&self) -> String { + let base = "changes to closure capture in Rust 2021 will affect"; + if !self.auto_traits.is_empty() && self.drop_order { + format!("{} drop order and which traits the closure implements", base) + } else if self.drop_order { + format!("{} drop order", base) + } else { + format!("{} which traits the closure implements", base) + } + } +} -/// Intermediate format to store information needed to generate migration lint. The tuple -/// contains the hir_id pointing to the use that resulted in the -/// corresponding place being captured, a String which contains the captured value's -/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that -/// capture -type MigrationNeededForCapture = (Option<hir::HirId>, String, String); +/// Intermediate format to store information needed to generate a note in the migration lint. +struct MigrationLintNote { + captures_info: UpvarMigrationInfo, + + /// reasons why migration is needed for this capture + reason: MigrationWarningReason, +} /// Intermediate format to store the hir id of the root variable and a HashSet containing /// information on why the root variable should be fully captured -type MigrationDiagnosticInfo = (hir::HirId, Vec<MigrationNeededForCapture>); +struct NeededMigration { + var_hir_id: hir::HirId, + diagnostics_info: Vec<MigrationLintNote>, +} struct InferBorrowKindVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -707,47 +744,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_head_span, |lint| { let mut diagnostics_builder = lint.build( - format!( - "changes to closure capture in Rust 2021 will affect {}", - reasons - ) - .as_str(), + &reasons.migration_message(), ); - for (var_hir_id, diagnostics_info) in need_migrations.iter() { + for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { // Labels all the usage of the captured variable and why they are responsible // for migration being needed - for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() { - if let Some(captured_hir_id) = captured_hir_id { - let cause_span = self.tcx.hir().span(*captured_hir_id); - diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", - self.tcx.hir().name(*var_hir_id), - captured_name, - )); + for lint_note in diagnostics_info.iter() { + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { + let cause_span = self.tcx.hir().span(*capture_expr_id); + diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", + self.tcx.hir().name(*var_hir_id), + captured_name, + )); + } + UpvarMigrationInfo::CapturingNothing { use_span } => { + diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", + self.tcx.hir().name(*var_hir_id), + )); + } + + _ => { } } // Add a label pointing to where a captured variable affected by drop order // is dropped - if reasons.contains("drop order") { + if lint_note.reason.drop_order { let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); - diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - self.tcx.hir().name(*var_hir_id), - captured_name, - )); + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", + self.tcx.hir().name(*var_hir_id), + captured_name, + )); + } + UpvarMigrationInfo::CapturingNothing { use_span: _ } => { + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", + v = self.tcx.hir().name(*var_hir_id), + )); + } + } } // Add a label explaining why a closure no longer implements a trait - if reasons.contains("trait implementation") { - let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1]; - - diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}", - missing_trait, - self.tcx.hir().name(*var_hir_id), - missing_trait, - missing_trait, - captured_name, - missing_trait, - )); + for &missing_trait in &lint_note.reason.auto_traits { + // not capturing something anymore cannot cause a trait to fail to be implemented: + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { + let var_name = self.tcx.hir().name(*var_hir_id); + diagnostics_builder.span_label(closure_head_span, format!("\ + in Rust 2018, this closure implements {missing_trait} \ + as `{var_name}` implements {missing_trait}, but in Rust 2021, \ + this closure will no longer implement {missing_trait} \ + because `{var_name}` is not fully captured \ + and `{captured_name}` does not implement {missing_trait}")); + } + + // Cannot happen: if we don't capture a variable, we impl strictly more traits + UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), + } } } } @@ -840,25 +896,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Combines all the reasons for 2229 migrations fn compute_2229_migrations_reasons( &self, - auto_trait_reasons: FxHashSet<&str>, - drop_reason: bool, - ) -> String { - let mut reasons = String::new(); - - if !auto_trait_reasons.is_empty() { - reasons = format!( - "{} trait implementation for closure", - auto_trait_reasons.clone().into_iter().collect::<Vec<&str>>().join(", ") - ); - } + auto_trait_reasons: FxHashSet<&'static str>, + drop_order: bool, + ) -> MigrationWarningReason { + let mut reasons = MigrationWarningReason::default(); - if !auto_trait_reasons.is_empty() && drop_reason { - reasons = format!("{} and ", reasons); + for auto_trait in auto_trait_reasons { + reasons.auto_traits.push(auto_trait); } - if drop_reason { - reasons = format!("{}drop order", reasons); - } + reasons.drop_order = drop_order; reasons } @@ -874,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, - ) -> Option<FxHashMap<CapturesInfo, FxHashSet<&str>>> { + ) -> Option<FxHashMap<UpvarMigrationInfo, FxHashSet<&'static str>>> { let auto_traits_def_id = vec![ self.tcx.lang_items().clone_trait(), self.tcx.lang_items().sync_trait(), @@ -963,7 +1010,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !capture_problems.is_empty() { problematic_captures.insert( - (capture.info.path_expr_id, capture.to_string(self.tcx)), + UpvarMigrationInfo::CapturingPrecise { + source_expr: capture.info.path_expr_id, + var_name: capture.to_string(self.tcx), + }, capture_problems, ); } @@ -986,6 +1036,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This function only returns a HashSet of CapturesInfo for significant drops. If there /// are no significant drops than None is returned + #[instrument(level = "debug", skip(self))] fn compute_2229_migrations_for_drop( &self, closure_def_id: DefId, @@ -993,25 +1044,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> Option<FxHashSet<CapturesInfo>> { + ) -> Option<FxHashSet<UpvarMigrationInfo>> { let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) { + debug!("does not have significant drop"); return None; } let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else { // The upvar is mentioned within the closure but no path starting from it is - // used. + // used. This occurs when you have (e.g.) + // + // ``` + // let x = move || { + // let _ = y; + // }); + // ``` + debug!("no path starting from it is used"); + match closure_clause { // Only migrate if closure is a move closure - hir::CaptureBy::Value => return Some(FxHashSet::default()), + hir::CaptureBy::Value => { + let mut diagnostics_info = FxHashSet::default(); + let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); + let upvar = upvars[&var_hir_id]; + diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); + return Some(diagnostics_info); + } hir::CaptureBy::Ref => {} } return None; }; + debug!(?root_var_min_capture_list); let mut projections_list = Vec::new(); let mut diagnostics_info = FxHashSet::default(); @@ -1021,19 +1088,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only care about captures that are moved into the closure ty::UpvarCapture::ByValue(..) => { projections_list.push(captured_place.place.projections.as_slice()); - diagnostics_info.insert(( - captured_place.info.path_expr_id, - captured_place.to_string(self.tcx), - )); + diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { + source_expr: captured_place.info.path_expr_id, + var_name: captured_place.to_string(self.tcx), + }); } ty::UpvarCapture::ByRef(..) => {} } } + debug!(?projections_list); + debug!(?diagnostics_info); + let is_moved = !projections_list.is_empty(); + debug!(?is_moved); let is_not_completely_captured = root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty()); + debug!(?is_not_completely_captured); if is_moved && is_not_completely_captured @@ -1066,15 +1138,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String /// containing the reason why root variables whose HirId is contained in the vector should /// be captured + #[instrument(level = "debug", skip(self))] fn compute_2229_migrations( &self, closure_def_id: DefId, closure_span: Span, closure_clause: hir::CaptureBy, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - ) -> (Vec<MigrationDiagnosticInfo>, String) { + ) -> (Vec<NeededMigration>, MigrationWarningReason) { let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else { - return (Vec::new(), String::new()); + return (Vec::new(), MigrationWarningReason::default()); }; let mut need_migrations = Vec::new(); @@ -1083,7 +1156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Perform auto-trait analysis for (&var_hir_id, _) in upvars.iter() { - let mut responsible_captured_hir_ids = Vec::new(); + let mut diagnostics_info = Vec::new(); let auto_trait_diagnostic = if let Some(diagnostics_info) = self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) @@ -1115,34 +1188,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut capture_diagnostic = capture_diagnostic.into_iter().collect::<Vec<_>>(); capture_diagnostic.sort(); - for captured_info in capture_diagnostic.iter() { + for captures_info in capture_diagnostic { // Get the auto trait reasons of why migration is needed because of that capture, if there are any let capture_trait_reasons = - if let Some(reasons) = auto_trait_diagnostic.get(captured_info) { + if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) { reasons.clone() } else { FxHashSet::default() }; // Check if migration is needed because of drop reorder as a result of that capture - let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info); + let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_info); // Combine all the reasons of why the root variable should be captured as a result of // auto trait implementation issues auto_trait_migration_reasons.extend(capture_trait_reasons.clone()); - responsible_captured_hir_ids.push(( - captured_info.0, - captured_info.1.clone(), - self.compute_2229_migrations_reasons( + diagnostics_info.push(MigrationLintNote { + captures_info, + reason: self.compute_2229_migrations_reasons( capture_trait_reasons, capture_drop_reorder_reason, ), - )); + }); } - if !capture_diagnostic.is_empty() { - need_migrations.push((var_hir_id, responsible_captured_hir_ids)); + if !diagnostics_info.is_empty() { + need_migrations.push(NeededMigration { var_hir_id, diagnostics_info }); } } ( @@ -2087,6 +2159,7 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol { tcx.hir().name(var_hir_id) } +#[instrument(level = "debug", skip(tcx))] fn should_do_rust_2021_incompatible_closure_captures_analysis( tcx: TyCtxt<'_>, closure_id: hir::HirId, @@ -2102,10 +2175,12 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis( /// - s2: Comma separated names of the variables being migrated. fn migration_suggestion_for_2229( tcx: TyCtxt<'_>, - need_migrations: &Vec<MigrationDiagnosticInfo>, + need_migrations: &Vec<NeededMigration>, ) -> (String, String) { - let need_migrations_variables = - need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::<Vec<_>>(); + let need_migrations_variables = need_migrations + .iter() + .map(|NeededMigration { var_hir_id: v, .. }| var_name(tcx, *v)) + .collect::<Vec<_>>(); let migration_ref_concat = need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::<Vec<_>>().join(", "); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 30aab38b1eb..06bfc427bba 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,3 +1,4 @@ +use crate::check::regionck::OutlivesEnvironmentExt; use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; @@ -11,16 +12,21 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ParItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::outlives::obligations::TypeOutlives; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, + self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, + WithConstness, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; use std::convert::TryInto; @@ -253,6 +259,364 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { .emit(); } } + + check_gat_where_clauses(tcx, trait_item, encl_trait_def_id); +} + +/// Require that the user writes where clauses on GATs for the implicit +/// outlives bounds involving trait parameters in trait functions and +/// lifetimes passed as GAT substs. See `self-outlives-lint` test. +/// +/// This trait will be our running example. We are currently WF checking the `Item` item... +/// +/// ```rust +/// trait LendingIterator { +/// type Item<'me>; // <-- WF checking this trait item +/// +/// fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; +/// } +/// ``` +fn check_gat_where_clauses( + tcx: TyCtxt<'_>, + trait_item: &hir::TraitItem<'_>, + encl_trait_def_id: DefId, +) { + let item = tcx.associated_item(trait_item.def_id); + // If the current trait item isn't a type, it isn't a GAT + if !matches!(item.kind, ty::AssocKind::Type) { + return; + } + let generics: &ty::Generics = tcx.generics_of(trait_item.def_id); + // If the current associated type doesn't have any (own) params, it's not a GAT + // FIXME(jackh726): we can also warn in the more general case + if generics.params.len() == 0 { + return; + } + let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id); + let mut clauses: Option<FxHashSet<ty::Predicate<'_>>> = None; + // For every function in this trait... + // In our example, this would be the `next` method + for item in + associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn)) + { + // The clauses we that we would require from this function + let mut function_clauses = FxHashSet::default(); + + let id = hir::HirId::make_owner(item.def_id.expect_local()); + let param_env = tcx.param_env(item.def_id.expect_local()); + + let sig = tcx.fn_sig(item.def_id); + // Get the signature using placeholders. In our example, this would + // convert the late-bound 'a into a free region. + let sig = tcx.liberate_late_bound_regions(item.def_id, sig); + // Collect the arguments that are given to this GAT in the return type + // of the function signature. In our example, the GAT in the return + // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments. + let (regions, types) = + GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output()); + + // If both regions and types are empty, then this GAT isn't in the + // return type, and we shouldn't try to do clause analysis + // (particularly, doing so would end up with an empty set of clauses, + // since the current method would require none, and we take the + // intersection of requirements of all methods) + if types.is_empty() && regions.is_empty() { + continue; + } + + // The types we can assume to be well-formed. In our example, this + // would be &'a mut Self, from the first argument. + let mut wf_tys = FxHashSet::default(); + wf_tys.extend(sig.inputs()); + + // For each region argument (e.g., 'a in our example), check for a + // relationship to the type arguments (e.g., Self). If there is an + // outlives relationship (`Self: 'a`), then we want to ensure that is + // reflected in a where clause on the GAT itself. + for (region, region_idx) in ®ions { + for (ty, ty_idx) in &types { + // In our example, requires that Self: 'a + if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) { + debug!(?ty_idx, ?region_idx); + debug!("required clause: {} must outlive {}", ty, region); + // Translate into the generic parameters of the GAT. In + // our example, the type was Self, which will also be + // Self in the GAT. + let ty_param = generics.param_at(*ty_idx, tcx); + let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy { + index: ty_param.index, + name: ty_param.name, + })); + // Same for the region. In our example, 'a corresponds + // to the 'me parameter. + let region_param = generics.param_at(*region_idx, tcx); + let region_param = + tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { + def_id: region_param.def_id, + index: region_param.index, + name: region_param.name, + })); + // The predicate we expect to see. (In our example, + // `Self: 'me`.) + let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( + ty_param, + region_param, + )); + let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); + function_clauses.insert(clause); + } + } + } + + // For each region argument (e.g., 'a in our example), also check for a + // relationship to the other region arguments. If there is an + // outlives relationship, then we want to ensure that is + // reflected in a where clause on the GAT itself. + for (region_a, region_a_idx) in ®ions { + for (region_b, region_b_idx) in ®ions { + if region_a == region_b { + continue; + } + + if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) { + debug!(?region_a_idx, ?region_b_idx); + debug!("required clause: {} must outlive {}", region_a, region_b); + // Translate into the generic parameters of the GAT. + let region_a_param = generics.param_at(*region_a_idx, tcx); + let region_a_param = + tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { + def_id: region_a_param.def_id, + index: region_a_param.index, + name: region_a_param.name, + })); + // Same for the region. + let region_b_param = generics.param_at(*region_b_idx, tcx); + let region_b_param = + tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { + def_id: region_b_param.def_id, + index: region_b_param.index, + name: region_b_param.name, + })); + // The predicate we expect to see. + let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + region_a_param, + region_b_param, + )); + let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); + function_clauses.insert(clause); + } + } + } + + // Imagine we have: + // ``` + // trait Foo { + // type Bar<'me>; + // fn gimme(&self) -> Self::Bar<'_>; + // fn gimme_default(&self) -> Self::Bar<'static>; + // } + // ``` + // We only want to require clauses on `Bar` that we can prove from *all* functions (in this + // case, `'me` can be `static` from `gimme_default`) + match clauses.as_mut() { + Some(clauses) => { + clauses.drain_filter(|p| !function_clauses.contains(p)); + } + None => { + clauses = Some(function_clauses); + } + } + } + + // If there are any missing clauses, emit an error + let mut clauses = clauses.unwrap_or_default(); + debug!(?clauses); + if !clauses.is_empty() { + let written_predicates: ty::GenericPredicates<'_> = + tcx.explicit_predicates_of(trait_item.def_id); + let mut clauses: Vec<_> = clauses + .drain_filter(|clause| { + written_predicates.predicates.iter().find(|p| &p.0 == clause).is_none() + }) + .map(|clause| format!("{}", clause)) + .collect(); + // We sort so that order is predictable + clauses.sort(); + if !clauses.is_empty() { + let mut err = tcx.sess.struct_span_err( + trait_item.span, + &format!("Missing required bounds on {}", trait_item.ident), + ); + + let suggestion = format!( + "{} {}", + if !trait_item.generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + clauses.join(", "), + ); + err.span_suggestion( + trait_item.generics.where_clause.tail_span_for_suggestion(), + "add the required where clauses", + suggestion, + Applicability::MachineApplicable, + ); + + err.emit() + } + } +} + +// FIXME(jackh726): refactor some of the shared logic between the two functions below + +/// Given a known `param_env` and a set of well formed types, can we prove that +/// `ty` outlives `region`. +fn ty_known_to_outlive<'tcx>( + tcx: TyCtxt<'tcx>, + id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + wf_tys: &FxHashSet<Ty<'tcx>>, + ty: Ty<'tcx>, + region: ty::Region<'tcx>, +) -> bool { + // Unfortunately, we have to use a new `InferCtxt` each call, because + // region constraints get added and solved there and we need to test each + // call individually. + tcx.infer_ctxt().enter(|infcx| { + let mut outlives_environment = OutlivesEnvironment::new(param_env); + outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); + outlives_environment.save_implied_bounds(id); + let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap(); + + let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation); + + let sup_type = ty; + let sub_region = region; + + let origin = SubregionOrigin::from_obligation_cause(&cause, || { + infer::RelateParamBound(cause.span, sup_type, None) + }); + + let outlives = &mut TypeOutlives::new( + &infcx, + tcx, + ®ion_bound_pairs, + Some(infcx.tcx.lifetimes.re_root_empty), + param_env, + ); + outlives.type_must_outlive(origin, sup_type, sub_region); + + let errors = infcx.resolve_regions( + id.expect_owner().to_def_id(), + &outlives_environment, + RegionckMode::default(), + ); + + debug!(?errors, "errors"); + + // If we were able to prove that the type outlives the region without + // an error, it must be because of the implied or explicit bounds... + errors.is_empty() + }) +} + +fn region_known_to_outlive<'tcx>( + tcx: TyCtxt<'tcx>, + id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + wf_tys: &FxHashSet<Ty<'tcx>>, + region_a: ty::Region<'tcx>, + region_b: ty::Region<'tcx>, +) -> bool { + // Unfortunately, we have to use a new `InferCtxt` each call, because + // region constraints get added and solved there and we need to test each + // call individually. + tcx.infer_ctxt().enter(|infcx| { + let mut outlives_environment = OutlivesEnvironment::new(param_env); + outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); + outlives_environment.save_implied_bounds(id); + + let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation); + + let origin = SubregionOrigin::from_obligation_cause(&cause, || { + infer::RelateRegionParamBound(cause.span) + }); + + use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; + (&infcx).push_sub_region_constraint(origin, region_a, region_b); + + let errors = infcx.resolve_regions( + id.expect_owner().to_def_id(), + &outlives_environment, + RegionckMode::default(), + ); + + debug!(?errors, "errors"); + + // If we were able to prove that the type outlives the region without + // an error, it must be because of the implied or explicit bounds... + errors.is_empty() + }) +} + +/// TypeVisitor that looks for uses of GATs like +/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into +/// the two vectors, `regions` and `types` (depending on their kind). For each +/// parameter `Pi` also track the index `i`. +struct GATSubstCollector<'tcx> { + tcx: TyCtxt<'tcx>, + gat: DefId, + // Which region appears and which parameter index its subsituted for + regions: FxHashSet<(ty::Region<'tcx>, usize)>, + // Which params appears and which parameter index its subsituted for + types: FxHashSet<(Ty<'tcx>, usize)>, +} + +impl<'tcx> GATSubstCollector<'tcx> { + fn visit<T: TypeFoldable<'tcx>>( + tcx: TyCtxt<'tcx>, + gat: DefId, + t: T, + ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { + let mut visitor = GATSubstCollector { + tcx, + gat, + regions: FxHashSet::default(), + types: FxHashSet::default(), + }; + t.visit_with(&mut visitor); + (visitor.regions, visitor.types) + } +} + +impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + match t.kind() { + ty::Projection(p) if p.item_def_id == self.gat => { + for (idx, subst) in p.substs.iter().enumerate() { + match subst.unpack() { + GenericArgKind::Lifetime(lt) => { + self.regions.insert((lt, idx)); + } + GenericArgKind::Type(t) => { + self.types.insert((t, idx)); + } + _ => {} + } + } + } + _ => {} + } + t.super_visit_with(self) + } + + fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> { + Some(self.tcx) + } } fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 96211be8cdc..a6ea8abdf3f 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -772,7 +772,7 @@ fn infer_placeholder_type<'a>( } else { err.span_note( tcx.hir().body(body_id).value.span, - &format!("however, the inferred type `{}` cannot be named", ty.to_string()), + &format!("however, the inferred type `{}` cannot be named", ty), ); } } @@ -796,7 +796,7 @@ fn infer_placeholder_type<'a>( } else { diag.span_note( tcx.hir().body(body_id).value.span, - &format!("however, the inferred type `{}` cannot be named", ty.to_string()), + &format!("however, the inferred type `{}` cannot be named", ty), ); } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 017e7ad8ca7..f90cfb88491 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -70,6 +70,7 @@ This API is completely unstable and subject to change. #![feature(never_type)] #![feature(slice_partition_dedup)] #![feature(control_flow_enum)] +#![feature(hash_drain_filter)] #![recursion_limit = "256"] #[macro_use] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 34d2cfc8e2c..5dda7bfa37c 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -104,6 +104,7 @@ #![feature(extend_one)] #![feature(fmt_internals)] #![feature(fn_traits)] +#![feature(inherent_ascii_escape)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_zip)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c0ca068de9c..4fb2f0c8530 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -318,6 +318,8 @@ impl<T: ?Sized> !marker::Sync for Rc<T> {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {} +#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")] +impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for Rc<T> {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {} diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 860f21085f3..ae730be0d25 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -108,6 +108,8 @@ pub use core::slice::ArrayChunks; pub use core::slice::ArrayChunksMut; #[unstable(feature = "array_windows", issue = "75027")] pub use core::slice::ArrayWindows; +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +pub use core::slice::EscapeAscii; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[stable(feature = "from_ref", since = "1.28.0")] @@ -130,6 +132,8 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; +#[stable(feature = "split_inclusive", since = "1.51.0")] +pub use core::slice::{SplitInclusive, SplitInclusiveMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 3b875477df3..104f5556566 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -46,7 +46,7 @@ pub use core::str::pattern; pub use core::str::EncodeUtf16; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] pub use core::str::SplitAsciiWhitespace; -#[stable(feature = "split_inclusive", since = "1.53.0")] +#[stable(feature = "split_inclusive", since = "1.51.0")] pub use core::str::SplitInclusive; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::SplitWhitespace; diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 18ebf1cbb10..0c00db5fdf3 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -94,7 +94,13 @@ depending on the target pointer size. } macro_rules! widening_impl { - ($SelfT:ty, $WideT:ty, $BITS:literal) => { + ($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => { + widening_impl!($SelfT, $WideT, $BITS, ""); + }; + ($SelfT:ty, $WideT:ty, $BITS:literal, signed) => { + widening_impl!($SelfT, $WideT, $BITS, "# //"); + }; + ($SelfT:ty, $WideT:ty, $BITS:literal, $AdaptiveTestPrefix:literal) => { /// Calculates the complete product `self * rhs` without the possibility to overflow. /// /// This returns the low-order (wrapping) bits and the high-order (overflow) bits @@ -148,6 +154,33 @@ macro_rules! widening_impl { /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); + #[doc = concat!($AdaptiveTestPrefix, "assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(0, ", stringify!($SelfT), "::MAX));" + )] + /// ``` + /// + /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), + /// except that it gives the value of the overflow instead of just whether one happened: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// let r = u8::carrying_mul(7, 13, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); + /// let r = u8::carrying_mul(13, 42, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); + /// ``` + /// + /// The value of the first field in the returned tuple matches what you'd get + /// by combining the [`wrapping_mul`](Self::wrapping_mul) and + /// [`wrapping_add`](Self::wrapping_add) methods: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!( + /// 789_u16.carrying_mul(456, 123).0, + /// 789_u16.wrapping_mul(456).wrapping_add(123), + /// ); /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] @@ -168,33 +201,33 @@ macro_rules! widening_impl { #[lang = "i8"] impl i8 { - widening_impl! { i8, i16, 8 } int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } + widening_impl! { i8, i16, 8, signed } } #[lang = "i16"] impl i16 { - widening_impl! { i16, i32, 16 } int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } + widening_impl! { i16, i32, 16, signed } } #[lang = "i32"] impl i32 { - widening_impl! { i32, i64, 32 } int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } + widening_impl! { i32, i64, 32, signed } } #[lang = "i64"] impl i64 { - widening_impl! { i64, i128, 64 } int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } + widening_impl! { i64, i128, 64, signed } } #[lang = "i128"] @@ -212,31 +245,31 @@ impl i128 { #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { - widening_impl! { isize, i32, 16 } int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + widening_impl! { isize, i32, 16, signed } } #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { - widening_impl! { isize, i64, 32 } int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + widening_impl! { isize, i64, 32, signed } } #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - widening_impl! { isize, i128, 64 } int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", - "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + widening_impl! { isize, i128, 64, signed } } /// If 6th bit set ascii is upper case. @@ -244,9 +277,9 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000; #[lang = "u8"] impl u8 { - widening_impl! { u8, u16, 8 } uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } + widening_impl! { u8, u16, 8, unsigned } /// Checks if the value is within the ASCII range. /// @@ -793,26 +826,26 @@ impl u8 { #[lang = "u16"] impl u16 { - widening_impl! { u16, u32, 16 } uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } + widening_impl! { u16, u32, 16, unsigned } } #[lang = "u32"] impl u32 { - widening_impl! { u32, u64, 32 } uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } + widening_impl! { u32, u64, 32, unsigned } } #[lang = "u64"] impl u64 { - widening_impl! { u64, u128, 64 } uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", ""} + widening_impl! { u64, u128, 64, unsigned } } #[lang = "u128"] @@ -830,29 +863,29 @@ impl u128 { #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { - widening_impl! { usize, u32, 16 } uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + widening_impl! { usize, u32, 16, unsigned } } #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { - widening_impl! { usize, u64, 32 } uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + widening_impl! { usize, u64, 32, unsigned } } #[cfg(target_pointer_width = "64")] #[lang = "usize"] impl usize { - widening_impl! { usize, u128, 64 } uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + widening_impl! { usize, u128, 64, unsigned } } /// A classification of floating point numbers. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 691d0891b14..a15eabf7966 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1504,6 +1504,8 @@ macro_rules! uint_impl { /// additional bit of overflow. This allows for chaining together multiple additions /// to create "big integers" which represent larger values. /// + #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")] + /// /// # Examples /// /// Basic usage @@ -1513,7 +1515,20 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (0, true));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")] + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ", + "(", stringify!($SelfT), "::MAX, true));" + )] + /// ``` + /// + /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add): + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")] /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 3a06cd04ab1..9d673d69687 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1074,7 +1074,11 @@ impl Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); } - Literal(bridge::client::Literal::float(&n.to_string())) + let mut repr = n.to_string(); + if !repr.contains('.') { + repr.push_str(".0"); + } + Literal(bridge::client::Literal::float(&repr)) } /// Creates a new suffixed floating-point literal. @@ -1115,7 +1119,11 @@ impl Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); } - Literal(bridge::client::Literal::float(&n.to_string())) + let mut repr = n.to_string(); + if !repr.contains('.') { + repr.push_str(".0"); + } + Literal(bridge::client::Literal::float(&repr)) } /// Creates a new suffixed floating-point literal. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 6bc445c6f2b..248ecdf4bef 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 30eeac14b43..01392ffab79 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -165,7 +165,14 @@ pub use core::ffi::c_void; #[unstable(feature = "c_size_t", issue = "88345")] pub type c_size_t = usize; -/// Equivalent to C's `ssize_t` type, from `stddef.h` (or `cstddef` for C++). +/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++). +/// +/// This type is currently always [`isize`], however in the future there may be +/// platforms where this is not the case. +#[unstable(feature = "c_size_t", issue = "88345")] +pub type c_ptrdiff_t = isize; + +/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type. /// /// This type is currently always [`isize`], however in the future there may be /// platforms where this is not the case. diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs index 4feb9c5a6d7..bb9fa54d02e 100644 --- a/library/std/src/sys/itron/thread.rs +++ b/library/std/src/sys/itron/thread.rs @@ -347,6 +347,6 @@ unsafe fn terminate_and_delete_current_task() -> ! { unsafe { crate::hint::unreachable_unchecked() }; } -pub fn available_concurrency() -> io::Result<crate::num::NonZeroUsize> { +pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> { super::unsupported() } diff --git a/library/std/src/sys/windows/thread_local_dtor.rs b/library/std/src/sys/windows/thread_local_dtor.rs index 7be13bc4b2b..25d1c6e8e87 100644 --- a/library/std/src/sys/windows/thread_local_dtor.rs +++ b/library/std/src/sys/windows/thread_local_dtor.rs @@ -1,4 +1,28 @@ +//! Implements thread-local destructors that are not associated with any +//! particular data. + #![unstable(feature = "thread_local_internals", issue = "none")] #![cfg(target_thread_local)] -pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor; +// Using a per-thread list avoids the problems in synchronizing global state. +#[thread_local] +static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); + +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + DESTRUCTORS.push((t, dtor)); +} + +/// Runs destructors. This should not be called until thread exit. +pub unsafe fn run_keyless_dtors() { + // Drop all the destructors. + // + // Note: While this is potentially an infinite loop, it *should* be + // the case that this loop always terminates because we provide the + // guarantee that a TLS key cannot be set after it is flagged for + // destruction. + while let Some((ptr, dtor)) = DESTRUCTORS.pop() { + (dtor)(ptr); + } + // We're done so free the memory. + DESTRUCTORS = Vec::new(); +} diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index 0bc51114665..ec670238e6f 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -196,6 +196,8 @@ pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c:: unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) { if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH { run_dtors(); + #[cfg(target_thread_local)] + super::thread_local_dtor::run_keyless_dtors(); } // See comments above for what this is doing. Note that we don't need this diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e7944c715ed..2a155ce3117 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1407,6 +1407,15 @@ impl<T> JoinHandle<T> { pub fn join(mut self) -> Result<T> { self.0.join() } + + /// Checks if the the associated thread is still running its main function. + /// + /// This might return `false` for a brief moment after the thread's main + /// function has returned, but before the thread itself has stopped running. + #[unstable(feature = "thread_is_running", issue = "90470")] + pub fn is_running(&self) -> bool { + Arc::strong_count(&self.0.packet.0) > 1 + } } impl<T> AsInner<imp::Thread> for JoinHandle<T> { diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 16ad366fc12..ca0d88135a5 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -2,9 +2,13 @@ use super::Builder; use crate::any::Any; use crate::mem; use crate::result; -use crate::sync::mpsc::{channel, Sender}; +use crate::sync::{ + mpsc::{channel, Sender}, + Arc, Barrier, +}; use crate::thread::{self, ThreadId}; use crate::time::Duration; +use crate::time::Instant; // !!! These tests are dangerous. If something is buggy, they will hang, !!! // !!! instead of exiting cleanly. This might wedge the buildbots. !!! @@ -47,6 +51,36 @@ fn test_run_basic() { } #[test] +fn test_is_running() { + let b = Arc::new(Barrier::new(2)); + let t = thread::spawn({ + let b = b.clone(); + move || { + b.wait(); + 1234 + } + }); + + // Thread is definitely running here, since it's still waiting for the barrier. + assert_eq!(t.is_running(), true); + + // Unblock the barrier. + b.wait(); + + // Now check that t.is_running() becomes false within a reasonable time. + let start = Instant::now(); + while t.is_running() { + assert!(start.elapsed() < Duration::from_secs(2)); + thread::sleep(Duration::from_millis(15)); + } + + // Joining the thread should not block for a significant time now. + let join_time = Instant::now(); + assert_eq!(t.join().unwrap(), 1234); + assert!(join_time.elapsed() < Duration::from_secs(2)); +} + +#[test] fn test_join_panic() { match thread::spawn(move || panic!()).join() { result::Result::Err(_) => (), diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index e2aebee916d..fa23cf26896 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -55,8 +55,8 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> { _stdout: &[u8], _state: &ConsoleTestState, ) -> io::Result<()> { - // Because the testsuit node holds some of the information as attributes, we can't write it - // until all of the tests has ran. Instead of writting every result as they come in, we add + // Because the testsuite node holds some of the information as attributes, we can't write it + // until all of the tests have finished. Instead of writing every result as they come in, we add // them to a Vec and write them all at once when run is complete. let duration = exec_time.map(|t| t.0).unwrap_or_default(); self.results.push((desc.clone(), result.clone(), duration)); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d5656f0f37e..6ba1b1b6036 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -482,6 +482,7 @@ impl<'a> Builder<'a> { doc::RustByExample, doc::RustcBook, doc::CargoBook, + doc::Clippy, doc::EmbeddedBook, doc::EditionGuide, ), diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e9cc7662e63..007ca9f7f5a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -197,7 +197,7 @@ fn copy_self_contained_objects( t!(fs::create_dir_all(&libdir_self_contained)); let mut target_deps = vec![]; - // Copies the CRT objects. + // Copies the libc and CRT objects. // // rustc historically provides a more self-contained installation for musl targets // not requiring the presence of a native musl toolchain. For example, it can fall back @@ -208,7 +208,7 @@ fn copy_self_contained_objects( let srcdir = builder.musl_libdir(target).unwrap_or_else(|| { panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple) }); - for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { + for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { copy_and_stamp( builder, &libdir_self_contained, @@ -235,7 +235,7 @@ fn copy_self_contained_objects( panic!("Target {:?} does not have a \"wasi-root\" key", target.triple) }) .join("lib/wasm32-wasi"); - for &obj in &["crt1-command.o", "crt1-reactor.o"] { + for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] { copy_and_stamp( builder, &libdir_self_contained, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 6f2470b706a..2804e7119fb 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -755,6 +755,7 @@ tool_doc!( "src/tools/rustfmt", ["rustfmt-nightly", "rustfmt-config_proc_macro"], ); +tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 63836654293..2b4b78e8135 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -1,3 +1,15 @@ +# We need recent curl, OpenSSL and CA certificates, so we can download further +# dependencies in the debian:6 image. We use an ubuntu 20.04 image download +# those. +FROM ubuntu:20.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates +WORKDIR /tmp +COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/ +RUN ./download-openssl-curl.sh + # We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other # distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and # SLES 11 SP4 (glibc 2.11, kernel 3.0). @@ -14,8 +26,6 @@ RUN apt-get update && \ apt-get install --allow-unauthenticated -y --no-install-recommends \ automake \ bzip2 \ - ca-certificates \ - curl \ file \ g++ \ g++-multilib \ @@ -34,11 +44,6 @@ RUN apt-get update && \ xz-utils \ zlib1g-dev -# Install new Let's Encrypt root CA certificate and remove the expired one. -COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt -RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf -RUN /usr/sbin/update-ca-certificates - ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig @@ -50,6 +55,7 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/ # static.rust-lang.org. This'll be used to link into libcurl below (and used # later as well), so build a copy of OpenSSL with dynamic libraries into our # generic root. +COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/ RUN ./build-openssl.sh @@ -59,8 +65,13 @@ RUN ./build-openssl.sh # # Note that we also disable a bunch of optional features of curl that we don't # really need. +COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/ -RUN ./build-curl.sh && apt-get remove -y curl +RUN ./build-curl.sh + +# Use up-to-date curl CA bundle +COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem +ENV CURL_CA_BUNDLE /tmp/cacert.pem # binutils < 2.22 has a bug where the 32-bit executables it generates # immediately segfault in Rust, so we need to install our own binutils. diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 7b560aaaaa6..50452349931 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -1,3 +1,15 @@ +# We need recent curl, OpenSSL and CA certificates, so we can download further +# dependencies in the debian:6 image. We use an ubuntu 20.04 image download +# those. +FROM ubuntu:20.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates +WORKDIR /tmp +COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/ +RUN ./download-openssl-curl.sh + # We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other # distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and # SLES 11 SP4 (glibc 2.11, kernel 3.0). @@ -14,8 +26,6 @@ RUN apt-get update && \ apt-get install --allow-unauthenticated -y --no-install-recommends \ automake \ bzip2 \ - ca-certificates \ - curl \ file \ g++ \ g++-multilib \ @@ -34,11 +44,6 @@ RUN apt-get update && \ xz-utils \ zlib1g-dev -# Install new Let's Encrypt root CA certificate and remove the expired one. -COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt -RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf -RUN /usr/sbin/update-ca-certificates - ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig @@ -50,6 +55,7 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/ # static.rust-lang.org. This'll be used to link into libcurl below (and used # later as well), so build a copy of OpenSSL with dynamic libraries into our # generic root. +COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/ RUN ./build-openssl.sh @@ -59,8 +65,13 @@ RUN ./build-openssl.sh # # Note that we also disable a bunch of optional features of curl that we don't # really need. +COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/ -RUN ./build-curl.sh && apt-get remove -y curl +RUN ./build-curl.sh + +# Use up-to-date curl CA bundle +COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem +ENV CURL_CA_BUNDLE /tmp/cacert.pem # binutils < 2.22 has a bug where the 32-bit executables it generates # immediately segfault in Rust, so we need to install our own binutils. diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh index 6efa7897566..88ee96eaa89 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh @@ -3,18 +3,11 @@ set -ex source shared.sh -VERSION=7.66.0 - -# This needs to be downloaded directly from S3, it can't go through the CDN. -# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1 -# (without paying an absurd amount of money). -curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \ - | xz --decompress \ - | tar xf - +tar xJf curl.tar.xz mkdir curl-build cd curl-build -hide_output ../curl-$VERSION/configure \ +hide_output ../curl-*/configure \ --prefix=/rustroot \ --with-ssl=/rustroot \ --disable-sspi \ @@ -35,4 +28,4 @@ hide_output make install cd .. rm -rf curl-build -rm -rf curl-$VERSION +rm -rf curl-* diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh index 34bbe19d2fa..b48b5c4c00a 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh @@ -3,21 +3,14 @@ set -ex source shared.sh -VERSION=1.0.2k +tar xzf openssl.tar.gz -# This needs to be downloaded directly from S3, it can't go through the CDN. -# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1 -# (without paying an absurd amount of money). -URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz - -curl $URL | tar xzf - - -cd openssl-$VERSION +cd openssl-* hide_output ./config --prefix=/rustroot shared -fPIC hide_output make -j$(nproc) hide_output make install cd .. -rm -rf openssl-$VERSION +rm -rf openssl-* # Make the system cert collection available to the new install. ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh new file mode 100755 index 00000000000..ca40a8cf7da --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -ex + +OPENSSL_VERSION=1.0.2k +CURL_VERSION=7.66.0 + +curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz +curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz +curl -f https://curl.se/ca/cacert.pem -o cacert.pem diff --git a/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt b/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt deleted file mode 100644 index b85c8037f6b..00000000000 --- a/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index b1dacf79d26..93b4f435d4d 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -50,7 +50,8 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then # Look for all source files involves in the COPY command copied_files=/tmp/.docker-copied-files.txt rm -f "$copied_files" - for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do + for i in $(sed -n -e '/^COPY --from=/! s/^COPY \(.*\) .*$/\1/p' \ + "$docker_dir/$image/Dockerfile"); do # List the file names find "$script_dir/$i" -type f >> $copied_files done diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 70c57e07fde..de6b52a5e00 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -53,7 +53,7 @@ files_to_extract=( for lib in c cxxrt gcc_s m thr util; do files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*") done -for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat; do +for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat kvm; do files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*") done diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index 3fa91bb51f0..eb181859453 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -1,6 +1,7 @@ # The Rustdoc Book - [What is rustdoc?](what-is-rustdoc.md) +- [How to read rustdoc output](how-to-read-rustdoc.md) - [How to write documentation](how-to-write-documentation.md) - [What to include (and exclude)](what-to-include.md) - [Command-line arguments](command-line-arguments.md) diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md new file mode 100644 index 00000000000..99724d859ee --- /dev/null +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -0,0 +1,107 @@ +# How to read rustdoc output + +Rustdoc's HTML output includes a friendly and useful navigation interface which +makes it easier for users to navigate and understand your code. +This chapter covers the major features of that interface, +and is a great starting point for documentation authors and users alike. + +## Structure + +The `rustdoc` output is divided into three sections. +Along the left side of each page is a quick navigation bar, +which shows contextual information about the current entry. +The rest of the page is taken up by the search interface at the top +and the documentation for the current item below that. + +## The Item Documentation + +The majority of the screen is taken up with the documentation text for the item +currently being viewed. +At the top is some at-a-glance info and controls: + +- the type and name of the item, + such as "Struct `std::time::Duration`", +- a button to copy the item's path to the clipboard, + which is a clipboard item +- a button to collapse or expand the top-level documentation for that item + (`[+]` or `[-]`), +- a link to the source code (`[src]`), + if [configured](the-doc-attribute.html#html_no_source), + and present (the source may not be available if + the documentation was created with `cargo doc --no-deps`), +- and the version in which the item became stable, + if it's a stable item in the standard library. + +Below this is the main documentation for the item, +including a definition or function signature if appropriate, +followed by a list of fields or variants for Rust types. +Finally, the page lists associated functions and trait implementations, +including automatic and blanket implementations that `rustdoc` knows about. + +### Navigation + +Subheadings, variants, fields, and many other things in this documentation +are anchors and can be clicked on and deep-linked to, +which is a great way to communicate exactly what you're talking about. +The typograpical character "§" appears next to lines with anchors on them +when hovered or given keyboard focus. + +## The Navigation Bar + +For example, when looking at documentation for the crate root, +it shows all the crates documented in the documentation bundle, +and quick links to the modules, structs, traits, functions, and macros available +from the current crate. +At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url) +alongside the current crate's name and version, +or the current item whose documentation is being displayed. + +## The Theme Picker and Search Interface + +When viewing `rustdoc`'s output in a browser with JavaScript enabled, +a dynamic interface appears at the top of the page. +To the left is the theme picker, denoted with a paint-brush icon, +and the search interface, help screen, and options appear to the right of that. + +### The Theme Picker + +Clicking on the theme picker provides a list of themes - +by default `ayu`, `light`, and `dark` - +which are available for viewing. + +### The Search Interface + +Typing in the search bar instantly searches the available documentation for +the string entered with a fuzzy matching algorithm that is tolerant of minor +typos. + +By default, the search results give are "In Names", +meaning that the fuzzy match is made against the names of items. +Matching names are shown on the left, and the first few words of their +descriptions are given on the right. +By clicking an item, you will navigate to its particular documentation. + +There are two other sets of results, shown as tabs in the search results pane. +"In Parameters" shows matches for the string in the types of parameters to +functions, and "In Return Types" shows matches in the return types of functions. +Both are very useful when looking for a function whose name you can't quite +bring to mind when you know the type you have or want. + +When typing in the search bar, you can prefix your search term with a type +followed by a colon (such as `mod:`) to restrict the results to just that +kind of item. (The available items are listed in the help popup.) + +### Shortcuts + +Pressing `S` while focused elsewhere on the page will move focus to the +search bar, and pressing `?` shows the help screen, +which includes all these shortcuts and more. +Pressing `T` focuses the theme picker. + +When the search results are focused, +the left and right arrows move between tabs and the up and down arrows move +among the results. +Pressing the enter or return key opens the highlighted result. + +When looking at the documentation for an item, the plus and minus keys expand +and collapse all sections in the document. diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index bd7234522e1..84fc6dcc339 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -257,7 +257,7 @@ unsafe { } println!( - "L1 Cache: {}", + "L0 Cache: {}", ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1) ); ``` @@ -885,5 +885,7 @@ The compiler performs some additional checks on options: - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds). - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited. - You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places. +- On x86, inline assembly must not end with an instruction prefix (such as `LOCK`) that would apply to instructions generated by the compiler. + - The compiler is currently unable to detect this due to the way inline assembly is compiled, but may catch and reject this in the future. > **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 88fffaecb93..56ae43855de 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -789,6 +789,7 @@ impl AttributesExt for [ast::Attribute] { fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> { let sess = tcx.sess; let doc_cfg_active = tcx.features().doc_cfg; + let doc_auto_cfg_active = tcx.features().doc_auto_cfg; fn single<T: IntoIterator>(it: T) -> Option<T::Item> { let mut iter = it.into_iter(); @@ -799,24 +800,26 @@ impl AttributesExt for [ast::Attribute] { Some(item) } - let mut cfg = if doc_cfg_active { + let mut cfg = if doc_cfg_active || doc_auto_cfg_active { let mut doc_cfg = self .iter() .filter(|attr| attr.has_name(sym::doc)) .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new)) .filter(|attr| attr.has_name(sym::cfg)) .peekable(); - if doc_cfg.peek().is_some() { + if doc_cfg.peek().is_some() && doc_cfg_active { doc_cfg .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else { + } else if doc_auto_cfg_active { self.iter() .filter(|attr| attr.has_name(sym::cfg)) .filter_map(|attr| single(attr.meta_item_list()?)) .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) .filter(|cfg| !hidden_cfg.contains(cfg)) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + Cfg::True } } else { Cfg::True diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index f84850c0fe1..cd0f44e5696 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -20,22 +20,28 @@ crate trait DocFolder: Sized { StructItem(mut i) => { let num_fields = i.fields.len(); i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); - i.fields_stripped |= - num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped()); + if !i.fields_stripped { + i.fields_stripped = + num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped()); + } StructItem(i) } UnionItem(mut i) => { let num_fields = i.fields.len(); i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); - i.fields_stripped |= - num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped()); + if !i.fields_stripped { + i.fields_stripped = + num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped()); + } UnionItem(i) } EnumItem(mut i) => { let num_variants = i.variants.len(); i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect(); - i.variants_stripped |= - num_variants != i.variants.len() || i.variants.iter().any(|f| f.is_stripped()); + if !i.variants_stripped { + i.variants_stripped = num_variants != i.variants.len() + || i.variants.iter().any(|f| f.is_stripped()); + } EnumItem(i) } TraitItem(mut i) => { @@ -46,24 +52,42 @@ crate trait DocFolder: Sized { i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect(); ImplItem(i) } - VariantItem(i) => { - let i2 = i.clone(); // this clone is small - match i { - Variant::Struct(mut j) => { - let num_fields = j.fields.len(); - j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); - j.fields_stripped |= num_fields != j.fields.len() + VariantItem(i) => match i { + Variant::Struct(mut j) => { + let num_fields = j.fields.len(); + j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + if !j.fields_stripped { + j.fields_stripped = num_fields != j.fields.len() || j.fields.iter().any(|f| f.is_stripped()); - VariantItem(Variant::Struct(j)) - } - Variant::Tuple(fields) => { - let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); - VariantItem(Variant::Tuple(fields)) } - _ => VariantItem(i2), + VariantItem(Variant::Struct(j)) } - } - x => x, + Variant::Tuple(fields) => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + VariantItem(Variant::Tuple(fields)) + } + Variant::CLike => VariantItem(Variant::CLike), + }, + ExternCrateItem { src: _ } + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | KeywordItem(_) => kind, } } @@ -86,14 +110,12 @@ crate trait DocFolder: Sized { fn fold_crate(&mut self, mut c: Crate) -> Crate { c.module = self.fold_item(c.module).unwrap(); - { - let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; - for (k, mut v) in external_traits { - v.trait_.items = - v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - c.external_traits.borrow_mut().insert(k, v); - } + let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; + for (k, mut v) in external_traits { + v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); + c.external_traits.borrow_mut().insert(k, v); } + c } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index a33bb3479ce..e177a113036 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -270,12 +270,18 @@ struct Decorations { impl Decorations { fn new(info: DecorationInfo) -> Self { - let (starts, ends) = info + // Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end). + let (mut starts, mut ends): (Vec<_>, Vec<_>) = info .0 .into_iter() .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi))) .flatten() .unzip(); + + // Sort the sequences in document order. + starts.sort_by_key(|(lo, _)| *lo); + ends.sort(); + Decorations { starts, ends } } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 76e46fa0aa3..069862efde6 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -461,9 +461,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } - let (mut krate, local_sources, matches) = collect_spans_and_sources( + let (local_sources, matches) = collect_spans_and_sources( tcx, - krate, + &krate, &src_root, include_sources, generate_link_to_definition, @@ -522,7 +522,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { }; if emit_crate { - krate = sources::render(&mut cx, krate)?; + sources::render(&mut cx, &krate)?; } // Build our search index diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f78129050d7..25fef114d95 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -76,7 +76,7 @@ use crate::html::format::{ use crate::html::highlight; use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine}; use crate::html::sources; -use crate::scrape_examples::CallData; +use crate::scrape_examples::{CallData, CallLocation}; use crate::try_none; /// A pair of name and its optional document. @@ -2594,6 +2594,21 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) { id = id ); + // Create a URL to a particular location in a reverse-dependency's source file + let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) { + let (line_lo, line_hi) = loc.call_expr.line_span; + let (anchor, title) = if line_lo == line_hi { + ((line_lo + 1).to_string(), format!("line {}", line_lo + 1)) + } else { + ( + format!("{}-{}", line_lo + 1, line_hi + 1), + format!("lines {}-{}", line_lo + 1, line_hi + 1), + ) + }; + let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor); + (url, title) + }; + // Generate the HTML for a single example, being the title and code block let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool { let contents = match fs::read_to_string(&path) { @@ -2631,15 +2646,7 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) { let (line_lo, line_hi) = loc.call_expr.line_span; let byte_range = (byte_lo - byte_min, byte_hi - byte_min); let line_range = (line_lo - line_min, line_hi - line_min); - let (anchor, line_title) = if line_lo == line_hi { - (format!("{}", line_lo + 1), format!("line {}", line_lo + 1)) - } else { - ( - format!("{}-{}", line_lo + 1, line_hi + 1), - format!("lines {}-{}", line_lo + 1, line_hi + 1), - ) - }; - let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor); + let (line_url, line_title) = link_to_loc(call_data, loc); (byte_range, (line_range, line_url, line_title)) }) @@ -2768,11 +2775,11 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) { if it.peek().is_some() { write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#); it.for_each(|(_, call_data)| { + let (url, _) = link_to_loc(&call_data, &call_data.locations[0]); write!( w, - r#"<li><a href="{root}{url}">{name}</a></li>"#, - root = cx.root_path(), - url = call_data.url, + r#"<li><a href="{url}">{name}</a></li>"#, + url = url, name = call_data.display_name ); }); diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 1a8562d05ea..7803a779727 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -37,21 +37,21 @@ crate enum LinkFromSrc { /// only keep the `lo` and `hi`. crate fn collect_spans_and_sources( tcx: TyCtxt<'_>, - krate: clean::Crate, + krate: &clean::Crate, src_root: &Path, include_sources: bool, generate_link_to_definition: bool, -) -> (clean::Crate, FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) { +) -> (FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) { let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; if include_sources { if generate_link_to_definition { tcx.hir().walk_toplevel_module(&mut visitor); } - let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate); - (krate, sources, visitor.matches) + let sources = sources::collect_local_sources(tcx, src_root, &krate); + (sources, visitor.matches) } else { - (krate, Default::default(), Default::default()) + (Default::default(), Default::default()) } } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9422f84f997..c8e93374e63 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -1,11 +1,11 @@ use crate::clean; use crate::docfs::PathError; use crate::error::Error; -use crate::fold::DocFolder; use crate::html::format::Buffer; use crate::html::highlight; use crate::html::layout; use crate::html::render::{Context, BASIC_KEYWORDS}; +use crate::visit::DocVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; @@ -16,23 +16,25 @@ use std::ffi::OsStr; use std::fs; use std::path::{Component, Path, PathBuf}; -crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result<clean::Crate, Error> { +crate fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> { info!("emitting source files"); + let dst = cx.dst.join("src").join(&*krate.name(cx.tcx()).as_str()); cx.shared.ensure_dir(&dst)?; - let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() }; - Ok(folder.fold_crate(krate)) + + let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() }; + collector.visit_crate(krate); + Ok(()) } crate fn collect_local_sources<'tcx>( tcx: TyCtxt<'tcx>, src_root: &Path, - krate: clean::Crate, -) -> (clean::Crate, FxHashMap<PathBuf, String>) { + krate: &clean::Crate, +) -> FxHashMap<PathBuf, String> { let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root }; - - let krate = lsc.fold_crate(krate); - (krate, lsc.local_sources) + lsc.visit_crate(krate); + lsc.local_sources } struct LocalSourcesCollector<'a, 'tcx> { @@ -42,7 +44,7 @@ struct LocalSourcesCollector<'a, 'tcx> { } fn is_real_and_local(span: clean::Span, sess: &Session) -> bool { - span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE + span.cnum(sess) == LOCAL_CRATE && span.filename(sess).is_real() } impl LocalSourcesCollector<'_, '_> { @@ -54,12 +56,13 @@ impl LocalSourcesCollector<'_, '_> { return; } let filename = span.filename(sess); - let p = match filename { - FileName::Real(ref file) => match file.local_path() { - Some(p) => p.to_path_buf(), - _ => return, - }, - _ => return, + let p = if let FileName::Real(file) = filename { + match file.into_local_path() { + Some(p) => p, + None => return, + } + } else { + return; }; if self.local_sources.contains_key(&*p) { // We've already emitted this source @@ -79,13 +82,11 @@ impl LocalSourcesCollector<'_, '_> { } } -impl DocFolder for LocalSourcesCollector<'_, '_> { - fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> { - self.add_local_source(&item); +impl DocVisitor for LocalSourcesCollector<'_, '_> { + fn visit_item(&mut self, item: &clean::Item) { + self.add_local_source(item); - // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value, - // we could return None here without having to walk the rest of the crate. - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } @@ -98,8 +99,12 @@ struct SourceCollector<'a, 'tcx> { emitted_local_sources: FxHashSet<PathBuf>, } -impl DocFolder for SourceCollector<'_, '_> { - fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> { +impl DocVisitor for SourceCollector<'_, '_> { + fn visit_item(&mut self, item: &clean::Item) { + if !self.cx.include_sources { + return; + } + let tcx = self.cx.tcx(); let span = item.span(tcx); let sess = tcx.sess; @@ -107,7 +112,7 @@ impl DocFolder for SourceCollector<'_, '_> { // If we're not rendering sources, there's nothing to do. // If we're including source files, and we haven't seen this file yet, // then we need to render it out to the filesystem. - if self.cx.include_sources && is_real_and_local(span, sess) { + if is_real_and_local(span, sess) { let filename = span.filename(sess); let span = span.inner(); let pos = sess.source_map().lookup_source_file(span.lo()); @@ -132,9 +137,8 @@ impl DocFolder for SourceCollector<'_, '_> { } }; } - // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value, - // we could return None here without having to walk the rest of the crate. - Some(self.fold_item_recur(item)) + + self.visit_item_recur(item) } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 93cbc0debb9..89a763ef6d7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -156,7 +156,8 @@ h1.fqn > .in-band > a:hover { section hierarchies. */ h2, .top-doc h3, -.top-doc h4 { +.top-doc h4, +.sidebar .others h3 { border-bottom: 1px solid; } h3.code-header { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index c421c6e9dc1..4b55a0a69b6 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -566,6 +566,7 @@ function hideThemeButtonState() { // delayed sidebar rendering. window.initSidebarItems = function(items) { var sidebar = document.getElementsByClassName("sidebar-elems")[0]; + var others; var current = window.sidebarCurrent; function addSidebarCrates(crates) { @@ -594,7 +595,7 @@ function hideThemeButtonState() { li.appendChild(link); ul.appendChild(li); } - sidebar.appendChild(div); + others.appendChild(div); } function block(shortty, longty) { @@ -635,10 +636,14 @@ function hideThemeButtonState() { ul.appendChild(li); } div.appendChild(ul); - sidebar.appendChild(div); + others.appendChild(div); } if (sidebar) { + others = document.createElement("div"); + others.className = "others"; + sidebar.appendChild(others); + var isModule = hasClass(document.body, "mod"); if (!isModule) { block("primitive", "Primitive Types"); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index cead54412bb..9fafea69145 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -108,12 +108,12 @@ data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#} </div> <script src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#} - {%- if layout.scrape_examples_extension -%} - <script src="{{static_root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#} - {%- endif -%} {%- for script in page.static_extra_scripts -%} <script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#} {% endfor %} + {%- if layout.scrape_examples_extension -%} + <script src="{{page.root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#} + {%- endif -%} {%- for script in page.extra_scripts -%} <script src="{{page.root_path | safe}}{{script}}.js"></script> {#- -#} {% endfor %} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b50fbf58bae..7eeb9d1fcaa 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -121,6 +121,7 @@ mod markdown; mod passes; mod scrape_examples; mod theme; +mod visit; mod visit_ast; mod visit_lib; diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs index 4501914fe0c..4e146a07d15 100644 --- a/src/librustdoc/passes/bare_urls.rs +++ b/src/librustdoc/passes/bare_urls.rs @@ -1,8 +1,8 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::main_body_opts; +use crate::visit::DocVisitor; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use regex::Regex; @@ -53,16 +53,17 @@ impl<'a, 'tcx> BareUrlsLinter<'a, 'tcx> { } crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - BareUrlsLinter { cx }.fold_crate(krate) + BareUrlsLinter { cx }.visit_crate(&krate); + krate } -impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option<Item> { +impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { let hir_id = match DocContext::as_local_hir_id(self.cx.tcx, item.def_id) { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return Some(self.fold_item_recur(item)); + return; } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -106,6 +107,6 @@ impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> { } } - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 5e3bd41b85c..85542ebd9ac 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -1,9 +1,9 @@ use crate::clean; use crate::core::DocContext; -use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests}; use crate::passes::Pass; +use crate::visit::DocVisitor; use rustc_hir as hir; use rustc_lint::builtin::MISSING_DOCS; use rustc_middle::lint::LintLevelSource; @@ -23,7 +23,7 @@ crate const CALCULATE_DOC_COVERAGE: Pass = Pass { fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate { let mut calc = CoverageCalculator { items: Default::default(), ctx }; - let krate = calc.fold_crate(krate); + calc.visit_crate(&krate); calc.print_results(); @@ -182,17 +182,18 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { } } -impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { - fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> { +impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> { + fn visit_item(&mut self, i: &clean::Item) { + if !i.def_id.is_local() { + // non-local items are skipped because they can be out of the users control, + // especially in the case of trait impls, which rustdoc eagerly inlines + return; + } + match *i.kind { - _ if !i.def_id.is_local() => { - // non-local items are skipped because they can be out of the users control, - // especially in the case of trait impls, which rustdoc eagerly inlines - return Some(i); - } clean::StrippedItem(..) => { // don't count items in stripped modules - return Some(i); + return; } // docs on `use` and `extern crate` statements are not displayed, so they're not // worth counting @@ -269,6 +270,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { } } - Some(self.fold_item_recur(i)) + self.visit_item_recur(i) } } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index b18208d26e2..fd2ab0dc97c 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -8,9 +8,9 @@ use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMM use crate::clean; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::{self, RustCodeBlock}; use crate::passes::Pass; +use crate::visit::DocVisitor; crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { name: "check-code-block-syntax", @@ -19,7 +19,8 @@ crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { }; crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { - SyntaxChecker { cx }.fold_crate(krate) + SyntaxChecker { cx }.visit_crate(&krate); + krate } struct SyntaxChecker<'a, 'tcx> { @@ -141,8 +142,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { } } -impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { - fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> { +impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> { + fn visit_item(&mut self, item: &clean::Item) { if let Some(dox) = &item.attrs.collapsed_doc_value() { let sp = item.attr_span(self.cx.tcx); let extra = crate::html::markdown::ExtraInfo::new_did( @@ -155,7 +156,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { } } - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 69a526d4618..7d3010cf332 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -7,8 +7,8 @@ use super::Pass; use crate::clean; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; +use crate::visit::DocVisitor; use crate::visit_ast::inherits_doc_hidden; use rustc_hir as hir; use rustc_middle::lint::LintLevelSource; @@ -27,17 +27,17 @@ struct DocTestVisibilityLinter<'a, 'tcx> { crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate { let mut coll = DocTestVisibilityLinter { cx }; - - coll.fold_crate(krate) + coll.visit_crate(&krate); + krate } -impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option<Item> { +impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); look_for_tests(self.cx, &dox, &item); - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9b2fe0c77e6..8541e6e1881 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -32,10 +32,10 @@ use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::{markdown_links, MarkdownLink}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; +use crate::visit::DocVisitor; mod early; crate use early::load_intra_link_crates; @@ -47,13 +47,14 @@ crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - LinkCollector { + let mut collector = LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None), visited_links: FxHashMap::default(), - } - .fold_crate(krate) + }; + collector.visit_crate(&krate); + krate } /// Top-level errors emitted by this pass. @@ -816,8 +817,8 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_ ) } -impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option<Item> { +impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { use rustc_middle::ty::DefIdTree; let parent_node = @@ -911,17 +912,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } - Some(if item.is_mod() { + if item.is_mod() { if !inner_docs { self.mod_ids.push(item.def_id.expect_def_id()); } - let ret = self.fold_item_recur(item); + self.visit_item_recur(item); self.mod_ids.pop(); - ret } else { - self.fold_item_recur(item) - }) + self.visit_item_recur(item) + } } } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 7a4198198fa..77513b05ff2 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -1,7 +1,7 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; +use crate::visit::DocVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::DefId; @@ -14,17 +14,18 @@ crate const COLLECT_TRAIT_IMPLS: Pass = Pass { description: "retrieves trait impls for items in the crate", }; -crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || { +crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let synth_impls = cx.sess().time("collect_synthetic_impls", || { let mut synth = SyntheticImplCollector { cx, impls: Vec::new() }; - (synth.fold_crate(krate), synth.impls) + synth.visit_crate(&krate); + synth.impls }); let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); - krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate)); + cx.sess().time("collect_items_for_trait_impls", || coll.visit_crate(&krate)); coll.items }; @@ -152,14 +153,13 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { } } - let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind { - items + if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind { + items.extend(synth_impls); + items.extend(new_items); } else { panic!("collect-trait-impls can't run"); }; - items.extend(synth_impls); - items.extend(new_items); krate } @@ -168,8 +168,8 @@ struct SyntheticImplCollector<'a, 'tcx> { impls: Vec<Item>, } -impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { - fn fold_item(&mut self, i: Item) -> Option<Item> { +impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> { + fn visit_item(&mut self, i: &Item) { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? if !self @@ -184,7 +184,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { } } - Some(self.fold_item_recur(i)) + self.visit_item_recur(i) } } @@ -199,11 +199,11 @@ impl ItemCollector { } } -impl DocFolder for ItemCollector { - fn fold_item(&mut self, i: Item) -> Option<Item> { +impl DocVisitor for ItemCollector { + fn visit_item(&mut self, i: &Item) { self.items.insert(i.def_id); - Some(self.fold_item_recur(i)) + self.visit_item_recur(i) } } diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index a3fde92d765..56b222d8932 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -1,11 +1,13 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::main_body_opts; -use core::ops::Range; +use crate::visit::DocVisitor; + use pulldown_cmark::{Event, Parser, Tag}; + use std::iter::Peekable; +use std::ops::Range; use std::str::CharIndices; crate const CHECK_INVALID_HTML_TAGS: Pass = Pass { @@ -19,13 +21,11 @@ struct InvalidHtmlTagsLinter<'a, 'tcx> { } crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - if !cx.tcx.sess.is_nightly_build() { - krate - } else { + if cx.tcx.sess.is_nightly_build() { let mut coll = InvalidHtmlTagsLinter { cx }; - - coll.fold_crate(krate) + coll.visit_crate(&krate); } + krate } const ALLOWED_UNCLOSED: &[&str] = &[ @@ -165,14 +165,14 @@ fn extract_tags( } } -impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option<Item> { +impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { let tcx = self.cx.tcx; let hir_id = match DocContext::as_local_hir_id(tcx, item.def_id) { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return Some(self.fold_item_recur(item)); + return; } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -217,6 +217,6 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { } } - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 05e746573f4..1b5a7504552 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -10,7 +10,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, intravisit::{self, Visitor}, - HirId, }; use rustc_interface::interface; use rustc_macros::{Decodable, Encodable}; @@ -83,15 +82,10 @@ crate struct CallLocation { impl CallLocation { fn new( - tcx: TyCtxt<'_>, expr_span: rustc_span::Span, - expr_id: HirId, + enclosing_item_span: rustc_span::Span, source_file: &SourceFile, ) -> Self { - let enclosing_item_span = - tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite(); - assert!(enclosing_item_span.contains(expr_span)); - CallLocation { call_expr: SyntaxRange::new(expr_span, source_file), enclosing_item: SyntaxRange::new(enclosing_item_span, source_file), @@ -168,13 +162,29 @@ where // If this span comes from a macro expansion, then the source code may not actually show // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros. if span.from_expansion() { + trace!("Rejecting expr from macro: {:?}", span); + return; + } + + // If the enclosing item has a span coming from a proc macro, then we also don't want to include + // the example. + let enclosing_item_span = tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id)); + if enclosing_item_span.from_expansion() { + trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span); return; } + assert!( + enclosing_item_span.contains(span), + "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call.", + span, + enclosing_item_span + ); + // Save call site if the function resolves to a concrete definition if let ty::FnDef(def_id, _) = ty.kind() { - // Ignore functions not from the crate being documented if self.target_crates.iter().all(|krate| *krate != def_id.krate) { + trace!("Rejecting expr from crate not being documented: {:?}", span); return; } @@ -198,7 +208,8 @@ where let fn_key = tcx.def_path_hash(*def_id); let fn_entries = self.calls.entry(fn_key).or_default(); - let location = CallLocation::new(tcx, span, ex.hir_id, &file); + trace!("Including expr: {:?}", span); + let location = CallLocation::new(span, enclosing_item_span, &file); fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location); } } @@ -240,6 +251,13 @@ crate fn run( let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates }; tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor()); + // Sort call locations within a given file in document order + for fn_calls in calls.values_mut() { + for file_calls in fn_calls.values_mut() { + file_calls.locations.sort_by_key(|loc| loc.call_expr.byte_span.0); + } + } + // Save output to provided path let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?; calls.encode(&mut encoder).map_err(|e| e.to_string())?; diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs new file mode 100644 index 00000000000..df4d1558ebd --- /dev/null +++ b/src/librustdoc/visit.rs @@ -0,0 +1,71 @@ +use crate::clean::*; + +crate trait DocVisitor: Sized { + fn visit_item(&mut self, item: &Item) { + self.visit_item_recur(item) + } + + /// don't override! + fn visit_inner_recur(&mut self, kind: &ItemKind) { + match kind { + StrippedItem(..) => unreachable!(), + ModuleItem(i) => { + self.visit_mod(i); + return; + } + StructItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)), + UnionItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)), + EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)), + TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)), + ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)), + VariantItem(i) => match i { + Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)), + Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)), + Variant::CLike => {} + }, + ExternCrateItem { src: _ } + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | KeywordItem(_) => {} + } + } + + /// don't override! + fn visit_item_recur(&mut self, item: &Item) { + match &*item.kind { + StrippedItem(i) => self.visit_inner_recur(i), + _ => self.visit_inner_recur(&item.kind), + } + } + + fn visit_mod(&mut self, m: &Module) { + m.items.iter().for_each(|i| self.visit_item(i)) + } + + fn visit_crate(&mut self, c: &Crate) { + self.visit_item(&c.module); + + // FIXME: make this a simple by-ref for loop once external_traits is cleaned up + let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; + for (k, v) in external_traits { + v.trait_.items.iter().for_each(|i| self.visit_item(i)); + c.external_traits.borrow_mut().insert(k, v); + } + } +} diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/Makefile b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/Makefile new file mode 100644 index 00000000000..4934e875da6 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/Makefile @@ -0,0 +1,18 @@ +-include ../../run-make-fulldeps/tools.mk + +OUTPUT_DIR := "$(TMPDIR)/rustdoc" +DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foobar_macro --crate-type dylib --print file-names -) + +all: + $(RUSTC) src/proc.rs --crate-name foobar_macro --edition=2021 --crate-type proc-macro --emit=dep-info,link + + $(RUSTC) src/lib.rs --crate-name foobar --edition=2021 --crate-type lib --emit=dep-info,link + + $(RUSTDOC) examples/ex.rs --crate-name ex --crate-type bin --output $(OUTPUT_DIR) \ + --extern foobar=$(TMPDIR)/libfoobar.rlib --extern foobar_macro=$(TMPDIR)/$(DYLIB_NAME) \ + -Z unstable-options --scrape-examples-output-path $(TMPDIR)/ex.calls --scrape-examples-target-crate foobar + + $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \ + -Z unstable-options --with-examples $(TMPDIR)/ex.calls + + $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/examples/ex.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/examples/ex.rs new file mode 100644 index 00000000000..4d8c8b30e31 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/examples/ex.rs @@ -0,0 +1,27 @@ +extern crate foobar; +extern crate foobar_macro; + +use foobar::*; +use foobar_macro::*; + +a_proc_macro!(); // no + +#[an_attr_macro] +fn a() { + f(); // no +} + +#[an_attr_macro(with_span)] +fn b() { + f(); // yes +} + +fn c() { + a_rules_macro!(f()); // yes +} + +fn d() { + a_rules_macro!(()); // no +} + +fn main(){} diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs new file mode 100644 index 00000000000..bac3970a4d3 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs @@ -0,0 +1,12 @@ +// Scraped example should only include line numbers for items b and c in ex.rs +// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '14' +// @has foobar/fn.f.html '//*[@class="line-numbers"]' '15' +// @has foobar/fn.f.html '//*[@class="line-numbers"]' '21' +// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '22' + +pub fn f() {} + +#[macro_export] +macro_rules! a_rules_macro { + ($e:expr) => { ($e, foobar::f()); } +} diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/proc.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/proc.rs new file mode 100644 index 00000000000..46e518fdf6a --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/proc.rs @@ -0,0 +1,39 @@ +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn a_proc_macro(_item: TokenStream) -> TokenStream { + "fn ex() { foobar::f(); }".parse().unwrap() +} + +// inserts foobar::f() to the end of the function +#[proc_macro_attribute] +pub fn an_attr_macro(attr: TokenStream, item: TokenStream) -> TokenStream { + let new_call: TokenStream = "foobar::f();".parse().unwrap(); + + let mut tokens = item.into_iter(); + + let fn_tok = tokens.next().unwrap(); + let ident_tok = tokens.next().unwrap(); + let args_tok = tokens.next().unwrap(); + let body = match tokens.next().unwrap() { + TokenTree::Group(g) => { + let new_g = Group::new(g.delimiter(), new_call); + let mut outer_g = Group::new( + g.delimiter(), + [TokenTree::Group(g.clone()), TokenTree::Group(new_g)].into_iter().collect(), + ); + + if attr.to_string() == "with_span" { + outer_g.set_span(g.span()); + } + + TokenTree::Group(outer_g) + } + _ => unreachable!(), + }; + + let tokens = vec![fn_tok, ident_tok, args_tok, body].into_iter().collect::<TokenStream>(); + + tokens +} diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs index d6d59820876..05c18007b0c 100644 --- a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs @@ -1,8 +1,10 @@ fn main() { - foobar::ok(); + foobar::ok(0); // this is a + // .. + // BIG // item diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs index a1133117f86..de21d9061f8 100644 --- a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs @@ -1,4 +1,8 @@ fn main() { - foobar::ok(); + foobar::ok(1); // small item } + +fn f() { + foobar::ok(2); +} diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs index f1b7686d368..5afffffdf99 100644 --- a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs @@ -1,4 +1,7 @@ // @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2' // @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1' +// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '1' +// @has foobar/fn.ok.html '//*[@class="highlight"]' '2' +// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '0' -pub fn ok() {} +pub fn ok(_x: i32) {} diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml index 35d772170f6..bdf17ec4570 100644 --- a/src/test/rustdoc-gui/headings.goml +++ b/src/test/rustdoc-gui/headings.goml @@ -109,6 +109,9 @@ assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0 assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"}) assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"}) +assert-text: (".sidebar .others h3", "Modules") +assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL) + goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html assert-css: ("h1.fqn", {"font-size": "24px"}) diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml index eacc9f6c15f..f9c707f81e7 100644 --- a/src/test/rustdoc-gui/sidebar.goml +++ b/src/test/rustdoc-gui/sidebar.goml @@ -4,17 +4,17 @@ assert-text: (".sidebar > .location", "Crate test_docs") assert-count: (".sidebar .location", 1) assert-text: (".sidebar-elems > #all-types", "See all test_docs's items") // We check that we have the crates list and that the "current" on is "test_docs". -assert-text: (".sidebar-elems > .crate > ul > li > a.current", "test_docs") +assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. -assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Macros") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Structs") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Enums") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Traits") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Functions") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Type Definitions") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(8)", "Unions") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(9)", "Keywords") +assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules") +assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros") +assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs") +assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums") +assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits") +assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions") +assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions") +assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions") +assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords") assert-text: ("#structs + .item-table .item-left > a", "Foo") click: "#structs + .item-table .item-left > a" @@ -24,13 +24,13 @@ assert-count: (".sidebar .location", 2) assert-false: ".sidebar-elems > .crate" // We now go back to the crate page to click on the "lib2" crate link. goto: file://|DOC_PATH|/test_docs/index.html -click: ".sidebar-elems > .crate > ul > li:first-child > a" +click: ".sidebar-elems .crate > ul > li:first-child > a" // PAGE: lib2/index.html goto: file://|DOC_PATH|/lib2/index.html assert-text: (".sidebar > .location", "Crate lib2") // We check that we have the crates list and that the "current" on is now "lib2". -assert-text: (".sidebar-elems > .crate > ul > li > a.current", "lib2") +assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2") // We now go to the "foobar" function page. assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules") assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs") @@ -57,6 +57,6 @@ assert-false: ".sidebar-elems > .crate" goto: ./sub_module/sub_sub_module/index.html assert-text: (".sidebar > .location", "Module sub_sub_module") // We check that we don't have the crate list. -assert-false: ".sidebar-elems > .crate" -assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions") +assert-false: ".sidebar-elems .crate" +assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions") assert-text: ("#functions + .item-table .item-left > a", "foo") diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs new file mode 100644 index 00000000000..fcdd8354569 --- /dev/null +++ b/src/test/rustdoc/doc-auto-cfg.rs @@ -0,0 +1,8 @@ +#![feature(doc_auto_cfg)] + +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test' +#[cfg(not(test))] +pub fn foo() {} diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs index b9d0d323137..424fa6d6a91 100644 --- a/src/test/rustdoc/doc-cfg-hide.rs +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -1,5 +1,5 @@ #![crate_name = "oud"] -#![feature(doc_cfg, doc_cfg_hide)] +#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)] #![doc(cfg_hide(feature = "solecism"))] diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs index 36c2025785d..5d17a4ede6a 100644 --- a/src/test/rustdoc/doc-cfg-implicit.rs +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -1,5 +1,5 @@ #![crate_name = "funambulism"] -#![feature(doc_cfg)] +#![feature(doc_auto_cfg, doc_cfg)] // @has 'funambulism/struct.Disorbed.html' // @count - '//*[@class="stab portability"]' 1 diff --git a/src/test/rustdoc/feature-gate-doc_auto_cfg.rs b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs new file mode 100644 index 00000000000..da76381e480 --- /dev/null +++ b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs @@ -0,0 +1,8 @@ +#![feature(doc_cfg)] + +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0 +#[cfg(not(test))] +pub fn foo() {} diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed b/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed new file mode 100644 index 00000000000..4e0b18e7233 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE lint level is defined here + +fn main() { + struct Foo(u32); + impl Drop for Foo { + fn drop(&mut self) { + println!("dropped {}", self.0); + } + } + + let f0 = Foo(0); + let f1 = Foo(1); + + let c0 = move || { + let _ = &f0; + //~^ ERROR changes to closure capture in Rust 2021 will affect drop order + //~| NOTE for more information + let _ = f0; + //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect + }; + + let c1 = move || { + let _ = &f1; + }; + + println!("dropping 0"); + drop(c0); + println!("dropping 1"); + drop(c1); + println!("dropped all"); +} +//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.rs b/src/test/ui/closures/2229_closure_analysis/issue-90465.rs new file mode 100644 index 00000000000..466e6dbabc5 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-90465.rs @@ -0,0 +1,34 @@ +// run-rustfix + +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE lint level is defined here + +fn main() { + struct Foo(u32); + impl Drop for Foo { + fn drop(&mut self) { + println!("dropped {}", self.0); + } + } + + let f0 = Foo(0); + let f1 = Foo(1); + + let c0 = move || { + //~^ ERROR changes to closure capture in Rust 2021 will affect drop order + //~| NOTE for more information + let _ = f0; + //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect + }; + + let c1 = move || { + let _ = &f1; + }; + + println!("dropping 0"); + drop(c0); + println!("dropping 1"); + drop(c1); + println!("dropped all"); +} +//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr b/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr new file mode 100644 index 00000000000..3e921dc0f8a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr @@ -0,0 +1,26 @@ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/issue-90465.rs:17:14 + | +LL | let c0 = move || { + | ^^^^^^^ +... +LL | let _ = f0; + | -- in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect +... +LL | } + | - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure + | +note: the lint level is defined here + --> $DIR/issue-90465.rs:3:9 + | +LL | #![deny(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html> +help: add a dummy let to cause `f0` to be fully captured + | +LL ~ let c0 = move || { +LL + let _ = &f0; + | + +error: aborting due to previous error + diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index b0fc5120f08..26703fbf811 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -20,8 +20,8 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -40,8 +40,9 @@ fn test_sync_trait() { let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -65,8 +66,8 @@ fn test_clone_trait() { let f = U(S(Foo(0)), T(0)); let c = || { let _ = &f; - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index 2bcf9a795ed..932db51d437 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -20,8 +20,8 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -40,8 +40,9 @@ fn test_sync_trait() { let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -64,8 +65,8 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(Foo(0)), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 8d2d3553d40..ee4907bb755 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,8 +1,8 @@ -error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send` ... LL | *fptr.0 = 20; | ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0` @@ -23,11 +23,14 @@ LL | LL | *fptr.0 = 20; ... -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + | ^^^^^^^^^^^^^^ + | | + | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send` ... LL | *fptr.0.0 = 20; | --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0` @@ -40,14 +43,14 @@ LL | LL | LL | LL | -LL | *fptr.0.0 = 20; +LL | ... -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/auto_traits.rs:66:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/auto_traits.rs:67:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone` ... LL | let f_1 = f.1; | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed index a5652154682..7df0dd76b44 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -19,8 +19,9 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index d9acde073fc..d02fac7c669 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -18,8 +18,9 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 10816b7bc3a..74f85b6ebaa 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -1,8 +1,11 @@ -error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/mir_calls_to_shims.rs:20:38 | LL | let result = panic::catch_unwind(move || { - | ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + | ^^^^^^^ + | | + | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe` + | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe` ... LL | f.0() | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index 11218eff133..2b86b0ddade 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -18,7 +18,6 @@ impl Foo { } } - struct S(Foo); #[derive(Clone)] @@ -37,8 +36,8 @@ fn test_multi_issues() { let f2 = U(S(Foo::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured let _f_1 = f1.0; @@ -57,8 +56,8 @@ fn test_capturing_all_disjoint_fields_individually() { let f1 = U(S(Foo::from("foo")), T(0)); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_1 = f1.0; @@ -83,9 +82,9 @@ fn test_capturing_several_disjoint_fields_individually_1() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -103,8 +102,8 @@ fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -136,9 +135,10 @@ fn test_multi_traits_issues() { let mut f2 = 10; let fptr2 = SendPointer(&mut f2 as *mut i32); thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured *fptr1.0.0 = 20; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index 02f2faa2e87..3cac4abfad7 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -18,7 +18,6 @@ impl Foo { } } - struct S(Foo); #[derive(Clone)] @@ -36,8 +35,8 @@ fn test_multi_issues() { let f1 = U(S(Foo::from("foo")), T(0)); let f2 = U(S(Foo::from("bar")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured let _f_1 = f1.0; @@ -55,8 +54,8 @@ fn test_multi_issues() { fn test_capturing_all_disjoint_fields_individually() { let f1 = U(S(Foo::from("foo")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_1 = f1.0; @@ -80,9 +79,9 @@ impl Clone for U1 { fn test_capturing_several_disjoint_fields_individually_1() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -99,8 +98,8 @@ fn test_capturing_several_disjoint_fields_individually_1() { fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -132,9 +131,10 @@ fn test_multi_traits_issues() { let mut f2 = 10; let fptr2 = SendPointer(&mut f2 as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured *fptr1.0.0 = 20; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index d425db5aa99..0008f1b2c07 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -1,8 +1,8 @@ -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:38:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/multi_diagnostics.rs:37:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_1 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -25,11 +25,11 @@ LL ~ let c = || { LL + let _ = (&f1, &f2); | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:57:13 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:56:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_1 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -41,14 +41,14 @@ LL ~ let c = || { LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:82:13 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:81:13 | LL | let c = || { | ^^ | | - | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` + | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone` ... LL | let _f_0 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -63,11 +63,11 @@ LL ~ let c = || { LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:101:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/multi_diagnostics.rs:100:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_0 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -88,14 +88,15 @@ LL ~ let c = || { LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/multi_diagnostics.rs:134:19 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:133:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` - | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send` + | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send` ... LL | *fptr1.0.0 = 20; | ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0` diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index d9479002b6c..36d6450c9a2 100644 --- a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable)]` + found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr index 880e38df2d7..91926f233d3 100644 --- a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[f<T>::{closure#0} closure_substs=(unavailable)]` + found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/src/test/ui/closures/print/closure-print-verbose.stderr b/src/test/ui/closures/print/closure-print-verbose.stderr index d19b07acbf1..083717b3334 100644 --- a/src/test/ui/closures/print/closure-print-verbose.stderr +++ b/src/test/ui/closures/print/closure-print-verbose.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `[main::{closure#0} closure_substs=(unavailable)]` + found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-print-verbose.rs:10:39 | diff --git a/src/test/ui/consts/qualif-indirect-mutation-fail.rs b/src/test/ui/consts/qualif-indirect-mutation-fail.rs index cedead00fec..f74a25a346f 100644 --- a/src/test/ui/consts/qualif-indirect-mutation-fail.rs +++ b/src/test/ui/consts/qualif-indirect-mutation-fail.rs @@ -2,6 +2,7 @@ #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_swap)] +#![feature(raw_ref_op)] // Mutable borrow of a field with drop impl. pub const fn f() { @@ -42,3 +43,22 @@ pub const fn g2<T>() { let _ = x.is_some(); let _y = x; //~ ERROR destructors cannot be evaluated } + +// Mutable raw reference to a Drop type. +pub const fn address_of_mut() { + let mut x: Option<String> = None; //~ ERROR destructors cannot be evaluated + &raw mut x; + + let mut y: Option<String> = None; //~ ERROR destructors cannot be evaluated + std::ptr::addr_of_mut!(y); +} + +// Const raw reference to a Drop type. Conservatively assumed to allow mutation +// until resolution of https://github.com/rust-lang/rust/issues/56604. +pub const fn address_of_const() { + let x: Option<String> = None; //~ ERROR destructors cannot be evaluated + &raw const x; + + let y: Option<String> = None; //~ ERROR destructors cannot be evaluated + std::ptr::addr_of!(y); +} diff --git a/src/test/ui/consts/qualif-indirect-mutation-fail.stderr b/src/test/ui/consts/qualif-indirect-mutation-fail.stderr index aa6ed465594..713df12b7a5 100644 --- a/src/test/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/src/test/ui/consts/qualif-indirect-mutation-fail.stderr @@ -1,33 +1,57 @@ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:8:9 + --> $DIR/qualif-indirect-mutation-fail.rs:9:9 | LL | let mut a: (u32, Option<String>) = (0, None); | ^^^^^ constant functions cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:14:9 + --> $DIR/qualif-indirect-mutation-fail.rs:15:9 | LL | let mut x = None; | ^^^^^ constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:30:9 + --> $DIR/qualif-indirect-mutation-fail.rs:31:9 | LL | let _z = x; | ^^ constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:35:9 + --> $DIR/qualif-indirect-mutation-fail.rs:36:9 | LL | let x: Option<T> = None; | ^ constant functions cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:43:9 + --> $DIR/qualif-indirect-mutation-fail.rs:44:9 | LL | let _y = x; | ^^ constant functions cannot evaluate destructors -error: aborting due to 5 previous errors +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:52:9 + | +LL | let mut y: Option<String> = None; + | ^^^^^ constant functions cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:49:9 + | +LL | let mut x: Option<String> = None; + | ^^^^^ constant functions cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:62:9 + | +LL | let y: Option<String> = None; + | ^ constant functions cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:59:9 + | +LL | let x: Option<String> = None; + | ^ constant functions cannot evaluate destructors + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/qualif-indirect-mutation-pass.rs b/src/test/ui/consts/qualif-indirect-mutation-pass.rs index 35a9b70a5f6..06af6a03b8f 100644 --- a/src/test/ui/consts/qualif-indirect-mutation-pass.rs +++ b/src/test/ui/consts/qualif-indirect-mutation-pass.rs @@ -3,6 +3,7 @@ #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] +// Mutable reference allows only mutation of !Drop place. pub const fn f() { let mut x: (Option<String>, u32) = (None, 0); let mut a = 10; @@ -10,7 +11,14 @@ pub const fn f() { x.1 = a; } +// Mutable reference allows only mutation of !Drop place. pub const fn g() { let mut a: (u32, Option<String>) = (0, None); let _ = &mut a.0; } + +// Shared reference does not allow for mutation. +pub const fn h() { + let x: Option<String> = None; + let _ = &x; +} diff --git a/src/test/ui/extern/extern-methods.rs b/src/test/ui/extern/extern-methods.rs index 3909b5301ad..22792c11366 100644 --- a/src/test/ui/extern/extern-methods.rs +++ b/src/test/ui/extern/extern-methods.rs @@ -1,5 +1,5 @@ // run-pass -// only-i686 +// only-x86 trait A { extern "fastcall" fn test1(i: i32); diff --git a/src/test/ui/extern/extern-thiscall.rs b/src/test/ui/extern/extern-thiscall.rs index 8ce94aa71aa..717df57ec48 100644 --- a/src/test/ui/extern/extern-thiscall.rs +++ b/src/test/ui/extern/extern-thiscall.rs @@ -1,5 +1,5 @@ // run-pass -// only-i686 +// only-x86 #![feature(abi_thiscall)] diff --git a/src/test/ui/extern/extern-vectorcall.rs b/src/test/ui/extern/extern-vectorcall.rs index f625eb0890f..a283573c9fb 100644 --- a/src/test/ui/extern/extern-vectorcall.rs +++ b/src/test/ui/extern/extern-vectorcall.rs @@ -1,7 +1,7 @@ // run-pass // revisions: x64 x32 // [x64]only-x86_64 -// [x32]only-i686 +// [x32]only-x86 #![feature(abi_vectorcall)] diff --git a/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs b/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs deleted file mode 100644 index 0cfd0a0b978..00000000000 --- a/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Test that we allow unsizing even if there is an unchanged param in the -// field getting unsized. -struct A<T, U: ?Sized + 'static>(T, B<T, U>); -struct B<T, U: ?Sized>(T, U); - -fn main() { - let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1])); - let y: &A<[u32; 1], [u32]> = &x; //~ ERROR mismatched types - assert_eq!(y.1.1.len(), 1); -} diff --git a/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.stderr b/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.stderr deleted file mode 100644 index f62def47726..00000000000 --- a/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/feature-gate-relaxed_struct_unsize.rs:8:34 - | -LL | let y: &A<[u32; 1], [u32]> = &x; - | ------------------- ^^ expected slice `[u32]`, found array `[u32; 1]` - | | - | expected due to this - | - = note: expected reference `&A<[u32; 1], [u32]>` - found reference `&A<[u32; 1], [u32; 1]>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs index 0944bf110c1..5b94cdee7c9 100644 --- a/src/test/ui/generic-associated-types/collections-project-default.rs +++ b/src/test/ui/generic-associated-types/collections-project-default.rs @@ -8,7 +8,7 @@ // check that we don't normalize with trait defaults. trait Collection<T> { - type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter; + type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter; type Family: CollectionFamily; // Test associated type defaults with parameters type Sibling<U>: Collection<U> = diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs index f14c6dac1b1..b0f2fb3f567 100644 --- a/src/test/ui/generic-associated-types/collections.rs +++ b/src/test/ui/generic-associated-types/collections.rs @@ -8,7 +8,7 @@ // run-pass trait Collection<T> { - type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter; + type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter; type Family: CollectionFamily; // Test associated type defaults with parameters type Sibling<U>: Collection<U> = diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs index 5d3a3a89352..d7c4dbda264 100644 --- a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs +++ b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs @@ -3,7 +3,7 @@ #![feature(generic_associated_types)] pub trait X { - type Y<'a>; + type Y<'a> where Self: 'a; fn m(&self) -> Self::Y<'_>; } diff --git a/src/test/ui/generic-associated-types/issue-70303.rs b/src/test/ui/generic-associated-types/issue-70303.rs index d238f53bde7..568996e1a17 100644 --- a/src/test/ui/generic-associated-types/issue-70303.rs +++ b/src/test/ui/generic-associated-types/issue-70303.rs @@ -3,7 +3,7 @@ #![feature(generic_associated_types)] trait Document { - type Cursor<'a>: DocCursor<'a>; + type Cursor<'a>: DocCursor<'a> where Self: 'a; fn cursor(&self) -> Self::Cursor<'_>; } diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs index 1dad856d5a3..20c6924afa6 100644 --- a/src/test/ui/generic-associated-types/issue-76535.rs +++ b/src/test/ui/generic-associated-types/issue-76535.rs @@ -3,7 +3,7 @@ pub trait SubTrait {} pub trait SuperTrait { - type SubType<'a>: SubTrait; + type SubType<'a>: SubTrait where Self: 'a; fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; } diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr index 0a7eb5dde60..64eeec1b2fc 100644 --- a/src/test/ui/generic-associated-types/issue-76535.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.stderr @@ -7,7 +7,7 @@ LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruc note: associated type defined here, with 1 lifetime parameter: `'a` --> $DIR/issue-76535.rs:6:10 | -LL | type SubType<'a>: SubTrait; +LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ -- help: add missing lifetime argument | @@ -25,7 +25,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all | LL | pub trait SuperTrait { | ---------- this trait cannot be made into an object... -LL | type SubType<'a>: SubTrait; +LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait @@ -40,7 +40,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all | LL | pub trait SuperTrait { | ---------- this trait cannot be made into an object... -LL | type SubType<'a>: SubTrait; +LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>` diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs index 7f0ac348358..47ef38ff45d 100644 --- a/src/test/ui/generic-associated-types/issue-79422.rs +++ b/src/test/ui/generic-associated-types/issue-79422.rs @@ -17,12 +17,12 @@ impl<'a, T> RefCont<'a, T> for Box<T> { } trait MapLike<K, V> { - type VRefCont<'a>: RefCont<'a, V>; + type VRefCont<'a>: RefCont<'a, V> where Self: 'a; fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>; } impl<K: Ord, V: 'static> MapLike<K, V> for std::collections::BTreeMap<K, V> { - type VRefCont<'a> = &'a V; + type VRefCont<'a> where Self: 'a = &'a V; fn get<'a>(&'a self, key: &K) -> Option<&'a V> { std::collections::BTreeMap::get(self, key) } diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr index b6f856a97e7..8b6f9b866e5 100644 --- a/src/test/ui/generic-associated-types/issue-79422.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.stderr @@ -7,7 +7,7 @@ LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>; note: associated type defined here, with 1 lifetime parameter: `'a` --> $DIR/issue-79422.rs:20:10 | -LL | type VRefCont<'a>: RefCont<'a, V>; +LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ -- help: add missing lifetime argument | @@ -25,7 +25,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all | LL | trait MapLike<K, V> { | ------- this trait cannot be made into an object... -LL | type VRefCont<'a>: RefCont<'a, V>; +LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait @@ -40,7 +40,7 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all | LL | trait MapLike<K, V> { | ------- this trait cannot be made into an object... -LL | type VRefCont<'a>: RefCont<'a, V>; +LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>` diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs index f1f05ea6627..0f62f83e256 100644 --- a/src/test/ui/generic-associated-types/issue-86787.rs +++ b/src/test/ui/generic-associated-types/issue-86787.rs @@ -9,6 +9,7 @@ enum Either<L, R> { pub trait HasChildrenOf { type T; type TRef<'a>; + //~^ Missing required bounds fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>; fn take_children(self) -> Vec<Self::T>; @@ -20,9 +21,9 @@ where Right: HasChildrenOf, { type T = Either<Left::T, Right::T>; + // We used to error below because the where clause doesn't match the trait. + // Now, we error early on the trait itself. type TRef<'a> - //~^ `impl` associated type signature - //~^^ `impl` associated type signature where <Left as HasChildrenOf>::T: 'a, <Right as HasChildrenOf>::T: 'a diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 648eff77d73..87dcd875de7 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -1,32 +1,10 @@ -error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature - --> $DIR/issue-86787.rs:23:5 +error: Missing required bounds on TRef + --> $DIR/issue-86787.rs:11:5 | -LL | type TRef<'a>; - | -------------- expected -... -LL | / type TRef<'a> -LL | | -LL | | -LL | | where -LL | | <Left as HasChildrenOf>::T: 'a, -LL | | <Right as HasChildrenOf>::T: 'a -LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ found +LL | type TRef<'a>; + | ^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where Self: 'a` -error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature - --> $DIR/issue-86787.rs:23:5 - | -LL | type TRef<'a>; - | -------------- expected -... -LL | / type TRef<'a> -LL | | -LL | | -LL | | where -LL | | <Left as HasChildrenOf>::T: 'a, -LL | | <Right as HasChildrenOf>::T: 'a -LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ found - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-88287.rs b/src/test/ui/generic-associated-types/issue-88287.rs index 2e65af594a6..df5586ed422 100644 --- a/src/test/ui/generic-associated-types/issue-88287.rs +++ b/src/test/ui/generic-associated-types/issue-88287.rs @@ -13,7 +13,8 @@ trait SearchableResource<Criteria> { trait SearchableResourceExt<Criteria>: SearchableResource<Criteria> { type Future<'f, A: 'f + ?Sized, B: 'f>: Future<Output = Result<Vec<A::SearchResult>, ()>> + 'f where - A: SearchableResource<B>; + A: SearchableResource<B>, + Self: 'f; fn search<'c>(&'c self, client: &'c ()) -> Self::Future<'c, Self, Criteria>; } @@ -29,6 +30,7 @@ where type Future<'f, A, B: 'f> where A: SearchableResource<B> + ?Sized + 'f, + Self: 'f, = SearchFutureTy<'f, A, B>; fn search<'c>(&'c self, _client: &'c ()) -> Self::Future<'c, Self, Criteria> { diff --git a/src/test/ui/generic-associated-types/issue-88360.rs b/src/test/ui/generic-associated-types/issue-88360.rs index 06af3f5ec96..8ee98201aba 100644 --- a/src/test/ui/generic-associated-types/issue-88360.rs +++ b/src/test/ui/generic-associated-types/issue-88360.rs @@ -1,13 +1,14 @@ #![feature(generic_associated_types)] trait GatTrait { - type Gat<'a>; + type Gat<'a> where Self: 'a; fn test(&self) -> Self::Gat<'_>; } trait SuperTrait<T> where + Self: 'static, for<'a> Self: GatTrait<Gat<'a> = &'a T>, { fn copy(&self) -> Self::Gat<'_> where T: Copy { diff --git a/src/test/ui/generic-associated-types/issue-88360.stderr b/src/test/ui/generic-associated-types/issue-88360.stderr index cfbf3aaa4e6..5f769d799fa 100644 --- a/src/test/ui/generic-associated-types/issue-88360.stderr +++ b/src/test/ui/generic-associated-types/issue-88360.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-88360.rs:14:9 + --> $DIR/issue-88360.rs:15:9 | LL | trait SuperTrait<T> | - this type parameter diff --git a/src/test/ui/generic-associated-types/issue-88459.rs b/src/test/ui/generic-associated-types/issue-88459.rs new file mode 100644 index 00000000000..3b26a180152 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-88459.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(generic_associated_types)] + +trait Trait { + type Assoc<'a>; +} + +fn f<T: Trait>(_: T, _: impl Fn(T::Assoc<'_>)) {} + +struct Type; + +impl Trait for Type { + type Assoc<'a> = (); +} + +fn main() { + f(Type, |_|()); +} diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs index b976ee3261f..bcbcfc18996 100644 --- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs @@ -1,7 +1,7 @@ #![feature(generic_associated_types)] pub trait X { - type Y<'a>; + type Y<'a> where Self: 'a; fn m(&self) -> Self::Y<'_>; } diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs new file mode 100644 index 00000000000..af90d158855 --- /dev/null +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -0,0 +1,173 @@ +#![feature(generic_associated_types)] + +// check-fail + +use std::fmt::Debug; + +// We have a `&'a self`, so we need a `Self: 'a` +trait Iterable { + type Item<'x>; + //~^ Missing required bounds + fn iter<'a>(&'a self) -> Self::Item<'a>; +} + +/* +impl<T> Iterable for T { + type Item<'a> = &'a T; + fn iter<'a>(&'a self) -> Self::Item<'a> { + self + } +} +*/ + +// We have a `&'a T`, so we need a `T: 'x` +trait Deserializer<T> { + type Out<'x>; + //~^ Missing required bounds + fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>; +} + +/* +impl<T> Deserializer<T> for () { + type Out<'a> = &'a T; + fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input } +} +*/ + +// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x` +trait Deserializer2<T> { + type Out<'x>; + //~^ Missing required bounds + fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>; +} + +// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y` +trait Deserializer3<T, U> { + type Out<'x, 'y>; + //~^ Missing required bounds + fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>; +} + +// `T` is a param on the function, so it can't be named by the associated type +trait Deserializer4 { + type Out<'x>; + fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>; +} + +struct Wrap<T>(T); + +// We pass `Wrap<T>` and we see `&'z Wrap<T>`, so we require `D: 'x` +trait Des { + type Out<'x, D>; + //~^ Missing required bounds + fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>; +} +/* +impl Des for () { + type Out<'x, D> = &'x D; // Not okay + fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> { + data + } +} +*/ + +// We have `T` and `'z` as GAT substs. Because of `&'z Wrap<T>`, there is an +// implied bound that `T: 'z`, so we require `D: 'x` +trait Des2 { + type Out<'x, D>; + //~^ Missing required bounds + fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>; +} +/* +impl Des2 for () { + type Out<'x, D> = &'x D; + fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> { + &data.0 + } +} +*/ + +// We see `&'z T`, so we require `D: 'x` +trait Des3 { + type Out<'x, D>; + //~^ Missing required bounds + fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>; +} +/* +impl Des3 for () { + type Out<'x, D> = &'x D; + fn des<'a, T>(&self, data: &'a T) -> Self::Out<'a, T> { + data + } +} +*/ + +// Similar case to before, except with GAT. +trait NoGat<'a> { + type Bar; + fn method(&'a self) -> Self::Bar; +} + +// Lifetime is not on function; except `Self: 'a` +// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one +trait TraitLifetime<'a> { + type Bar<'b>; + //~^ Missing required bounds + fn method(&'a self) -> Self::Bar<'a>; +} + +// Like above, but we have a where clause that can prove what we want +// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one +trait TraitLifetimeWhere<'a> where Self: 'a { + type Bar<'b>; + //~^ Missing required bounds + fn method(&'a self) -> Self::Bar<'a>; +} + +// Explicit bound instead of implicit; we want to still error +trait ExplicitBound { + type Bar<'b>; + //~^ Missing required bounds + fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b; +} + +// The use of the GAT here is not in the return, we don't want to error +trait NotInReturn { + type Bar<'b>; + fn method<'b>(&'b self) where Self::Bar<'b>: Debug; +} + +// We obviously error for `Iterator`, but we should also error for `Item` +trait IterableTwo { + type Item<'a>; + type Iterator<'a>: Iterator<Item = Self::Item<'a>>; + //~^ Missing required bounds + fn iter<'a>(&'a self) -> Self::Iterator<'a>; +} + +// We also should report region outlives clauses +trait RegionOutlives { + type Bar<'a, 'b>; + //~^ Missing required bounds + fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>; +} + +/* +impl Foo for () { + type Bar<'a, 'b> = &'a &'b (); + fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y> { + input + } +} +*/ + +// If there are multiple methods that return the GAT, require a set of clauses +// that can be satisfied by *all* methods +trait MultipleMethods { + type Bar<'me>; + + fn gimme<'a>(&'a self) -> Self::Bar<'a>; + fn gimme_default(&self) -> Self::Bar<'static>; +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr new file mode 100644 index 00000000000..bf85780f69f --- /dev/null +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -0,0 +1,98 @@ +error: Missing required bounds on Item + --> $DIR/self-outlives-lint.rs:9:5 + | +LL | type Item<'x>; + | ^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where Self: 'x` + +error: Missing required bounds on Out + --> $DIR/self-outlives-lint.rs:25:5 + | +LL | type Out<'x>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where T: 'x` + +error: Missing required bounds on Out + --> $DIR/self-outlives-lint.rs:39:5 + | +LL | type Out<'x>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where T: 'x` + +error: Missing required bounds on Out + --> $DIR/self-outlives-lint.rs:46:5 + | +LL | type Out<'x, 'y>; + | ^^^^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where T: 'x, U: 'y` + +error: Missing required bounds on Out + --> $DIR/self-outlives-lint.rs:61:5 + | +LL | type Out<'x, D>; + | ^^^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where D: 'x` + +error: Missing required bounds on Out + --> $DIR/self-outlives-lint.rs:77:5 + | +LL | type Out<'x, D>; + | ^^^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where D: 'x` + +error: Missing required bounds on Out + --> $DIR/self-outlives-lint.rs:92:5 + | +LL | type Out<'x, D>; + | ^^^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where D: 'x` + +error: Missing required bounds on Bar + --> $DIR/self-outlives-lint.rs:114:5 + | +LL | type Bar<'b>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where Self: 'a, Self: 'b` + +error: Missing required bounds on Bar + --> $DIR/self-outlives-lint.rs:122:5 + | +LL | type Bar<'b>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where Self: 'a, Self: 'b` + +error: Missing required bounds on Bar + --> $DIR/self-outlives-lint.rs:129:5 + | +LL | type Bar<'b>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where Self: 'b` + +error: Missing required bounds on Iterator + --> $DIR/self-outlives-lint.rs:143:5 + | +LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where Self: 'a` + +error: Missing required bounds on Bar + --> $DIR/self-outlives-lint.rs:150:5 + | +LL | type Bar<'a, 'b>; + | ^^^^^^^^^^^^^^^^- + | | + | help: add the required where clauses: `where 'a: 'b` + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/generic-associated-types/streaming_iterator.rs b/src/test/ui/generic-associated-types/streaming_iterator.rs index 2feff9f4c6f..f83d4d7b68e 100644 --- a/src/test/ui/generic-associated-types/streaming_iterator.rs +++ b/src/test/ui/generic-associated-types/streaming_iterator.rs @@ -5,12 +5,12 @@ use std::fmt::Display; trait StreamingIterator { - type Item<'a>; + type Item<'a> where Self: 'a; // Applying the lifetime parameter `'a` to `Self::Item` inside the trait. fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; } -struct Foo<T: StreamingIterator> { +struct Foo<T: StreamingIterator + 'static> { // Applying a concrete lifetime to the constructor outside the trait. bar: <T as StreamingIterator>::Item<'static>, } @@ -30,7 +30,7 @@ struct StreamEnumerate<I> { } impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> { - type Item<'a> = (usize, I::Item<'a>); + type Item<'a> where Self: 'a = (usize, I::Item<'a>); fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> { match self.iter.next() { None => None, @@ -44,7 +44,7 @@ impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> { } impl<I: Iterator> StreamingIterator for I { - type Item<'a> = <I as Iterator>::Item; + type Item<'a> where Self: 'a = <I as Iterator>::Item; fn next(&mut self) -> Option<<I as StreamingIterator>::Item<'_>> { Iterator::next(self) } diff --git a/src/test/ui/generic-associated-types/variance_constraints.rs b/src/test/ui/generic-associated-types/variance_constraints.rs index 7bc250ee87b..7d0f7638ac8 100644 --- a/src/test/ui/generic-associated-types/variance_constraints.rs +++ b/src/test/ui/generic-associated-types/variance_constraints.rs @@ -3,7 +3,7 @@ #![feature(generic_associated_types)] trait A { - type B<'a>; + type B<'a> where Self: 'a; fn make_b<'a>(&'a self) -> Self::B<'a>; } diff --git a/src/test/ui/hello2021.rs b/src/test/ui/hello2021.rs index 738f151b0f6..134d8af5bfb 100644 --- a/src/test/ui/hello2021.rs +++ b/src/test/ui/hello2021.rs @@ -1,6 +1,5 @@ // run-pass // edition:2021 -// compile-flags: -Zunstable-options fn main() { println!("hello, 2021"); diff --git a/src/test/ui/issues/issue-44005.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs index ab3b92142c8..f255eac0c4b 100644 --- a/src/test/ui/issues/issue-44005.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs @@ -1,3 +1,5 @@ +// check-pass + pub trait Foo<'a> { type Bar; fn foo(&'a self) -> Self::Bar; @@ -24,7 +26,6 @@ pub fn catalyst(x: &i32) { pub fn broken<F: Fn(&i32)>(x: &i32, f: F) { uncallable(x, |y| f(y)); - //~^ type mismatch } fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs index 24ac566f9df..7c3c72e04cb 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs @@ -77,7 +77,7 @@ where P: Execute + 'static { } fn main() { - task(annotate( //~ type mismatch + task(annotate( //~^ the size //~^^ the trait bound Annotate::<RefMutFamily<usize>>::new(), diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr index b13226fef6e..01b14660b65 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr @@ -1,29 +1,3 @@ -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-62529-1.rs:80:10 - | -LL | task(annotate( - | _____----_^ - | | | - | | required by a bound introduced by this call -LL | | -LL | | -LL | | Annotate::<RefMutFamily<usize>>::new(), -LL | | |value: &mut usize| { - | | ------------------- found signature of `for<'r> fn(&'r mut usize) -> _` -LL | | *value = 2; -LL | | } -LL | | )); - | |_____^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _` - | -note: required by a bound in `annotate` - --> $DIR/issue-62529-1.rs:44:8 - | -LL | fn annotate<F, Q>(_q: Annotate<Q>, func: F) -> impl Execute + 'static - | -------- required by a bound in this -LL | where -LL | F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out) + 'static, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `annotate` - error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time --> $DIR/issue-62529-1.rs:80:10 | @@ -73,7 +47,6 @@ LL | fn task<P>(processor: P) -> Task LL | where P: Execute + 'static { | ^^^^^^^ required by this bound in `task` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0631. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs index 87d1a250f7a..3ced40230f0 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs @@ -1,3 +1,5 @@ +// check-pass + pub trait MyTrait<'a> { type Output: 'a; fn gimme_value(&self) -> Self::Output; @@ -23,7 +25,7 @@ where fn main() { let struc = MyStruct; - meow(struc, |foo| { //~ type mismatch + meow(struc, |foo| { println!("{:?}", foo); }) } diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr deleted file mode 100644 index efc956888ee..00000000000 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-70120.rs:26:5 - | -LL | meow(struc, |foo| { - | ^^^^ ----- found signature of `for<'r> fn(&'r usize) -> _` - | | - | expected signature of `for<'any2> fn(<MyStruct as MyTrait<'any2>>::Output) -> _` - | -note: required by a bound in `meow` - --> $DIR/issue-70120.rs:18:8 - | -LL | fn meow<T, F>(t: T, f: F) - | ---- required by a bound in this -... -LL | F: for<'any2> Fn(<T as MyTrait<'any2>>::Output), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `meow` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr new file mode 100644 index 00000000000..119cec1fa95 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr @@ -0,0 +1,92 @@ +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:52:5 + | +LL | foo(bar, "string", |s| s.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:52:5 + | +LL | foo(bar, "string", |s| s.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:52:5 + | +LL | foo(bar, "string", |s| s.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:52:5 + | +LL | foo(bar, "string", |s| s.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:52:5 + | +LL | foo(bar, "string", |s| s.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:58:5 + | +LL | foo(baz, "string", |s| s.0.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:58:5 + | +LL | foo(baz, "string", |s| s.0.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:58:5 + | +LL | foo(baz, "string", |s| s.0.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:58:5 + | +LL | foo(baz, "string", |s| s.0.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: implementation of `Parser` is not general enough + --> $DIR/issue-71955.rs:58:5 + | +LL | foo(baz, "string", |s| s.0.len() == 5); + | ^^^ implementation of `Parser` is not general enough + | + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr new file mode 100644 index 00000000000..69ab446bc7a --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/issue-71955.rs:42:1 + | +LL | fn main() { + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs new file mode 100644 index 00000000000..95e3b3d4e1b --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs @@ -0,0 +1,64 @@ +// ignore-compare-mode-nll +// revisions: migrate nll +// [nll]compile-flags: -Zborrowck=mir +// check-fail + +#![feature(rustc_attrs)] + +trait Parser<'s> { + type Output; + + fn call(&self, input: &'s str) -> (&'s str, Self::Output); +} + +impl<'s, F, T> Parser<'s> for F +where F: Fn(&'s str) -> (&'s str, T) { + type Output = T; + fn call(&self, input: &'s str) -> (&'s str, T) { + self(input) + } +} + +fn foo<F1, F2>( + f1: F1, + base: &'static str, + f2: F2 +) +where + F1: for<'a> Parser<'a>, + F2: FnOnce(&<F1 as Parser>::Output) -> bool +{ + let s: String = base.to_owned(); + let str_ref = s.as_ref(); + let (remaining, produced) = f1.call(str_ref); + assert!(f2(&produced)); + assert_eq!(remaining.len(), 0); +} + +struct Wrapper<'a>(&'a str); + +// Because nll currently succeeds and migrate doesn't +#[rustc_error] +fn main() { + //[nll]~^ fatal + fn bar<'a>(s: &'a str) -> (&'a str, &'a str) { + (&s[..1], &s[..]) + } + + fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) { + (&s[..1], Wrapper(&s[..])) + } + + foo(bar, "string", |s| s.len() == 5); + //[migrate]~^ ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + foo(baz, "string", |s| s.0.len() == 5); + //[migrate]~^ ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough + //[migrate]~| ERROR implementation of `Parser` is not general enough +} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs new file mode 100644 index 00000000000..93ccb42684c --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs @@ -0,0 +1,30 @@ +// check-pass + +use std::marker::PhantomData; + +trait A<'a> { + type B; + fn b(self) -> Self::B; +} + +struct T; +struct S<'a>(PhantomData<&'a ()>); + +impl<'a> A<'a> for T { + type B = S<'a>; + fn b(self) -> Self::B { + S(PhantomData) + } +} + +fn s<TT, F>(t: TT, f: F) +where + TT: for<'a> A<'a>, + F: for<'a> FnOnce(<TT as A<'a>>::B) +{ + f(t.b()); +} + +fn main() { + s(T, |_| {}); +} diff --git a/src/test/ui/hrtb/issue-90177.rs b/src/test/ui/hrtb/issue-90177.rs new file mode 100644 index 00000000000..b151a9d3ab6 --- /dev/null +++ b/src/test/ui/hrtb/issue-90177.rs @@ -0,0 +1,32 @@ +// check-pass + +trait Base<'f> { + type Assoc; + + fn do_something(&self); +} + +trait ForAnyLifetime: for<'f> Base<'f> {} + +impl<T> ForAnyLifetime for T where T: for<'f> Base<'f> {} + +trait CanBeDynamic: ForAnyLifetime + for<'f> Base<'f, Assoc = ()> {} + +fn foo(a: &dyn CanBeDynamic) { + a.do_something(); +} + +struct S; + +impl<'a> Base<'a> for S { + type Assoc = (); + + fn do_something(&self) {} +} + +impl CanBeDynamic for S {} + +fn main() { + let s = S; + foo(&s); +} diff --git a/src/test/ui/issues/issue-44005.stderr b/src/test/ui/issues/issue-44005.stderr deleted file mode 100644 index 307e444e696..00000000000 --- a/src/test/ui/issues/issue-44005.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-44005.rs:26:5 - | -LL | uncallable(x, |y| f(y)); - | ^^^^^^^^^^ -------- found signature of `for<'r> fn(&'r i32) -> _` - | | - | expected signature of `for<'a> fn(<&i32 as Foo<'a>>::Bar) -> _` - | -note: required by a bound in `uncallable` - --> $DIR/issue-44005.rs:16:8 - | -LL | pub fn uncallable<T, F>(x: T, f: F) - | ---------- required by a bound in this -... -LL | F: for<'a> Fn(<T as Foo<'a>>::Bar), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `uncallable` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/iterators/into-iter-on-arrays-2021.rs b/src/test/ui/iterators/into-iter-on-arrays-2021.rs index ec54ed00517..158317efe47 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-2021.rs +++ b/src/test/ui/iterators/into-iter-on-arrays-2021.rs @@ -1,6 +1,5 @@ // check-pass // edition:2021 -// compile-flags: -Zunstable-options use std::array::IntoIter; use std::ops::Deref; diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.fixed b/src/test/ui/lifetimes/issue-90170-elision-mismatch.fixed new file mode 100644 index 00000000000..0bc889ee721 --- /dev/null +++ b/src/test/ui/lifetimes/issue-90170-elision-mismatch.fixed @@ -0,0 +1,9 @@ +// run-rustfix + +pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch + +pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch + +pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch + +fn main() {} diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr b/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr new file mode 100644 index 00000000000..a5bc7450bbf --- /dev/null +++ b/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr @@ -0,0 +1,29 @@ +error: lifetime may not live long enough + --> $DIR/issue-90170-elision-mismatch.rs:3:40 + | +LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } + | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | | | + | | let's call the lifetime of this reference `'1` + | let's call the lifetime of this reference `'2` + +error: lifetime may not live long enough + --> $DIR/issue-90170-elision-mismatch.rs:5:44 + | +LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } + | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | | | + | | let's call the lifetime of this reference `'1` + | let's call the lifetime of this reference `'2` + +error: lifetime may not live long enough + --> $DIR/issue-90170-elision-mismatch.rs:7:63 + | +LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } + | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | | | + | | let's call the lifetime of this reference `'1` + | let's call the lifetime of this reference `'2` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.rs b/src/test/ui/lifetimes/issue-90170-elision-mismatch.rs new file mode 100644 index 00000000000..1d6573c00ad --- /dev/null +++ b/src/test/ui/lifetimes/issue-90170-elision-mismatch.rs @@ -0,0 +1,9 @@ +// run-rustfix + +pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch + +pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch + +pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch + +fn main() {} diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.stderr b/src/test/ui/lifetimes/issue-90170-elision-mismatch.stderr new file mode 100644 index 00000000000..7fa092ca220 --- /dev/null +++ b/src/test/ui/lifetimes/issue-90170-elision-mismatch.stderr @@ -0,0 +1,45 @@ +error[E0623]: lifetime mismatch + --> $DIR/issue-90170-elision-mismatch.rs:3:47 + | +LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } + | --- --- ^ ...but data from `y` flows into `x` here + | | + | these two types are declared with different lifetimes... + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++++ ++ ++ + +error[E0623]: lifetime mismatch + --> $DIR/issue-90170-elision-mismatch.rs:5:51 + | +LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } + | ------ --- ^ ...but data from `y` flows into `x` here + | | + | these two types are declared with different lifetimes... + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++++ ~~ ++ + +error[E0623]: lifetime mismatch + --> $DIR/issue-90170-elision-mismatch.rs:7:70 + | +LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } + | --- --- ^ ...but data from `y` flows into `x` here + | | + | these two types are declared with different lifetimes... + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++ ++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr index 0aff80c6fbd..5c793636778 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -5,6 +5,12 @@ LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { | --- --- these two types are declared with different lifetimes... LL | *v = x; | ^ ...but data from `x` flows here + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr index 2e5ff6782d3..1a7b4fca1ba 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr @@ -5,6 +5,12 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { | --- --- these two types are declared with different lifetimes... LL | z.push((x,y)); | ^ ...but data flows into `z` here + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) { + | ++++ ++ ++ error[E0623]: lifetime mismatch --> $DIR/ex3-both-anon-regions-3.rs:2:15 @@ -13,6 +19,12 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { | --- --- these two types are declared with different lifetimes... LL | z.push((x,y)); | ^ ...but data flows into `z` here + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) { + | ++++ ++ ++ error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr index d2cc3dba6a4..6ed3528bb9f 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr @@ -5,6 +5,12 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { | --- --- these two types are declared with different lifetimes... LL | y.push(z); | ^ ...but data from `z` flows into `y` here + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr index 2acc4eaf60f..ede1631db27 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr @@ -5,6 +5,12 @@ LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) { | --- --- these two types are declared with different lifetimes... LL | y.push(z); | ^ ...but data from `z` flows into `y` here + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr index b2784827672..cf405c0de3f 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr @@ -5,6 +5,12 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) { | --- --- these two types are declared with different lifetimes... LL | x.push(y); | ^ ...but data from `y` flows into `x` here + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs index 3fab9148392..3a3d81176d6 100644 --- a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs +++ b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs @@ -1,6 +1,6 @@ // --force-warn $LINT causes $LINT (which is deny-by-default) to warn // despite $LINT being allowed on command line -// compile-flags: -A const_err --force-warn const_err -Zunstable-options +// compile-flags: -A const_err --force-warn const_err // check-pass const C: i32 = 1 / 0; diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs index 4eb05b538b0..9736027452a 100644 --- a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs +++ b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs @@ -1,6 +1,6 @@ // --force-warn $LINT_GROUP causes $LINT (which is warn-by-default) to warn // despite $LINT being allowed on command line -// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms -Zunstable-options +// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms // check-pass pub trait SomeTrait {} diff --git a/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs b/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs index d2cb3417be6..267e7b45f0c 100644 --- a/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs +++ b/src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs @@ -1,6 +1,6 @@ // --force-warn $LINT causes $LINT (which is warn-by-default) to warn // despite being allowed in one submodule (but not the other) -// compile-flags: --force-warn dead_code -Zunstable-options +// compile-flags: --force-warn dead_code // check-pass mod one { diff --git a/src/test/ui/lint/force-warn/warnings-lint-group.rs b/src/test/ui/lint/force-warn/warnings-lint-group.rs index fa25a1f8a84..d1d4f5602f2 100644 --- a/src/test/ui/lint/force-warn/warnings-lint-group.rs +++ b/src/test/ui/lint/force-warn/warnings-lint-group.rs @@ -1,5 +1,5 @@ // --force-warn warnings is an error -// compile-flags: --force-warn warnings -Zunstable-options +// compile-flags: --force-warn warnings // error-pattern: `warnings` lint group is not supported fn main() {} diff --git a/src/test/ui/lint/force-warn/warnings-lint-group.stderr b/src/test/ui/lint/force-warn/warnings-lint-group.stderr index 03f5788b527..1faeed33704 100644 --- a/src/test/ui/lint/force-warn/warnings-lint-group.stderr +++ b/src/test/ui/lint/force-warn/warnings-lint-group.stderr @@ -2,8 +2,6 @@ error[E0602]: `warnings` lint group is not supported with ´--force-warn´ error[E0602]: `warnings` lint group is not supported with ´--force-warn´ -error[E0602]: `warnings` lint group is not supported with ´--force-warn´ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0602`. diff --git a/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs b/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs new file mode 100644 index 00000000000..425e2703c94 --- /dev/null +++ b/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs @@ -0,0 +1,9 @@ +// check-pass +// Allowing the code lint should work without warning and +// the text flow char in the comment should be ignored. + +#![allow(text_direction_codepoint_in_comment)] + +fn main() { + // U+2066 LEFT-TO-RIGHT ISOLATE follows: +} diff --git a/src/test/ui/lint/unused_parens_json_suggestion.fixed b/src/test/ui/lint/unused_parens_json_suggestion.fixed index 15ee19755bf..c4004540467 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.fixed +++ b/src/test/ui/lint/unused_parens_json_suggestion.fixed @@ -1,4 +1,4 @@ -// compile-flags: --error-format json -Zunstable-options +// compile-flags: --error-format json // run-rustfix // The output for humans should just highlight the whole span without showing diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs index d72df21e09a..962c8bdd7d7 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_json_suggestion.rs @@ -1,4 +1,4 @@ -// compile-flags: --error-format json -Zunstable-options +// compile-flags: --error-format json // run-rustfix // The output for humans should just highlight the whole span without showing diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 498c25d2e1c..169fb824021 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -1,4 +1,4 @@ -{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":597,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3)); +{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":577,"byte_end":578,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3)); --> $DIR/unused_parens_json_suggestion.rs:16:14 | LL | let _a = (1 / (2 + 3)); diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed index 1d891d328dd..8a57cd57385 100644 --- a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed @@ -1,4 +1,4 @@ -// compile-flags: --error-format json -Zunstable-options +// compile-flags: --error-format json // run-rustfix // The output for humans should just highlight the whole span without showing diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs index 494cd184506..952332d54e9 100644 --- a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs @@ -1,4 +1,4 @@ -// compile-flags: --error-format json -Zunstable-options +// compile-flags: --error-format json // run-rustfix // The output for humans should just highlight the whole span without showing diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr index 08291b10fcc..43367aaa911 100644 --- a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr @@ -1,4 +1,4 @@ -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":501,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) { +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":481,"byte_end":482,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) { --> $DIR/unused_parens_remove_json_suggestion.rs:17:8 | LL | if (_b) { @@ -16,7 +16,7 @@ LL + if _b { | "} -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":632,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) { +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":612,"byte_end":613,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) { --> $DIR/unused_parens_remove_json_suggestion.rs:28:7 | LL | if(c) { @@ -29,7 +29,7 @@ LL + if c { | "} -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":712,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){ +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":692,"byte_end":693,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){ --> $DIR/unused_parens_remove_json_suggestion.rs:32:8 | LL | if (c){ @@ -42,7 +42,7 @@ LL + if c { | "} -{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition --> $DIR/unused_parens_remove_json_suggestion.rs:36:11 | LL | while (false && true){ @@ -55,7 +55,7 @@ LL + while false && true { | "} -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) { +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":802,"byte_end":803,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) { --> $DIR/unused_parens_remove_json_suggestion.rs:37:12 | LL | if (c) { @@ -68,7 +68,7 @@ LL + if c { | "} -{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":919,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) { +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":899,"byte_end":900,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) { --> $DIR/unused_parens_remove_json_suggestion.rs:43:10 | LL | while(true && false) { @@ -81,7 +81,7 @@ LL + while true && false { | "} -{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":988,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){ +{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":968,"byte_end":969,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){ --> $DIR/unused_parens_remove_json_suggestion.rs:44:18 | LL | for _ in (0 .. 3){ @@ -94,7 +94,7 @@ LL + for _ in 0 .. 3 { | "} -{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1089,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) { +{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1069,"byte_end":1070,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) { --> $DIR/unused_parens_remove_json_suggestion.rs:49:14 | LL | for _ in (0 .. 3) { @@ -107,7 +107,7 @@ LL + for _ in 0 .. 3 { | "} -{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1148,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) { +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1128,"byte_end":1129,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) { --> $DIR/unused_parens_remove_json_suggestion.rs:50:15 | LL | while (true && false) { diff --git a/src/test/ui/matches2021.rs b/src/test/ui/matches2021.rs index f5497c1d16d..9143a8cdd59 100644 --- a/src/test/ui/matches2021.rs +++ b/src/test/ui/matches2021.rs @@ -1,6 +1,5 @@ // run-pass // edition:2021 -// compile-flags: -Zunstable-options // regression test for https://github.com/rust-lang/rust/pull/85678 diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs deleted file mode 100644 index 374a9f75a13..00000000000 --- a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs +++ /dev/null @@ -1,48 +0,0 @@ -// compile-flags: -Zunleash-the-miri-inside-of-you - -// This test demonstrates a shortcoming of the `MaybeMutBorrowedLocals` analysis. It does not -// handle code that takes a reference to one field of a struct, then use pointer arithmetic to -// transform it to another field of that same struct that may have interior mutability. For now, -// this is UB, but this may change in the future. See [rust-lang/unsafe-code-guidelines#134]. -// -// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 - -#![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)] - -use std::cell::UnsafeCell; -use std::intrinsics::rustc_peek; - -#[repr(C)] -struct PartialInteriorMut { - zst: [i32; 0], - cell: UnsafeCell<i32>, -} - -#[rustc_mir(rustc_peek_indirectly_mutable,stop_after_dataflow)] -const BOO: i32 = { - let x = PartialInteriorMut { - zst: [], - cell: UnsafeCell::new(0), - }; - - let p_zst: *const _ = &x.zst ; // Doesn't cause `x` to get marked as indirectly mutable. - - let rmut_cell = unsafe { - // Take advantage of the fact that `zst` and `cell` are at the same location in memory. - // This trick would work with any size type if miri implemented `ptr::offset`. - let p_cell = p_zst as *const UnsafeCell<i32>; - - let pmut_cell = (*p_cell).get(); - &mut *pmut_cell - }; - - *rmut_cell = 42; // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!! - let val = *rmut_cell; - rustc_peek(x); //~ ERROR rustc_peek: bit not set - - val -}; - -fn main() { - println!("{}", BOO); -} diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr deleted file mode 100644 index 1d5287c15ab..00000000000 --- a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: rustc_peek: bit not set - --> $DIR/indirect-mutation-offset.rs:41:5 - | -LL | rustc_peek(x); - | ^^^^^^^^^^^^^ - -error: stop_after_dataflow ended compilation - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs index f926eee9d92..ec8666f93f0 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -1,5 +1,6 @@ // aux-crate:priv:priv_dep=priv_dep.rs // aux-build:pub_dep.rs +// compile-flags: -Zunstable-options #![deny(exported_private_dependencies)] // This crate is a private dependency diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr index e6b4d33f103..f64b8569015 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -1,23 +1,23 @@ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:20:5 + --> $DIR/pub-priv1.rs:21:5 | LL | pub field: OtherType, | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/pub-priv1.rs:3:9 + --> $DIR/pub-priv1.rs:4:9 | LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:27:5 + --> $DIR/pub-priv1.rs:28:5 | LL | pub fn pub_fn(param: OtherType) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:34:5 + --> $DIR/pub-priv1.rs:35:5 | LL | type Foo: OtherTrait; | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/auxiliary/api/parse.rs b/src/test/ui/proc-macro/auxiliary/api/parse.rs index 93551ebaf82..6186b941ef6 100644 --- a/src/test/ui/proc-macro/auxiliary/api/parse.rs +++ b/src/test/ui/proc-macro/auxiliary/api/parse.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + use proc_macro::Literal; pub fn test() { @@ -8,6 +10,14 @@ pub fn test() { fn test_display_literal() { assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10"); assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize"); + assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0"); + assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32"); + assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0"); + assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64"); + assert_eq!( + Literal::f64_unsuffixed(1e100).to_string(), + "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", + ); } fn test_parse_literal() { diff --git a/src/test/ui/rust-2021/prelude2021.rs b/src/test/ui/rust-2021/prelude2021.rs index 3a9fd693228..a63b6fcf262 100644 --- a/src/test/ui/rust-2021/prelude2021.rs +++ b/src/test/ui/rust-2021/prelude2021.rs @@ -1,6 +1,5 @@ // check-pass // edition:2021 -// compile-flags: -Zunstable-options fn main() { let _: u16 = 123i32.try_into().unwrap(); diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed index e026f01e93f..eed2f313abe 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed @@ -1,6 +1,6 @@ // check-pass // run-rustfix -// compile-flags: -Z unstable-options --edition 2018 +// edition:2018 #![warn(rust_2021_prefixes_incompatible_syntax)] diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.rs b/src/test/ui/rust-2021/reserved-prefixes-migration.rs index d24f2963480..0565db793df 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.rs +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.rs @@ -1,6 +1,6 @@ // check-pass // run-rustfix -// compile-flags: -Z unstable-options --edition 2018 +// edition:2018 #![warn(rust_2021_prefixes_incompatible_syntax)] diff --git a/src/test/ui/suggestions/undeclared-module-alloc.rs b/src/test/ui/suggestions/undeclared-module-alloc.rs new file mode 100644 index 00000000000..1defa1cef28 --- /dev/null +++ b/src/test/ui/suggestions/undeclared-module-alloc.rs @@ -0,0 +1,5 @@ +// edition:2018 + +use alloc::rc::Rc; //~ ERROR failed to resolve: use of undeclared crate or module `alloc` + +fn main() {} diff --git a/src/test/ui/suggestions/undeclared-module-alloc.stderr b/src/test/ui/suggestions/undeclared-module-alloc.stderr new file mode 100644 index 00000000000..39169dfa9f7 --- /dev/null +++ b/src/test/ui/suggestions/undeclared-module-alloc.stderr @@ -0,0 +1,11 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `alloc` + --> $DIR/undeclared-module-alloc.rs:3:5 + | +LL | use alloc::rc::Rc; + | ^^^^^ use of undeclared crate or module `alloc` + | + = help: add `extern crate alloc` to use the `alloc` crate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr index 76c14ccc14b..8976da01e73 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr @@ -5,6 +5,12 @@ LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } | ------ ------ ^ ...but data from `y` flows into `x` here | | | these two types are declared with different lifetimes... + | + = note: each elided lifetime in input position becomes a distinct lifetime +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++++ ~~ ~~ error: aborting due to previous error diff --git a/src/test/ui/unsized/unchanged-param.rs b/src/test/ui/unsized/unchanged-param.rs index 83199e8112e..93c7af68ac3 100644 --- a/src/test/ui/unsized/unchanged-param.rs +++ b/src/test/ui/unsized/unchanged-param.rs @@ -1,4 +1,3 @@ -#![feature(relaxed_struct_unsize)] // run-pass // Test that we allow unsizing even if there is an unchanged param in the // field getting unsized. diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs index 9339a004d3b..6ac558974d0 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs @@ -1,7 +1,7 @@ // --extern-location with a raw reference // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar +// compile-flags:--extern-location bar -Zunstable-options #![warn(unused_crate_dependencies)] diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 6c1bc24b8b49d4bc965f67d7037906dc199c72b +Subproject 94ca096afbf25f670e76e07dca754fcfe27134b diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config.toml index 688473f2f9b..688473f2f9b 100644 --- a/src/tools/clippy/.cargo/config +++ b/src/tools/clippy/.cargo/config.toml diff --git a/src/tools/clippy/.github/deploy.sh b/src/tools/clippy/.github/deploy.sh index a3c57232f55..34225a54029 100644 --- a/src/tools/clippy/.github/deploy.sh +++ b/src/tools/clippy/.github/deploy.sh @@ -13,7 +13,8 @@ cp util/gh-pages/lints.json out/master if [[ -n $TAG_NAME ]]; then echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it" cp -Tr out/master "out/$TAG_NAME" - ln -sf "$TAG_NAME" out/stable + rm -f out/stable + ln -s "$TAG_NAME" out/stable fi if [[ $BETA = "true" ]]; then diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 3b4c687209e..85a6a6be8b7 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,162 @@ document. ## Unreleased / In Rust Nightly -[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master) +[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master) + +## Rust 1.57 + +Current beta, release 2021-12-02 + +[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f) + +### New Lints + +* [`negative_feature_names`] + [#7539](https://github.com/rust-lang/rust-clippy/pull/7539) +* [`redundant_feature_names`] + [#7539](https://github.com/rust-lang/rust-clippy/pull/7539) +* [`mod_module_files`] + [#7543](https://github.com/rust-lang/rust-clippy/pull/7543) +* [`self_named_module_files`] + [#7543](https://github.com/rust-lang/rust-clippy/pull/7543) +* [`manual_split_once`] + [#7565](https://github.com/rust-lang/rust-clippy/pull/7565) +* [`derivable_impls`] + [#7570](https://github.com/rust-lang/rust-clippy/pull/7570) +* [`needless_option_as_deref`] + [#7596](https://github.com/rust-lang/rust-clippy/pull/7596) +* [`iter_not_returning_iterator`] + [#7610](https://github.com/rust-lang/rust-clippy/pull/7610) +* [`same_name_method`] + [#7653](https://github.com/rust-lang/rust-clippy/pull/7653) +* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669) +* [`non_send_fields_in_send_ty`] + [#7709](https://github.com/rust-lang/rust-clippy/pull/7709) +* [`equatable_if_let`] + [#7762](https://github.com/rust-lang/rust-clippy/pull/7762) + +### Moves and Deprecations + +* Move [`shadow_unrelated`] to `restriction` + [#7338](https://github.com/rust-lang/rust-clippy/pull/7338) +* Move [`option_if_let_else`] to `nursery` + [#7568](https://github.com/rust-lang/rust-clippy/pull/7568) +* Move [`branches_sharing_code`] to `nursery` + [#7595](https://github.com/rust-lang/rust-clippy/pull/7595) +* Rename `if_let_some_result` to [`match_result_ok`] which now also handles + `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608) +* Move [`many_single_char_names`] to `pedantic` + [#7671](https://github.com/rust-lang/rust-clippy/pull/7671) +* Move [`float_cmp`] to `pedantic` + [#7692](https://github.com/rust-lang/rust-clippy/pull/7692) +* Rename `box_vec` to [`box_collection`] and lint on more general cases + [#7693](https://github.com/rust-lang/rust-clippy/pull/7693) +* Uplift `invalid_atomic_ordering` to rustc + [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039) + +### Enhancements + +* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not + limited to certain patterns + [#7338](https://github.com/rust-lang/rust-clippy/pull/7338) +* The `avoid-breaking-exported-api` configuration now also works for + [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`], + [`option_option`], [`linkedlist`], [`rc_mutex`] + [#7560](https://github.com/rust-lang/rust-clippy/pull/7560) +* [`unnecessary_unwrap`]: Now also checks for `expect`s + [#7584](https://github.com/rust-lang/rust-clippy/pull/7584) +* [`disallowed_method`]: Allow adding a reason that will be displayed with the + lint message + [#7621](https://github.com/rust-lang/rust-clippy/pull/7621) +* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10` + [#7629](https://github.com/rust-lang/rust-clippy/pull/7629) +* [`approx_constant`]: Add `TAU` + [#7642](https://github.com/rust-lang/rust-clippy/pull/7642) +* [`needless_borrow`]: Now also lints on needless mutable borrows + [#7657](https://github.com/rust-lang/rust-clippy/pull/7657) +* [`missing_safety_doc`]: Now also lints on unsafe traits + [#7734](https://github.com/rust-lang/rust-clippy/pull/7734) + +### False Positive Fixes + +* [`manual_map`]: No longer lints when the option is borrowed in the match and + also consumed in the arm + [#7531](https://github.com/rust-lang/rust-clippy/pull/7531) +* [`filter_next`]: No longer lints if `filter` method is not the + `Iterator::filter` method + [#7562](https://github.com/rust-lang/rust-clippy/pull/7562) +* [`manual_flatten`]: No longer lints if expression is used after `if let` + [#7566](https://github.com/rust-lang/rust-clippy/pull/7566) +* [`option_if_let_else`]: Multiple fixes + [#7573](https://github.com/rust-lang/rust-clippy/pull/7573) + * `break` and `continue` statements local to the would-be closure are + allowed + * Don't lint in const contexts + * Don't lint when yield expressions are used + * Don't lint when the captures made by the would-be closure conflict with + the other branch + * Don't lint when a field of a local is used when the type could be + potentially moved from + * In some cases, don't lint when scrutinee expression conflicts with the + captures of the would-be closure +* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces + wide pointers with thin pointers + [#7592](https://github.com/rust-lang/rust-clippy/pull/7592) +* [`bool_assert_comparison`]: No longer lints on types that do not implement the + `Not` trait with `Output = bool` + [#7605](https://github.com/rust-lang/rust-clippy/pull/7605) +* [`mut_range_bound`]: No longer lints on range bound mutations, that are + immediately followed by a `break;` + [#7607](https://github.com/rust-lang/rust-clippy/pull/7607) +* [`mutable_key_type`]: Improve accuracy and document remaining false positives + and false negatives + [#7640](https://github.com/rust-lang/rust-clippy/pull/7640) +* [`redundant_closure`]: Rewrite the lint to fix various false positives and + false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661) +* [`large_enum_variant`]: No longer wrongly identifies the second largest + variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677) +* [`needless_return`]: No longer lints on let-else expressions + [#7685](https://github.com/rust-lang/rust-clippy/pull/7685) +* [`suspicious_else_formatting`]: No longer lints in proc-macros + [#7707](https://github.com/rust-lang/rust-clippy/pull/7707) +* [`excessive_precision`]: No longer lints when in some cases the float was + already written in the shortest form + [#7722](https://github.com/rust-lang/rust-clippy/pull/7722) +* [`doc_markdown`]: No longer lints on intra-doc links + [#7772](https://github.com/rust-lang/rust-clippy/pull/7772) + +### Suggestion Fixes/Improvements + +* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a + function call in an indexing operation + [#7453](https://github.com/rust-lang/rust-clippy/pull/7453) +* [`manual_split_once`]: Produce semantically equivalent suggestion when + `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663) +* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut` + [#7690](https://github.com/rust-lang/rust-clippy/pull/7690) +* [`manual_assert`]: No better handles complex conditions + [#7741](https://github.com/rust-lang/rust-clippy/pull/7741) +* Correctly handle signs in exponents in numeric literals lints + [#7747](https://github.com/rust-lang/rust-clippy/pull/7747) +* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative + [#7770](https://github.com/rust-lang/rust-clippy/pull/7770) +* Drop exponent from suggestion if it is 0 in numeric literals lints + [#7774](https://github.com/rust-lang/rust-clippy/pull/7774) + +### ICE Fixes + +* [`implicit_hasher`] + [#7761](https://github.com/rust-lang/rust-clippy/pull/7761) + +### Others + +* Clippy now uses the 2021 + [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro) + [#7664](https://github.com/rust-lang/rust-clippy/pull/7664) ## Rust 1.56 -Current beta, release 2021-10-21 +Current stable, released 2021-10-21 [74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e) @@ -74,13 +225,9 @@ Current beta, release 2021-10-21 * [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507) -### New Lints - -* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case. - ## Rust 1.55 -Current stable, released 2021-09-09 +Released 2021-09-09 [3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561) @@ -2748,7 +2895,6 @@ Released 2018-09-13 [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else -[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone @@ -2806,6 +2952,7 @@ Released 2018-09-13 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion +[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map @@ -2976,6 +3123,7 @@ Released 2018-09-13 [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned +[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same @@ -3000,6 +3148,7 @@ Released 2018-09-13 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes +[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools @@ -3046,6 +3195,7 @@ Released 2018-09-13 [`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp +[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 4273fda4e64..97ff31b4bc5 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -262,7 +262,9 @@ to be run inside the `rust` directory): 2. Checkout the commit from the latest available nightly. You can get it using `rustup check`. 3. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash - # Make sure to change `your-github-name` to your github name in the following command + # Make sure to change `your-github-name` to your github name in the following command. Also be + # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand + # because changes cannot be fast forwarded git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust ``` diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index ed7fb144013..602877bb9d6 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -22,13 +22,13 @@ path = "src/driver.rs" [dependencies] clippy_lints = { version = "0.1", path = "clippy_lints" } -semver = "0.11" +semver = "1.0" rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } tempfile = { version = "3.2", optional = true } [dev-dependencies] -cargo_metadata = "0.12" -compiletest_rs = { version = "0.7", features = ["tmp"] } +cargo_metadata = "0.14" +compiletest_rs = { version = "0.7.1", features = ["tmp"] } tester = "0.9" regex = "1.5" # This is used by the `collect-metadata` alias. diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 25320907bb4..43a478ee77d 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -42,7 +42,8 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; - create_test(&lint).context("Unable to create a test for the new lint") + create_test(&lint).context("Unable to create a test for the new lint")?; + add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs") } fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { @@ -80,6 +81,33 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { } } +fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { + let path = "clippy_lints/src/lib.rs"; + let mut lib_rs = fs::read_to_string(path).context("reading")?; + + let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment"); + + let new_lint = if enable_msrv { + format!( + "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ", + lint_pass = lint.pass, + module_name = lint.name, + camel_name = to_camel_case(lint.name), + ) + } else { + format!( + "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ", + lint_pass = lint.pass, + module_name = lint.name, + camel_name = to_camel_case(lint.name), + ) + }; + + lib_rs.insert_str(comment_start, &new_lint); + + fs::write(path, lib_rs).context("writing") +} + fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { OpenOptions::new() @@ -151,7 +179,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }; let lint_name = lint.name; - let pass_name = lint.pass; let category = lint.category; let name_camel = to_camel_case(lint.name); let name_upper = lint_name.to_uppercase(); @@ -228,18 +255,14 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { extract_msrv_attr!({context_import}); }} - // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, - // e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv))); // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, - pass_name = pass_name, name_upper = name_upper, name_camel = name_camel, - module_name = lint_name, context_import = context_import, ) } else { @@ -248,16 +271,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { declare_lint_pass!({name_camel} => [{name_upper}]); impl {pass_type}{pass_lifetimes} for {name_camel} {{}} - // - // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, - // e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel})); "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, - pass_name = pass_name, name_upper = name_upper, name_camel = name_camel, - module_name = lint_name, ) }); diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index aaf9ac83d49..281480b8d94 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2021" [dependencies] -cargo_metadata = "0.12" +cargo_metadata = "0.14" clippy_utils = { path = "../clippy_utils" } if_chain = "1.0" itertools = "0.10" @@ -21,7 +21,7 @@ serde_json = { version = "1.0", optional = true } toml = "0.5" unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } -semver = "0.11" +semver = "1.0" rustc-semver = "1.1" # NOTE: cargo requires serde feat in its url dep # see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864> diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 833ad122e0d..4af412ccaf3 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,15 +1,88 @@ +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::expr_or_init; use clippy_utils::ty::is_isize_or_usize; -use rustc_hir::Expr; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; use super::{utils, CAST_POSSIBLE_TRUNCATION}; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { +fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { + if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { + Some(c) + } else { + None + } +} + +fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> { + constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros())) +} + +fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 { + match expr_or_init(cx, expr).kind { + ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed), + ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)), + ExprKind::Binary(op, left, right) => match op.node { + BinOpKind::Div => { + apply_reductions(cx, nbits, left, signed) + - (if signed { + 0 // let's be conservative here + } else { + // by dividing by 1, we remove 0 bits, etc. + get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1)) + }) + }, + BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) + .unwrap_or(u64::max_value()) + .min(apply_reductions(cx, nbits, left, signed)), + BinOpKind::Shr => { + apply_reductions(cx, nbits, left, signed) + - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high")) + }, + _ => nbits, + }, + ExprKind::MethodCall(method, _, [left, right], _) => { + if signed { + return nbits; + } + let max_bits = if method.ident.as_str() == "min" { + get_constant_bits(cx, right) + } else { + None + }; + apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) + }, + ExprKind::MethodCall(method, _, [_, lo, hi], _) => { + if method.ident.as_str() == "clamp" { + //FIXME: make this a diagnostic item + if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { + return lo_bits.max(hi_bits); + } + } + nbits + }, + ExprKind::MethodCall(method, _, [_value], _) => { + if method.ident.name.as_str() == "signum" { + 0 // do not lint if cast comes from a `signum` function + } else { + nbits + } + }, + _ => nbits, + } +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { let msg = match (cast_from.is_integral(), cast_to.is_integral()) { (true, true) => { - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); + let from_nbits = apply_reductions( + cx, + utils::int_ty_to_nbits(cast_from, cx.tcx), + cast_expr, + cast_from.is_signed(), + ); let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index f0800c6a6f1..233abd17894 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { - cast_possible_truncation::check(cx, expr, cast_from, cast_to); + cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to); diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index c604516742c..9d8524ec91c 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -1,3 +1,6 @@ +// NOTE: if you add a deprecated lint in this file, please add a corresponding test in +// tests/ui/deprecated.rs + /// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This /// enables the simple extraction of the metadata without changing the current deprecation /// declaration. diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 7825e5f6ed5..ce59311c4aa 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { target_mut, }, )); - } + }, _ => (), } }, diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 5511c3ea9b6..87ad5178ff0 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -1,6 +1,6 @@ use clippy_utils::attrs::is_doc_hidden; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note}; -use clippy_utils::source::first_line_of_span; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::source::{first_line_of_span, snippet_with_applicability}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; use if_chain::if_chain; @@ -10,7 +10,7 @@ use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::Handler; +use rustc_errors::{Applicability, Handler}; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{AnonConst, Expr, ExprKind, QPath}; @@ -48,7 +48,7 @@ declare_clippy_lint! { /// content are not linted. /// /// In addition, when writing documentation comments, including `[]` brackets - /// inside a link text would trip the parser. Therfore, documenting link with + /// inside a link text would trip the parser. Therefore, documenting link with /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec /// would fail. /// @@ -578,9 +578,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize // text "http://example.com" by pulldown-cmark continue; } - headers.safety |= in_heading && text.trim() == "Safety"; - headers.errors |= in_heading && text.trim() == "Errors"; - headers.panics |= in_heading && text.trim() == "Panics"; + let trimmed_text = text.trim(); + headers.safety |= in_heading && trimmed_text == "Safety"; + headers.safety |= in_heading && trimmed_text == "Implementation safety"; + headers.safety |= in_heading && trimmed_text == "Implementation Safety"; + headers.errors |= in_heading && trimmed_text == "Errors"; + headers.panics |= in_heading && trimmed_text == "Panics"; if in_code { if is_rust { let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition()); @@ -686,10 +689,18 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str for word in text.split(|c: char| c.is_whitespace() || c == '\'') { // Trim punctuation as in `some comment (see foo::bar).` // ^^ - // Or even as in `_foo bar_` which is emphasized. - let word = word.trim_matches(|c: char| !c.is_alphanumeric()); + // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. + let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); - if valid_idents.contains(word) { + // Remove leading or trailing single `:` which may be part of a sentence. + if word.starts_with(':') && !word.starts_with("::") { + word = word.trim_start_matches(':'); + } + if word.ends_with(':') && !word.ends_with("::") { + word = word.trim_end_matches(':'); + } + + if valid_idents.contains(word) || word.chars().all(|c| c == ':') { continue; } @@ -744,17 +755,22 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { } } - // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343) + // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) if has_underscore(word) && has_hyphen(word) { return; } if has_underscore(word) || word.contains("::") || is_camel_case(word) { - span_lint( + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( cx, DOC_MARKDOWN, span, - &format!("you should put `{}` between ticks in the documentation", word), + "item in documentation is missing backticks", + "try", + format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)), + applicability, ); } } @@ -793,9 +809,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option) - || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result) + let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) + || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) { self.panic_span = Some(expr.span); } diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index ac6824672f6..57fd24bd4f0 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map ExprKind::MethodCall( _, _, - [map, Expr { - kind: ExprKind::AddrOf(_, _, key), - span: key_span, - .. - }], + [ + map, + Expr { + kind: ExprKind::AddrOf(_, _, key), + span: key_span, + .. + }, + ], _, ) if key_span.ctxt() == expr.span.ctxt() => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 174260fabd2..404b67c8f29 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -1,8 +1,8 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use clippy_utils::camel_case; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; +use clippy_utils::str_utils::{self, count_match_end, count_match_start}; use rustc_hir::{EnumDef, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [ MODULE_INCEPTION ]); -/// Returns the number of chars that match from the start -#[must_use] -fn partial_match(pre: &str, name: &str) -> usize { - let mut name_iter = name.chars(); - let _ = name_iter.next_back(); // make sure the name is never fully matched - pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count() -} - -/// Returns the number of chars that match from the end -#[must_use] -fn partial_rmatch(post: &str, name: &str) -> usize { - let mut name_iter = name.chars(); - let _ = name_iter.next(); // make sure the name is never fully matched - post.chars() - .rev() - .zip(name_iter.rev()) - .take_while(|&(l, r)| l == r) - .count() -} - fn check_variant( cx: &LateContext<'_>, threshold: u64, @@ -150,7 +130,7 @@ fn check_variant( } for var in def.variants { let name = var.ident.name.as_str(); - if partial_match(item_name, &name) == item_name_chars + if count_match_start(item_name, &name).char_count == item_name_chars && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) { @@ -161,7 +141,7 @@ fn check_variant( "variant name starts with the enum's name", ); } - if partial_rmatch(item_name, &name) == item_name_chars { + if count_match_end(item_name, &name).char_count == item_name_chars { span_lint( cx, ENUM_VARIANT_NAMES, @@ -171,14 +151,14 @@ fn check_variant( } } let first = &def.variants[0].ident.name.as_str(); - let mut pre = &first[..camel_case::until(&*first)]; - let mut post = &first[camel_case::from(&*first)..]; + let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index]; + let mut post = &first[str_utils::camel_case_start(&*first).byte_index..]; for var in def.variants { let name = var.ident.name.as_str(); - let pre_match = partial_match(pre, &name); + let pre_match = count_match_start(pre, &name).byte_count; pre = &pre[..pre_match]; - let pre_camel = camel_case::until(pre); + let pre_camel = str_utils::camel_case_until(pre).byte_index; pre = &pre[..pre_camel]; while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { if next.is_numeric() { @@ -186,18 +166,18 @@ fn check_variant( } if next.is_lowercase() { let last = pre.len() - last.len_utf8(); - let last_camel = camel_case::until(&pre[..last]); - pre = &pre[..last_camel]; + let last_camel = str_utils::camel_case_until(&pre[..last]); + pre = &pre[..last_camel.byte_index]; } else { break; } } - let post_match = partial_rmatch(post, &name); - let post_end = post.len() - post_match; + let post_match = count_match_end(post, &name); + let post_end = post.len() - post_match.byte_count; post = &post[post_end..]; - let post_camel = camel_case::from(post); - post = &post[post_camel..]; + let post_camel = str_utils::camel_case_start(post); + post = &post[post_camel.byte_index..]; } let (what, value) = match (pre.is_empty(), post.is_empty()) { (true, true) => return, @@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames { ); } } - if item.vis.node.is_pub() { - let matching = partial_match(mod_camel, &item_camel); - let rmatching = partial_rmatch(mod_camel, &item_camel); + // The `module_name_repetitions` lint should only trigger if the item has the module in its + // name. Having the same name is accepted. + if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() { + let matching = count_match_start(mod_camel, &item_camel); + let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric(); - if matching == nchars { + if matching.char_count == nchars { match item_camel.chars().nth(nchars) { Some(c) if is_word_beginning(c) => span_lint( cx, @@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames { _ => (), } } - if rmatching == nchars { + if rmatching.char_count == nchars { span_lint( cx, MODULE_NAME_REPETITIONS, diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 765a6c7585a..9247343b52a 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_ } match *cx.typeck_results().expr_adjustments(arg) { [] => true, - [Adjustment { - kind: Adjust::Deref(None), - .. - }, Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), - .. - }] => { + [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), + .. + }, + ] => { // re-borrow with the same mutability is allowed let ty = cx.typeck_results().expr_ty(arg); matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into()) diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index c22f9d0e170..7169ac9ad6c 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -49,15 +49,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { let mut applicability = Applicability::MachineApplicable; if format_args.value_args.is_empty() { - if_chain! { - if let [e] = &*format_args.format_string_parts; - if let ExprKind::Lit(lit) = &e.kind; - if let Some(s_src) = snippet_opt(cx, lit.span); - then { - // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = s_src.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); - span_useless_format(cx, call_site, sugg, applicability); + if format_args.format_string_parts.is_empty() { + span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability); + } else { + if_chain! { + if let [e] = &*format_args.format_string_parts; + if let ExprKind::Lit(lit) = &e.kind; + if let Some(s_src) = snippet_opt(cx, lit.span); + then { + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = s_src.replace("{{", "{").replace("}}", "}"); + let sugg = format!("{}.to_string()", s_expand); + span_useless_format(cx, call_site, sugg, applicability); + } } } } else if let [value] = *format_args.value_args { @@ -89,6 +93,18 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { } } +fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { + span_lint_and_sugg( + cx, + USELESS_FORMAT, + span, + "useless use of `format!`", + "consider using `String::new()`", + sugg, + applicability, + ); +} + fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs index 3ce91d421ba..ac938156237 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -2,9 +2,9 @@ //! on the condition use clippy_utils::diagnostics::span_lint_and_help; -use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp}; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_middle::lint::in_external_macro; +use clippy_utils::is_else_clause; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -46,14 +46,21 @@ declare_clippy_lint! { declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]); -impl EarlyLintPass for IfNotElse { - fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { - if in_external_macro(cx.sess, item.span) { +impl LateLintPass<'_> for IfNotElse { + fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { + // While loops will be desugared to ExprKind::If. This will cause the lint to fire. + // To fix this, return early if this span comes from a macro or desugaring. + if item.span.from_expansion() { return; } - if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind { + if let ExprKind::If(cond, _, Some(els)) = item.kind { if let ExprKind::Block(..) = els.kind { - match cond.kind { + // Disable firing the lint in "else if" expressions. + if is_else_clause(cx.tcx, item) { + return; + } + + match cond.peel_drop_temps().kind { ExprKind::Unary(UnOp::Not, _) => { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs index 49b69dd072a..6850e0c3476 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -89,7 +89,7 @@ impl IntPlusOne { }, _ => None, } - } + }, // case where `x + 1 <= ...` or `1 + x <= ...` (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => @@ -104,7 +104,7 @@ impl IntPlusOne { }, _ => None, } - } + }, // case where `... >= y - 1` or `... >= -1 + y` (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs index b1f70b30c12..82438d85c7a 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -1,5 +1,3 @@ -use std::cmp::Ordering; - use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; @@ -7,11 +5,11 @@ use rustc_middle::ty::{self, IntTy, UintTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; +use clippy_utils::comparisons; use clippy_utils::comparisons::Rel; -use clippy_utils::consts::{constant, Constant}; +use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; -use clippy_utils::{comparisons, sext}; declare_clippy_lint! { /// ### What it does @@ -39,53 +37,6 @@ declare_clippy_lint! { declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]); -#[derive(Copy, Clone, Debug, Eq)] -enum FullInt { - S(i128), - U(u128), -} - -impl FullInt { - #[allow(clippy::cast_sign_loss)] - #[must_use] - fn cmp_s_u(s: i128, u: u128) -> Ordering { - if s < 0 { - Ordering::Less - } else if u > (i128::MAX as u128) { - Ordering::Greater - } else { - (s as u128).cmp(&u) - } - } -} - -impl PartialEq for FullInt { - #[must_use] - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal - } -} - -impl PartialOrd for FullInt { - #[must_use] - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(match (self, other) { - (&Self::S(s), &Self::S(o)) => s.cmp(&o), - (&Self::U(s), &Self::U(o)) => s.cmp(&o), - (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o), - (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(), - }) - } -} - -impl Ord for FullInt { - #[must_use] - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other) - .expect("`partial_cmp` for FullInt can never return `None`") - } -} - fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> { if let ExprKind::Cast(cast_exp, _) = expr.kind { let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp); @@ -118,19 +69,6 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> } } -fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> { - let val = constant(cx, cx.typeck_results(), expr)?.0; - if let Constant::Int(const_int) = val { - match *cx.typeck_results().expr_ty(expr).kind() { - ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), - ty::Uint(_) => Some(FullInt::U(const_int)), - _ => None, - } - } else { - None - } -} - fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) { if let ExprKind::Cast(cast_val, _) = expr.kind { span_lint( @@ -156,7 +94,7 @@ fn upcast_comparison_bounds_err<'tcx>( invert: bool, ) { if let Some((lb, ub)) = lhs_bounds { - if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { + if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) { if rel == Rel::Eq || rel == Rel::Ne { if norm_rhs_val < lb || norm_rhs_val > ub { err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs index c949ee23ecc..15edb79d36c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -76,7 +76,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(get_last_with_len::GET_LAST_WITH_LEN), LintId::of(identity_op::IDENTITY_OP), LintId::of(if_let_mutex::IF_LET_MUTEX), - LintId::of(if_then_panic::IF_THEN_PANIC), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), LintId::of(inherent_to_string::INHERENT_TO_STRING), @@ -218,6 +217,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), @@ -282,6 +282,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), + LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_ARG), LintId::of(unit_types::UNIT_CMP), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs index ff56a6081fb..4217fd3a3ea 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs @@ -64,6 +64,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), + LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_CMP), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs index e8dd3708c8e..2cb86418e3c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs @@ -159,7 +159,6 @@ store.register_lints(&[ identity_op::IDENTITY_OP, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, - if_then_panic::IF_THEN_PANIC, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, implicit_hasher::IMPLICIT_HASHER, implicit_return::IMPLICIT_RETURN, @@ -216,6 +215,7 @@ store.register_lints(&[ loops::WHILE_LET_ON_ITERATOR, macro_use::MACRO_USE_IMPORTS, main_recursion::MAIN_RECURSION, + manual_assert::MANUAL_ASSERT, manual_async_fn::MANUAL_ASYNC_FN, manual_map::MANUAL_MAP, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, @@ -327,6 +327,7 @@ store.register_lints(&[ misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::MIXED_CASE_HEX_LITERALS, misc_early::REDUNDANT_PATTERN, + misc_early::SEPARATED_LITERAL_SUFFIX, misc_early::UNNEEDED_FIELD_PATTERN, misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::UNSEPARATED_LITERAL_SUFFIX, @@ -431,6 +432,7 @@ store.register_lints(&[ strings::STRING_ADD_ASSIGN, strings::STRING_FROM_UTF8_AS_BYTES, strings::STRING_LIT_AS_BYTES, + strings::STRING_SLICE, strings::STRING_TO_STRING, strings::STR_TO_STRING, strlen_on_c_strings::STRLEN_ON_C_STRINGS, @@ -476,6 +478,7 @@ store.register_lints(&[ unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, uninit_vec::UNINIT_VEC, + unit_hash::UNIT_HASH, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs index 1e54482a8da..44c75a11eec 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs @@ -17,7 +17,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutex_atomic::MUTEX_INTEGER), - LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs index 268349d2848..404ca20b5ab 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs @@ -48,6 +48,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(loops::EXPLICIT_ITER_LOOP), LintId::of(macro_use::MACRO_USE_IMPORTS), + LintId::of(manual_assert::MANUAL_ASSERT), LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(matches::MATCH_BOOL), @@ -65,7 +66,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::MAP_UNWRAP_OR), LintId::of(misc::FLOAT_CMP), LintId::of(misc::USED_UNDERSCORE_BINDING), - LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), LintId::of(mut_mut::MUT_MUT), LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), @@ -88,7 +88,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(types::LINKEDLIST), LintId::of(types::OPTION_OPTION), - LintId::of(unicode::NON_ASCII_LITERAL), LintId::of(unicode::UNICODE_NOT_NFC), LintId::of(unit_types::LET_UNIT_VALUE), LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs index 3d68a6e9009..eab389a9bd8 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs @@ -35,7 +35,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::GET_UNWRAP), LintId::of(methods::UNWRAP_USED), LintId::of(misc::FLOAT_CMP_CONST), + LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), @@ -53,11 +55,13 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(shadow::SHADOW_SAME), LintId::of(shadow::SHADOW_UNRELATED), LintId::of(strings::STRING_ADD), + LintId::of(strings::STRING_SLICE), LintId::of(strings::STRING_TO_STRING), LintId::of(strings::STR_TO_STRING), LintId::of(types::RC_BUFFER), LintId::of(types::RC_MUTEX), LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS), + LintId::of(unicode::NON_ASCII_LITERAL), LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(verbose_file_reads::VERBOSE_FILE_READS), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs index a39c111c574..744880bda3e 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs @@ -27,7 +27,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(if_then_panic::IF_THEN_PANIC), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(len_zero::COMPARISON_TO_EMPTY), LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs index 8859787fbc8..a3f964d1580 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs @@ -15,6 +15,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::MUT_RANGE_BOUND), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), ]) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index ed7e8277023..7174d0a082e 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -228,7 +228,6 @@ mod get_last_with_len; mod identity_op; mod if_let_mutex; mod if_not_else; -mod if_then_panic; mod if_then_some_else_none; mod implicit_hasher; mod implicit_return; @@ -255,6 +254,7 @@ mod literal_representation; mod loops; mod macro_use; mod main_recursion; +mod manual_assert; mod manual_async_fn; mod manual_map; mod manual_non_exhaustive; @@ -364,6 +364,7 @@ mod undocumented_unsafe_blocks; mod undropped_manually_drops; mod unicode; mod uninit_vec; +mod unit_hash; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -522,6 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch)); store.register_late_pass(|| Box::new(unicode::Unicode)); store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); + store.register_late_pass(|| Box::new(unit_hash::UnitHash)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); @@ -666,7 +668,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(double_parens::DoubleParens)); store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new())); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); - store.register_early_pass(|| Box::new(if_not_else::IfNotElse)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); store.register_early_pass(|| Box::new(formatting::Formatting)); @@ -720,6 +721,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); + store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems)); @@ -770,14 +772,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); store.register_late_pass(move || Box::new(feature_name::FeatureName)); store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); - store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic)); + store.register_late_pass(move || Box::new(manual_assert::ManualAssert)); let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(move || Box::new(format_args::FormatArgs)); store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); - + // add lints here, do not remove this comment, it's used in `new_lint` } #[rustfmt::skip] @@ -828,6 +830,7 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) { /// /// Used in `./src/driver.rs`. pub fn register_renamed(ls: &mut rustc_lint::LintStore) { + // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions"); ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default"); ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"); diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index e5e6f8d25cc..cb0b96e0652 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -378,11 +378,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, _) => { + TyKind::OpaqueDef(item, bounds) => { let map = self.cx.tcx.hir(); let item = map.item(item); walk_item(self, item); walk_ty(self, ty); + self.lts.extend(bounds.iter().filter_map(|bound| match bound { + GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)), + _ => None, + })); }, TyKind::BareFn(&BareFnTy { decl, .. }) => { let mut sub_visitor = RefVisitor::new(self.cx); diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 2f7360210ba..f9f515cc40a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -338,7 +338,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(), meth_name, ) - } + }, _ => format!( "{}.into_iter()", sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() diff --git a/src/tools/clippy/clippy_lints/src/if_then_panic.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index e8cea5529e8..e55aa3f1850 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_panic.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -26,14 +26,14 @@ declare_clippy_lint! { /// let sad_people: Vec<&str> = vec![]; /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` - pub IF_THEN_PANIC, - style, + pub MANUAL_ASSERT, + pedantic, "`panic!` and only a `panic!` in `if`-then statement" } -declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]); +declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]); -impl LateLintPass<'_> for IfThenPanic { +impl LateLintPass<'_> for ManualAssert { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let Expr { @@ -54,23 +54,24 @@ impl LateLintPass<'_> for IfThenPanic { if !cx.tcx.sess.source_map().is_multiline(cond.span); then { - let span = if let Some(panic_expn) = PanicExpn::parse(semi) { + let call = if_chain! { + if let ExprKind::Block(block, _) = semi.kind; + if let Some(init) = block.expr; + then { + init + } else { + semi + } + }; + let span = if let Some(panic_expn) = PanicExpn::parse(call) { match *panic_expn.format_args.value_args { [] => panic_expn.format_args.format_string_span, [.., last] => panic_expn.format_args.format_string_span.to(last.span), } + } else if let ExprKind::Call(_, [format_args]) = call.kind { + format_args.span } else { - if_chain! { - if let ExprKind::Block(block, _) = semi.kind; - if let Some(init) = block.expr; - if let ExprKind::Call(_, [format_args]) = init.kind; - - then { - format_args.span - } else { - return - } - } + return }; let mut applicability = Applicability::MachineApplicable; let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); @@ -86,7 +87,7 @@ impl LateLintPass<'_> for IfThenPanic { span_lint_and_sugg( cx, - IF_THEN_PANIC, + MANUAL_ASSERT, expr.span, "only a `panic!` in `if`-then statement", "try", diff --git a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs index a83f38e3d51..f501593c518 100644 --- a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs @@ -127,10 +127,10 @@ fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> { fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> { let case_check = match case_method { - CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) }, - CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) }, - CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) }, - CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) }, + CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) }, + CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) }, + CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) }, + CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) }, }; for arm in arms { @@ -153,7 +153,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) { let (method_str, suggestion) = match case_method { - CaseMethod::LowerCase => ("to_lower_case", bad_case_str.to_lowercase()), + CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()), CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()), CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()), CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()), diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index b643fba5d32..eb311983b29 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, miri_to_const, Constant}; +use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; use clippy_utils::diagnostics::{ multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; @@ -930,9 +930,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() { let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex)); - let type_ranges = type_ranges(&ranges); - if !type_ranges.is_empty() { - if let Some((start, end)) = overlapping(&type_ranges) { + if !ranges.is_empty() { + if let Some((start, end)) = overlapping(&ranges) { span_lint_and_note( cx, MATCH_OVERLAPPING_ARM, @@ -968,8 +967,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm } if_chain! { if matching_wild; - if let ExprKind::Block(block, _) = arm.body.kind; - if is_panic_block(block); + if is_panic_call(arm.body); then { // `Err(_)` or `Err(_e)` arm with `panic!` found span_lint_and_note(cx, @@ -1172,14 +1170,19 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) } // If the block contains only a `panic!` macro (as expression or statement) -fn is_panic_block(block: &Block<'_>) -> bool { - match (&block.expr, block.stmts.len(), block.stmts.first()) { - (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(), - (&None, 1, Some(stmt)) => { - is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none() - }, - _ => false, - } +fn is_panic_call(expr: &Expr<'_>) -> bool { + // Unwrap any wrapping blocks + let span = if let ExprKind::Block(block, _) = expr.kind { + match (&block.expr, block.stmts.len(), block.stmts.first()) { + (&Some(exp), 0, _) => exp.span, + (&None, 1, Some(stmt)) => stmt.span, + _ => return false, + } + } else { + expr.span + }; + + is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none() } fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) @@ -1601,7 +1604,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<' } /// Gets all arms that are unbounded `PatRange`s. -fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> { +fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> { arms.iter() .filter_map(|arm| { if let Arm { pat, guard: None, .. } = *arm { @@ -1614,21 +1617,25 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, }; - let rhs = match range_end { - RangeEnd::Included => Bound::Included(rhs), - RangeEnd::Excluded => Bound::Excluded(rhs), + + let lhs_val = lhs.int_value(cx, ty)?; + let rhs_val = rhs.int_value(cx, ty)?; + + let rhs_bound = match range_end { + RangeEnd::Included => Bound::Included(rhs_val), + RangeEnd::Excluded => Bound::Excluded(rhs_val), }; return Some(SpannedRange { span: pat.span, - node: (lhs, rhs), + node: (lhs_val, rhs_bound), }); } if let PatKind::Lit(value) = pat.kind { - let value = constant(cx, cx.typeck_results(), value)?.0; + let value = constant_full_int(cx, cx.typeck_results(), value)?; return Some(SpannedRange { span: pat.span, - node: (value.clone(), Bound::Included(value)), + node: (value, Bound::Included(value)), }); } } @@ -1643,32 +1650,6 @@ pub struct SpannedRange<T> { pub node: (T, Bound<T>), } -type TypedRanges = Vec<SpannedRange<u128>>; - -/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway -/// and other types than -/// `Uint` and `Int` probably don't make sense. -fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges { - ranges - .iter() - .filter_map(|range| match range.node { - (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange { - span: range.span, - node: (start, Bound::Included(end)), - }), - (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange { - span: range.span, - node: (start, Bound::Excluded(end)), - }), - (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange { - span: range.span, - node: (start, Bound::Unbounded), - }), - _ => None, - }) - .collect() -} - // Checks if arm has the form `None => None` fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 1a32af5dc7a..b4dacb2580c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -85,7 +85,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => { return; - } + }, ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) @@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, ) => { return; - } + }, _ => false, }; diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index b5bbbb09092..fe9ffde0d33 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -186,7 +186,7 @@ pub(super) fn check<'tcx>( check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); } } - } + }, _ => (), } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs b/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs index 6f65778e119..06ba968fa4e 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs @@ -1,4 +1,3 @@ -use super::MiscEarlyLints; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind, UnOp}; use rustc_lint::EarlyContext; @@ -6,18 +5,14 @@ use rustc_lint::EarlyContext; use super::DOUBLE_NEG; pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) { - match expr.kind { - ExprKind::Unary(UnOp::Neg, ref inner) => { - if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { - span_lint( - cx, - DOUBLE_NEG, - expr.span, - "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", - ); - } - }, - ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit), - _ => (), + if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind { + if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { + span_lint( + cx, + DOUBLE_NEG, + expr.span, + "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs new file mode 100644 index 00000000000..1165c19a0cf --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::Lit; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; + +use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX}; + +pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { + let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { + val + } else { + return; // It's useless so shouldn't lint. + }; + // Do not lint when literal is unsuffixed. + if !suffix.is_empty() { + if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' { + span_lint_and_sugg( + cx, + SEPARATED_LITERAL_SUFFIX, + lit.span, + &format!("{} type suffix should not be separated by an underscore", sugg_type), + "remove the underscore", + format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + UNSEPARATED_LITERAL_SUFFIX, + lit.span, + &format!("{} type suffix should be separated by an underscore", sugg_type), + "add an underscore", + format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index b32feab4ee3..7c3f5f22ade 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -1,15 +1,15 @@ mod builtin_type_shadow; mod double_neg; +mod literal_suffix; mod mixed_case_hex_literals; mod redundant_pattern; mod unneeded_field_pattern; mod unneeded_wildcard_pattern; -mod unseparated_literal_suffix; mod zero_prefixed_literal; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; +use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -115,9 +115,11 @@ declare_clippy_lint! { /// ### What it does /// Warns if literal suffixes are not separated by an /// underscore. + /// To enforce unseparated literal suffix style, + /// see the `separated_literal_suffix` lint. /// /// ### Why is this bad? - /// It is much less readable. + /// Suffix style should be consistent. /// /// ### Example /// ```rust @@ -128,12 +130,34 @@ declare_clippy_lint! { /// let y = 123832_i32; /// ``` pub UNSEPARATED_LITERAL_SUFFIX, - pedantic, + restriction, "literals whose suffix is not separated by an underscore" } declare_clippy_lint! { /// ### What it does + /// Warns if literal suffixes are separated by an underscore. + /// To enforce separated literal suffix style, + /// see the `unseparated_literal_suffix` lint. + /// + /// ### Why is this bad? + /// Suffix style should be consistent. + /// + /// ### Example + /// ```rust + /// // Bad + /// let y = 123832_i32; + /// + /// // Good + /// let y = 123832i32; + /// ``` + pub SEPARATED_LITERAL_SUFFIX, + restriction, + "literals whose suffix is separated by an underscore" +} + +declare_clippy_lint! { + /// ### What it does /// Warns if an integral constant literal starts with `0`. /// /// ### Why is this bad? @@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [ DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, + SEPARATED_LITERAL_SUFFIX, ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW, REDUNDANT_PATTERN, @@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints { if in_external_macro(cx.sess, expr.span) { return; } + + if let ExprKind::Lit(ref lit) = expr.kind { + MiscEarlyLints::check_lit(cx, lit); + } double_neg::check(cx, expr); } } @@ -332,7 +361,7 @@ impl MiscEarlyLints { LitIntType::Unsigned(ty) => ty.name_str(), LitIntType::Unsuffixed => "", }; - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); + literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); if lit_snip.starts_with("0x") { mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip); } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { @@ -342,7 +371,7 @@ impl MiscEarlyLints { } } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind { let suffix = float_ty.name_str(); - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); + literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); } } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unseparated_literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/unseparated_literal_suffix.rs deleted file mode 100644 index 2018aa6184a..00000000000 --- a/src/tools/clippy/clippy_lints/src/misc_early/unseparated_literal_suffix.rs +++ /dev/null @@ -1,26 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::ast::Lit; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; - -use super::UNSEPARATED_LITERAL_SUFFIX; - -pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { - let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { - val - } else { - return; // It's useless so shouldn't lint. - }; - // Do not lint when literal is unsuffixed. - if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' { - span_lint_and_sugg( - cx, - UNSEPARATED_LITERAL_SUFFIX, - lit.span, - &format!("{} type suffix should be separated by an underscore", sugg_type), - "add an underscore", - format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), - Applicability::MachineApplicable, - ); - } -} diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs index f351d0098b7..d41b5474564 100644 --- a/src/tools/clippy/clippy_lints/src/module_style.rs +++ b/src/tools/clippy/clippy_lints/src/module_style.rs @@ -106,7 +106,7 @@ impl EarlyLintPass for ModStyle { } process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders); check_self_named_mod_exists(cx, path, file); - } + }, _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs index 1b2495d764d..f1be90c44f9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs @@ -107,14 +107,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { - if let [Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Borrow(_), - .. - }] = *adj3 + if let [ + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Borrow(_), + .. + }, + ] = *adj3 { let help_msg_ty = if matches!(mutability, Mutability::Not) { format!("&{}", ty) diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index 374b7bd5964..7ebf84d400f 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -44,7 +44,7 @@ declare_clippy_lint! { /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) /// or specify correct bounds on generic type parameters (`T: Send`). pub NON_SEND_FIELDS_IN_SEND_TY, - nursery, + suspicious, "there is field that does not implement `Send` in a `Send` struct" } diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index a62eb069989..cbe1c5d44d5 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// expression). /// /// ### Why is this bad? - /// Using the dedicated functions of the Option type is clearer and + /// Using the dedicated functions of the `Option` type is clearer and /// more concise than an `if let` expression. /// /// ### Known problems diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 92a4801a846..8a36e20fc97 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -3,16 +3,16 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; +use clippy_utils::ty::walk_ptrs_hir_ty; use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{ - BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item, - ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, + BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind, + Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -153,7 +153,7 @@ declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USA impl<'tcx> LateLintPass<'tcx> for Ptr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, _, body_id) = item.kind { - check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); + check_fn(cx, sig.decl, Some(body_id)); } } @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { return; // ignore trait impls } } - check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); + check_fn(cx, sig.decl, Some(body_id)); } } @@ -176,7 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } else { None }; - check_fn(cx, sig.decl, item.hir_id(), body_id); + check_fn(cx, sig.decl, body_id); } } @@ -244,13 +244,10 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } #[allow(clippy::too_many_lines)] -fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) { - let fn_def_id = cx.tcx.hir().local_def_id(fn_id); - let sig = cx.tcx.fn_sig(fn_def_id); - let fn_ty = sig.skip_binder(); +fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) { let body = opt_body_id.map(|id| cx.tcx.hir().body(id)); - for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() { + for (idx, arg) in decl.inputs.iter().enumerate() { // Honor the allow attribute on parameters. See issue 5644. if let Some(body) = &body { if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) { @@ -258,8 +255,20 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } } - if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym::Vec) { + let (item_name, path) = if_chain! { + if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind; + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind; + if let Res::Def(_, did) = path.res; + if let Some(item_name) = cx.tcx.get_diagnostic_name(did); + then { + (item_name, path) + } else { + continue + } + }; + + match item_name { + sym::Vec => { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) { span_lint_and_then( cx, @@ -289,7 +298,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if is_type_diagnostic_item(cx, ty, sym::String) { + }, + sym::String => { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { span_lint_and_then( cx, @@ -311,7 +321,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) { + }, + sym::PathBuf => { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) { span_lint_and_then( cx, @@ -338,11 +349,10 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if match_type(cx, ty, &paths::COW) { + }, + sym::Cow => { if_chain! { - if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind; - if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind; - if let [ref bx] = *pp.segments; + if let [ref bx] = *path.segments; if let Some(params) = bx.args; if !params.parenthesized; if let Some(inner) = params.args.iter().find_map(|arg| match arg { @@ -363,7 +373,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: ); } } - } + }, + _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 4d616e26bfc..f63ef163bcb 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -172,23 +172,17 @@ impl QuestionMark { } } - fn expression_returns_unmodified_err( - cx: &LateContext<'_>, - expression: &Expr<'_>, - origin_hir_id: &Expr<'_>, - ) -> bool { - match expression.kind { + fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool { + match expr.kind { ExprKind::Block(block, _) => { if let Some(return_expression) = Self::return_expression(block) { - return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id); + return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr); } false }, - ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => { - Self::expression_returns_unmodified_err(cx, expr, origin_hir_id) - }, - ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id), + ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr), + ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 35b6bde5696..6435107b8b4 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -107,51 +107,87 @@ declare_clippy_lint! { "calling `as_bytes` on a string literal instead of using a byte string literal" } -declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]); +declare_clippy_lint! { + /// ### What it does + /// Checks for slice operations on strings + /// + /// ### Why is this bad? + /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character + /// counts and string indices. This may lead to panics, and should warrant some test cases + /// containing wide UTF-8 characters. This lint is most useful in code that should avoid + /// panics at all costs. + /// + /// ### Known problems + /// Probably lots of false positives. If an index comes from a known valid position (e.g. + /// obtained via `char_indices` over the same string), it is totally OK. + /// + /// # Example + /// ```rust,should_panic + /// &"Ölkanne"[1..]; + /// ``` + pub STRING_SLICE, + restriction, + "slicing a string" +} + +declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]); impl<'tcx> LateLintPass<'tcx> for StringAdd { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), e.span) { return; } - - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Add, .. - }, - left, - _, - ) = e.kind - { - if is_string(cx, left) { - if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { - let parent = get_parent_expr(cx, e); - if let Some(p) = parent { - if let ExprKind::Assign(target, _, _) = p.kind { - // avoid duplicate matches - if SpanlessEq::new(cx).eq_expr(target, left) { - return; + match e.kind { + ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + left, + _, + ) => { + if is_string(cx, left) { + if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { + let parent = get_parent_expr(cx, e); + if let Some(p) = parent { + if let ExprKind::Assign(target, _, _) = p.kind { + // avoid duplicate matches + if SpanlessEq::new(cx).eq_expr(target, left) { + return; + } } } } + span_lint( + cx, + STRING_ADD, + e.span, + "you added something to a string. Consider using `String::push_str()` instead", + ); } - span_lint( - cx, - STRING_ADD, - e.span, - "you added something to a string. Consider using `String::push_str()` instead", - ); - } - } else if let ExprKind::Assign(target, src, _) = e.kind { - if is_string(cx, target) && is_add(cx, src, target) { - span_lint( - cx, - STRING_ADD_ASSIGN, - e.span, - "you assigned the result of adding something to this string. Consider using \ - `String::push_str()` instead", - ); - } + }, + ExprKind::Assign(target, src, _) => { + if is_string(cx, target) && is_add(cx, src, target) { + span_lint( + cx, + STRING_ADD_ASSIGN, + e.span, + "you assigned the result of adding something to this string. Consider using \ + `String::push_str()` instead", + ); + } + }, + ExprKind::Index(target, _idx) => { + let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); + if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) { + span_lint( + cx, + STRING_SLICE, + e.span, + "indexing into a string may panic if the index is within a UTF-8 character", + ); + } + }, + _ => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index e08e4d03c7e..11aef50991b 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -145,8 +145,9 @@ impl UndocumentedUnsafeBlocks { let file_name = source_map.span_to_filename(between_span); let source_file = source_map.get_source_file(&file_name)?; - let lex_start = (between_span.lo().0 + 1) as usize; - let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string(); + let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize; + let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize; + let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string(); let mut pos = 0; let mut comment = false; diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index f337dec8f2b..f49ce696a04 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// let x = String::from("\u{20ac}"); /// ``` pub NON_ASCII_LITERAL, - pedantic, + restriction, "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape" } diff --git a/src/tools/clippy/clippy_lints/src/unit_hash.rs b/src/tools/clippy/clippy_lints/src/unit_hash.rs new file mode 100644 index 00000000000..a3a3f2d41c7 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unit_hash.rs @@ -0,0 +1,77 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detects `().hash(_)`. + /// + /// ### Why is this bad? + /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + /// + /// ### Example + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => ().hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => 0_u8.hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + pub UNIT_HASH, + correctness, + "hashing a unit value, which does nothing" +} +declare_lint_pass!(UnitHash => [UNIT_HASH]); + +impl LateLintPass<'tcx> for UnitHash { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; + if name_ident.ident.name == sym::hash; + if let [recv, state_param] = args; + if cx.typeck_results().expr_ty(recv).is_unit(); + then { + span_lint_and_then( + cx, + UNIT_HASH, + expr.span, + "this call to `hash` on the unit type will do nothing", + |diag| { + diag.span_suggestion( + expr.span, + "remove the call to `hash` or consider using", + format!( + "0_u8.hash({})", + snippet(cx, state_param.span, ".."), + ), + Applicability::MaybeIncorrect, + ); + diag.note("the implementation of `Hash` for `()` is a no-op"); + } + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index a4680ae137b..6447e3fa2ca 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -13,7 +13,7 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for functions of type Result that contain `expect()` or `unwrap()` + /// Checks for functions of type `Result` that contain `expect()` or `unwrap()` /// /// ### Why is this bad? /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index d05c52122d5..122a5ce3fc8 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -288,10 +288,10 @@ define_Conf! { /// /// The list of imports to always rename, a fully qualified path followed by the rename. (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()), - /// Lint: RESTRICTED_SCRIPTS. + /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec<String> = vec!["Latin".to_string()]), + (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()), /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 0d27874b7af..99cf4c1ed40 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -512,12 +512,21 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str); let mut docs = String::from(&*lines.next()?.as_str()); let mut in_code_block = false; + let mut is_code_block_rust = false; for line in lines { - docs.push('\n'); let line = line.as_str(); let line = &*line; + + // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :) + if is_code_block_rust && line.trim_start().starts_with("# ") { + continue; + } + + // The line should be represented in the lint list, even if it's just an empty line + docs.push('\n'); if let Some(info) = line.trim_start().strip_prefix("```") { in_code_block = !in_code_block; + is_code_block_rust = false; if in_code_block { let lang = info .trim() @@ -528,6 +537,8 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { .unwrap_or("rust"); docs.push_str("```"); docs.push_str(lang); + + is_code_block_rust = lang == "rust"; continue; } } diff --git a/src/tools/clippy/clippy_utils/src/camel_case.rs b/src/tools/clippy/clippy_utils/src/camel_case.rs deleted file mode 100644 index a6636e39137..00000000000 --- a/src/tools/clippy/clippy_utils/src/camel_case.rs +++ /dev/null @@ -1,117 +0,0 @@ -/// Returns the index of the character after the first camel-case component of `s`. -#[must_use] -pub fn until(s: &str) -> usize { - let mut iter = s.char_indices(); - if let Some((_, first)) = iter.next() { - if !first.is_uppercase() { - return 0; - } - } else { - return 0; - } - let mut up = true; - let mut last_i = 0; - for (i, c) in iter { - if up { - if c.is_lowercase() { - up = false; - } else { - return last_i; - } - } else if c.is_uppercase() { - up = true; - last_i = i; - } else if !c.is_lowercase() { - return i; - } - } - if up { last_i } else { s.len() } -} - -/// Returns index of the last camel-case component of `s`. -#[must_use] -pub fn from(s: &str) -> usize { - let mut iter = s.char_indices().rev(); - if let Some((_, first)) = iter.next() { - if !first.is_lowercase() { - return s.len(); - } - } else { - return s.len(); - } - let mut down = true; - let mut last_i = s.len(); - for (i, c) in iter { - if down { - if c.is_uppercase() { - down = false; - last_i = i; - } else if !c.is_lowercase() { - return last_i; - } - } else if c.is_lowercase() { - down = true; - } else if c.is_uppercase() { - last_i = i; - } else { - return last_i; - } - } - last_i -} - -#[cfg(test)] -mod test { - use super::{from, until}; - - #[test] - fn from_full() { - assert_eq!(from("AbcDef"), 0); - assert_eq!(from("Abc"), 0); - assert_eq!(from("ABcd"), 0); - assert_eq!(from("ABcdEf"), 0); - assert_eq!(from("AabABcd"), 0); - } - - #[test] - fn from_partial() { - assert_eq!(from("abcDef"), 3); - assert_eq!(from("aDbc"), 1); - assert_eq!(from("aabABcd"), 3); - } - - #[test] - fn from_not() { - assert_eq!(from("AbcDef_"), 7); - assert_eq!(from("AbcDD"), 5); - } - - #[test] - fn from_caps() { - assert_eq!(from("ABCD"), 4); - } - - #[test] - fn until_full() { - assert_eq!(until("AbcDef"), 6); - assert_eq!(until("Abc"), 3); - } - - #[test] - fn until_not() { - assert_eq!(until("abcDef"), 0); - assert_eq!(until("aDbc"), 0); - } - - #[test] - fn until_partial() { - assert_eq!(until("AbcDef_"), 6); - assert_eq!(until("CallTypeC"), 8); - assert_eq!(until("AbcDD"), 3); - } - - #[test] - fn until_caps() { - assert_eq!(until("ABCD"), 0); - } -} diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 8bf31807d55..04347672e0f 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -155,6 +155,19 @@ impl Constant { _ => None, } } + + /// Returns the integer value or `None` if `self` or `val_type` is not integer type. + pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> { + if let Constant::Int(const_int) = *self { + match *val_type.kind() { + ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), + ty::Uint(_) => Some(FullInt::U(const_int)), + _ => None, + } + } else { + None + } + } } /// Parses a `LitKind` to a `Constant`. @@ -202,6 +215,52 @@ pub fn constant_simple<'tcx>( constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) } +pub fn constant_full_int( + lcx: &LateContext<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + e: &Expr<'_>, +) -> Option<FullInt> { + constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e)) +} + +#[derive(Copy, Clone, Debug, Eq)] +pub enum FullInt { + S(i128), + U(u128), +} + +impl PartialEq for FullInt { + #[must_use] + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl PartialOrd for FullInt { + #[must_use] + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for FullInt { + #[must_use] + fn cmp(&self, other: &Self) -> Ordering { + use FullInt::{S, U}; + + fn cmp_s_u(s: i128, u: u128) -> Ordering { + u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u)) + } + + match (*self, *other) { + (S(s), S(o)) => s.cmp(&o), + (U(s), U(o)) => s.cmp(&o), + (S(s), U(o)) => cmp_s_u(s, o), + (U(s), S(o)) => cmp_s_u(o, s).reverse(), + } + } +} + /// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. pub fn constant_context<'a, 'tcx>( lcx: &'a LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 9302e5c21fa..d47b002ad7a 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -72,7 +72,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult /// 6 | let other_f64_nan = 0.0f64 / 0.0; /// | ^^^^^^^^^^^^ /// | -/// = help: Consider using `f64::NAN` if you would like a constant representing NaN +/// = help: consider using `f64::NAN` if you would like a constant representing NaN /// ``` pub fn span_lint_and_help<'a, T: LintContext>( cx: &'a T, diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 60c4cb361aa..b3a9a1de2ec 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -1,14 +1,14 @@ -//! This module contains functions that retrieves specifiec elements. +//! This module contains functions that retrieve specific elements. #![deny(clippy::missing_docs_in_private_items)] use crate::ty::is_type_diagnostic_item; -use crate::{is_expn_of, last_path_segment, match_def_path, paths}; +use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths}; use if_chain::if_chain; use rustc_ast::ast::{self, LitKind}; use rustc_hir as hir; use rustc_hir::{ - Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp, + Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp, }; use rustc_lint::LateContext; use rustc_span::{sym, symbol, ExpnKind, Span, Symbol}; @@ -513,6 +513,8 @@ pub struct FormatArgsExpn<'tcx> { pub format_string_parts: &'tcx [Expr<'tcx>], /// Symbols corresponding to [`Self::format_string_parts`] pub format_string_symbols: Vec<Symbol>, + /// Match arm patterns, the `arg0`, etc. from the next field `args` + pub arg_names: &'tcx [Pat<'tcx>], /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)` pub args: &'tcx [Expr<'tcx>], /// The final argument passed to `Arguments::new_v1_formatted`, if applicable @@ -557,6 +559,7 @@ impl FormatArgsExpn<'tcx> { _ => None, }) .collect(); + if let PatKind::Tuple(arg_names, None) = arm.pat.kind; if let ExprKind::Array(args) = arm.body.kind; then { Some(FormatArgsExpn { @@ -564,6 +567,7 @@ impl FormatArgsExpn<'tcx> { value_args, format_string_parts, format_string_symbols, + arg_names, args, fmt_expr, }) @@ -587,9 +591,15 @@ impl FormatArgsExpn<'tcx> { if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); if let ExprKind::Lit(lit) = &position_field.expr.kind; if let LitKind::Int(position, _) = lit.node; + if let Ok(i) = usize::try_from(position); + let arg = &self.args[i]; + if let ExprKind::Call(_, [arg_name, _]) = arg.kind; + if let Some(j) = self + .arg_names + .iter() + .position(|pat| path_to_local_id(arg_name, pat.hir_id)); then { - let i = usize::try_from(position).unwrap(); - Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) }) + Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) }) } else { None } @@ -718,9 +728,7 @@ impl PanicExpn<'tcx> { /// Parses an expanded `panic!` invocation pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> { if_chain! { - if let ExprKind::Block(block, _) = expr.kind; - if let Some(init) = block.expr; - if let ExprKind::Call(_, [format_args]) = init.kind; + if let ExprKind::Call(_, [format_args]) = expr.kind; let expn_data = expr.span.ctxt().outer_expn_data(); if let Some(format_args) = FormatArgsExpn::parse(format_args); then { @@ -770,13 +778,13 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - } return Some(VecInitKind::WithExprCapacity(arg.hir_id)); } - } + }, ExprKind::Path(QPath::Resolved(_, path)) if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => { return Some(VecInitKind::Default); - } + }, _ => (), } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 9bc380ca6ca..086fbc9d3dd 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -37,7 +37,6 @@ pub mod sym_helper; #[allow(clippy::module_name_repetitions)] pub mod ast_utils; pub mod attrs; -pub mod camel_case; pub mod comparisons; pub mod consts; pub mod diagnostics; @@ -50,6 +49,7 @@ pub mod paths; pub mod ptr; pub mod qualify_min_const_fn; pub mod source; +pub mod str_utils; pub mod sugg; pub mod ty; pub mod usage; @@ -712,7 +712,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// Checks if the top level expression can be moved into a closure as is. /// Currently checks for: /// * Break/Continue outside the given loop HIR ids. -/// * Yield/Return statments. +/// * Yield/Return statements. /// * Inline assembly. /// * Usages of a field of a local where the type of the local can be partially moved. /// @@ -844,10 +844,13 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind let mut capture_expr_ty = e; for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) { - if let [Adjustment { - kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), - target, - }, ref adjust @ ..] = *cx + if let [ + Adjustment { + kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), + target, + }, + ref adjust @ .., + ] = *cx .typeck_results() .adjustments() .get(child_id) @@ -1232,9 +1235,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti for (_, node) in tcx.hir().parent_iter(expr.hir_id) { match node { Node::Expr( - e - @ - Expr { + e @ Expr { kind: ExprKind::Loop(..) | ExprKind::Closure(..), .. }, @@ -1692,10 +1693,12 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool { pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Call( _, - &[Expr { - kind: ExprKind::Closure(_, _, body, _, _), - .. - }], + &[ + Expr { + kind: ExprKind::Closure(_, _, body, _, _), + .. + }, + ], ) = body.value.kind { if let ExprKind::Block( @@ -2123,7 +2126,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { vis.found } -/// Checks whether item either has `test` attribute appelied, or +/// Checks whether item either has `test` attribute applied, or /// is a module with `test` in its name. /// /// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`. diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs new file mode 100644 index 00000000000..cba96e05a24 --- /dev/null +++ b/src/tools/clippy/clippy_utils/src/str_utils.rs @@ -0,0 +1,230 @@ +/// Dealing with sting indices can be hard, this struct ensures that both the +/// character and byte index are provided for correct indexing. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct StrIndex { + pub char_index: usize, + pub byte_index: usize, +} + +impl StrIndex { + pub fn new(char_index: usize, byte_index: usize) -> Self { + Self { char_index, byte_index } + } +} + +/// Returns the index of the character after the first camel-case component of `s`. +/// +/// ``` +/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6)); +/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); +/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3)); +/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7)); +/// ``` +#[must_use] +pub fn camel_case_until(s: &str) -> StrIndex { + let mut iter = s.char_indices().enumerate(); + if let Some((_char_index, (_, first))) = iter.next() { + if !first.is_uppercase() { + return StrIndex::new(0, 0); + } + } else { + return StrIndex::new(0, 0); + } + let mut up = true; + let mut last_index = StrIndex::new(0, 0); + for (char_index, (byte_index, c)) in iter { + if up { + if c.is_lowercase() { + up = false; + } else { + return last_index; + } + } else if c.is_uppercase() { + up = true; + last_index.byte_index = byte_index; + last_index.char_index = char_index; + } else if !c.is_lowercase() { + return StrIndex::new(char_index, byte_index); + } + } + + if up { + last_index + } else { + StrIndex::new(s.chars().count(), s.len()) + } +} + +/// Returns index of the last camel-case component of `s`. +/// +/// ``` +/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); +/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); +/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4)); +/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4)); +/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6)); +/// ``` +#[must_use] +pub fn camel_case_start(s: &str) -> StrIndex { + let char_count = s.chars().count(); + let range = 0..char_count; + let mut iter = range.rev().zip(s.char_indices().rev()); + if let Some((char_index, (_, first))) = iter.next() { + if !first.is_lowercase() { + return StrIndex::new(char_index, s.len()); + } + } else { + return StrIndex::new(char_count, s.len()); + } + let mut down = true; + let mut last_index = StrIndex::new(char_count, s.len()); + for (char_index, (byte_index, c)) in iter { + if down { + if c.is_uppercase() { + down = false; + last_index.byte_index = byte_index; + last_index.char_index = char_index; + } else if !c.is_lowercase() { + return last_index; + } + } else if c.is_lowercase() { + down = true; + } else if c.is_uppercase() { + last_index.byte_index = byte_index; + last_index.char_index = char_index; + } else { + return last_index; + } + } + last_index +} + +/// Dealing with sting comparison can be complicated, this struct ensures that both the +/// character and byte count are provided for correct indexing. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct StrCount { + pub char_count: usize, + pub byte_count: usize, +} + +impl StrCount { + pub fn new(char_count: usize, byte_count: usize) -> Self { + Self { char_count, byte_count } + } +} + +/// Returns the number of chars that match from the start +/// +/// ``` +/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6)); +/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0)); +/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11)); +/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5)); +/// ``` +#[must_use] +pub fn count_match_start(str1: &str, str2: &str) -> StrCount { + // (char_index, char1) + let char_count = str1.chars().count(); + let iter1 = (0..=char_count).zip(str1.chars()); + // (byte_index, char2) + let iter2 = str2.char_indices(); + + iter1 + .zip(iter2) + .take_while(|((_, c1), (_, c2))| c1 == c2) + .last() + .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| { + StrCount::new(char_index + 1, byte_index + character.len_utf8()) + }) +} + +/// Returns the number of chars and bytes that match from the end +/// +/// ``` +/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4)); +/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0)); +/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6)); +/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5)); +/// ``` +#[must_use] +pub fn count_match_end(str1: &str, str2: &str) -> StrCount { + let char_count = str1.chars().count(); + if char_count == 0 { + return StrCount::default(); + } + + // (char_index, char1) + let iter1 = (0..char_count).rev().zip(str1.chars().rev()); + // (byte_index, char2) + let byte_count = str2.len(); + let iter2 = str2.char_indices().rev(); + + iter1 + .zip(iter2) + .take_while(|((_, c1), (_, c2))| c1 == c2) + .last() + .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| { + StrCount::new(char_count - char_index, byte_count - byte_index) + }) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn camel_case_start_full() { + assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0)); + } + + #[test] + fn camel_case_start_partial() { + assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); + assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1)); + assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3)); + assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4)); + } + + #[test] + fn camel_case_start_not() { + assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7)); + assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5)); + assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9)); + assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12)); + } + + #[test] + fn camel_case_start_caps() { + assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4)); + } + + #[test] + fn camel_case_until_full() { + assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6)); + assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3)); + assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9)); + } + + #[test] + fn camel_case_until_not() { + assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0)); + assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0)); + } + + #[test] + fn camel_case_until_partial() { + assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6)); + assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8)); + assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3)); + assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7)); + } + + #[test] + fn until_caps() { + assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); + } +} diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md index 004eb28b446..bd32696d6db 100644 --- a/src/tools/clippy/doc/adding_lints.md +++ b/src/tools/clippy/doc/adding_lints.md @@ -16,6 +16,7 @@ because that's clearly a non-descriptive name. - [Edition 2018 tests](#edition-2018-tests) - [Testing manually](#testing-manually) - [Lint declaration](#lint-declaration) + - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) - [Emitting a lint](#emitting-a-lint) - [Adding the lint logic](#adding-the-lint-logic) @@ -43,9 +44,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this lint you can run `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and -`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to -register the new lint. For cargo lints, two project hierarchies (fail/pass) will -be created by default under `tests/ui-cargo`. +`clippy_lints/src/foo_functions.rs`, as well as +[registering the lint](#lint-registration). For cargo lints, two project +hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. Next, we'll open up these files and add our lint! @@ -220,32 +221,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]); impl EarlyLintPass for FooFunctions {} ``` -Normally after declaring the lint, we have to run `cargo dev update_lints`, -which updates some files, so Clippy knows about the new lint. Since we used -`cargo dev new_lint ...` to generate the lint declaration, this was done -automatically. While `update_lints` automates most of the things, it doesn't -automate everything. We will have to register our lint pass manually in the -`register_plugins` function in `clippy_lints/src/lib.rs`: +[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 +[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure +[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints +[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 + +## Lint registration + +When using `cargo dev new_lint`, the lint is automatically registered and +nothing more has to be done. + +When declaring a new lint by hand and `cargo dev update_lints` is used, the lint +pass may have to be registered manually in the `register_plugins` function in +`clippy_lints/src/lib.rs`: ```rust -store.register_early_pass(|| box foo_functions::FooFunctions); +store.register_early_pass(|| Box::new(foo_functions::FooFunctions)); ``` As one may expect, there is a corresponding `register_late_pass` method available as well. Without a call to one of `register_early_pass` or `register_late_pass`, the lint pass in question will not be run. -One reason that `cargo dev` does not automate this step is that multiple lints -can use the same lint pass, so registering the lint pass may already be done -when adding a new lint. Another reason that this step is not automated is that -the order that the passes are registered determines the order the passes -actually run, which in turn affects the order that any emitted lints are output -in. - -[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 -[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure -[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints -[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 +One reason that `cargo dev update_lints` does not automate this step is that +multiple lints can use the same lint pass, so registering the lint pass may +already be done when adding a new lint. Another reason that this step is not +automated is that the order that the passes are registered determines the order +the passes actually run, which in turn affects the order that any emitted lints +are output in. ## Lint passes @@ -564,7 +567,8 @@ in the following steps: /// <The configuration field doc comment> (configuration_ident: Type = DefaultValue), ``` - The doc comment will be automatically added to the lint documentation. + The doc comment is automatically added to the documentation of the listed lints. The default + value will be formatted using the `Debug` implementation of the type. 2. Adding the configuration value to the lint impl struct: 1. This first requires the definition of a lint impl struct. Lint impl structs are usually generated with the `declare_lint_pass!` macro. This struct needs to be defined manually diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 67eaf286004..09554c08987 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-10-21" +channel = "nightly-2021-11-04" components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index c15835ef299..f25cf1d3ef5 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -104,7 +104,10 @@ fn extern_flags() -> String { } fn default_config() -> compiletest::Config { - let mut config = compiletest::Config::default(); + let mut config = compiletest::Config { + edition: Some("2021".into()), + ..compiletest::Config::default() + }; if let Ok(filters) = env::var("TESTNAME") { config.filters = filters.split(',').map(std::string::ToString::to_string).collect(); diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs index bd342e390f5..7d6edc2b1e0 100644 --- a/src/tools/clippy/tests/missing-test-files.rs +++ b/src/tools/clippy/tests/missing-test-files.rs @@ -1,7 +1,10 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::assertions_on_constants)] +#![feature(path_file_prefix)] +use std::cmp::Ordering; +use std::ffi::OsStr; use std::fs::{self, DirEntry}; use std::path::Path; @@ -21,29 +24,39 @@ fn test_missing_tests() { } } -/* -Test for missing files. - -Since rs files are alphabetically before stderr/stdout, we can sort by the full name -and iter in that order. If we've seen the file stem for the first time and it's not -a rust file, it means the rust file has to be missing. -*/ +// Test for missing files. fn explore_directory(dir: &Path) -> Vec<String> { let mut missing_files: Vec<String> = Vec::new(); let mut current_file = String::new(); let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect(); - files.sort_by_key(std::fs::DirEntry::path); + files.sort_by(|x, y| { + match x.path().file_prefix().cmp(&y.path().file_prefix()) { + Ordering::Equal => (), + ord => return ord, + } + // Sort rs files before the others if they share the same prefix. So when we see + // the file prefix for the first time and it's not a rust file, it means the rust + // file has to be missing. + match ( + x.path().extension().and_then(OsStr::to_str), + y.path().extension().and_then(OsStr::to_str), + ) { + (Some("rs"), _) => Ordering::Less, + (_, Some("rs")) => Ordering::Greater, + _ => Ordering::Equal, + } + }); for entry in &files { let path = entry.path(); if path.is_dir() { missing_files.extend(explore_directory(&path)); } else { - let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string(); + let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string(); if let Some(ext) = path.extension() { match ext.to_str().unwrap() { - "rs" => current_file = file_stem.clone(), + "rs" => current_file = file_prefix.clone(), "stderr" | "stdout" => { - if file_stem != current_file { + if file_prefix != current_file { missing_files.push(path.to_str().unwrap().to_string()); } }, diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs index 33a3ef75136..e678c896fd3 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::too_many_lines)] // This function should be considered one line. diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr index 7551cac9f50..d736bf89973 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr @@ -1,5 +1,5 @@ error: this function has too many lines (2/1) - --> $DIR/test.rs:20:1 + --> $DIR/test.rs:18:1 | LL | / fn too_many_lines() { LL | | println!("This is bad."); @@ -10,7 +10,7 @@ LL | | } = note: `-D clippy::too-many-lines` implied by `-D warnings` error: this function has too many lines (4/1) - --> $DIR/test.rs:26:1 + --> $DIR/test.rs:24:1 | LL | / async fn async_too_many_lines() { LL | | println!("This is bad."); @@ -19,7 +19,7 @@ LL | | } | |_^ error: this function has too many lines (4/1) - --> $DIR/test.rs:32:1 + --> $DIR/test.rs:30:1 | LL | / fn closure_too_many_lines() { LL | | let _ = { @@ -30,7 +30,7 @@ LL | | } | |_^ error: this function has too many lines (2/1) - --> $DIR/test.rs:54:1 + --> $DIR/test.rs:52:1 | LL | / fn comment_before_code() { LL | | let _ = "test"; diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs index 2180f848d62..cb516d0f977 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.rs +++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs @@ -1,3 +1,4 @@ +//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843 #![allow(non_fmt_panics)] macro_rules! assert_const { @@ -6,7 +7,6 @@ macro_rules! assert_const { debug_assert!($len < 0); }; } - fn main() { assert!(true); assert!(false); @@ -14,7 +14,7 @@ fn main() { assert!(false, "false message"); let msg = "panic message"; - assert!(false, msg.to_uppercase()); + assert!(false, "{}", msg.to_uppercase()); const B: bool = true; assert!(B); diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr index 4ca1e6f6e88..ec80ec702fb 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr @@ -26,22 +26,13 @@ LL | assert!(true, "true message"); = help: remove it = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `assert!(false, "false message")` should probably be replaced +error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced --> $DIR/assertions_on_constants.rs:14:5 | LL | assert!(false, "false message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: use `panic!("false message")` or `unreachable!("false message")` - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `assert!(false, msg.to_uppercase())` should probably be replaced - --> $DIR/assertions_on_constants.rs:17:5 - | -LL | assert!(false, msg.to_uppercase()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())` + = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler @@ -62,13 +53,13 @@ LL | assert!(C); = help: use `panic!()` or `unreachable!()` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `assert!(false, "C message")` should probably be replaced +error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced --> $DIR/assertions_on_constants.rs:24:5 | LL | assert!(C, "C message"); | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: use `panic!("C message")` or `unreachable!("C message")` + = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `debug_assert!(true)` will be optimized out by the compiler @@ -80,5 +71,5 @@ LL | debug_assert!(true); = help: remove it = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed index 9b1a7ac3ba9..e20b58269b9 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.fixed +++ b/src/tools/clippy/tests/ui/async_yields_async.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs index 731c094edb4..c1dfa398450 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.rs +++ b/src/tools/clippy/tests/ui/async_yields_async.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr index 3f2051458f6..b0c4215e7dd 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.stderr +++ b/src/tools/clippy/tests/ui/async_yields_async.stderr @@ -1,5 +1,5 @@ error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:40:9 + --> $DIR/async_yields_async.rs:39:9 | LL | let _h = async { | ____________________- @@ -20,7 +20,7 @@ LL + }.await | error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:45:9 + --> $DIR/async_yields_async.rs:44:9 | LL | let _i = async { | ____________________- @@ -33,7 +33,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:51:9 + --> $DIR/async_yields_async.rs:50:9 | LL | let _j = async || { | _______________________- @@ -53,7 +53,7 @@ LL + }.await | error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:56:9 + --> $DIR/async_yields_async.rs:55:9 | LL | let _k = async || { | _______________________- @@ -66,7 +66,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:58:23 + --> $DIR/async_yields_async.rs:57:23 | LL | let _l = async || CustomFutureType; | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | let _l = async || CustomFutureType; | help: consider awaiting this value: `CustomFutureType.await` error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:64:9 + --> $DIR/async_yields_async.rs:63:9 | LL | let _m = async || { | _______________________- diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs index 0458950edee..dd6640a387a 100644 --- a/src/tools/clippy/tests/ui/await_holding_lock.rs +++ b/src/tools/clippy/tests/ui/await_holding_lock.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::await_holding_lock)] use std::sync::Mutex; diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr index a5fcff7e0e4..ddfb104cdfb 100644 --- a/src/tools/clippy/tests/ui/await_holding_lock.stderr +++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr @@ -1,12 +1,12 @@ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:7:9 + --> $DIR/await_holding_lock.rs:6:9 | LL | let guard = x.lock().unwrap(); | ^^^^^ | = note: `-D clippy::await-holding-lock` implied by `-D warnings` note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:7:5 + --> $DIR/await_holding_lock.rs:6:5 | LL | / let guard = x.lock().unwrap(); LL | | baz().await @@ -14,13 +14,13 @@ LL | | } | |_^ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:28:9 + --> $DIR/await_holding_lock.rs:27:9 | LL | let guard = x.lock().unwrap(); | ^^^^^ | note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:28:5 + --> $DIR/await_holding_lock.rs:27:5 | LL | / let guard = x.lock().unwrap(); LL | | @@ -32,13 +32,13 @@ LL | | } | |_^ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:41:13 + --> $DIR/await_holding_lock.rs:40:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:41:9 + --> $DIR/await_holding_lock.rs:40:9 | LL | / let guard = x.lock().unwrap(); LL | | baz().await @@ -46,13 +46,13 @@ LL | | }; | |_____^ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:53:13 + --> $DIR/await_holding_lock.rs:52:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:53:9 + --> $DIR/await_holding_lock.rs:52:9 | LL | / let guard = x.lock().unwrap(); LL | | baz().await diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs index 88841597bb6..23b7095de3a 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::await_holding_refcell_ref)] use std::cell::RefCell; diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr index 55e41dbca96..67cc0032be2 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr @@ -1,12 +1,12 @@ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:7:9 + --> $DIR/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:7:5 + --> $DIR/await_holding_refcell_ref.rs:6:5 | LL | / let b = x.borrow(); LL | | baz().await @@ -14,13 +14,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:12:9 + --> $DIR/await_holding_refcell_ref.rs:11:9 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:12:5 + --> $DIR/await_holding_refcell_ref.rs:11:5 | LL | / let b = x.borrow_mut(); LL | | baz().await @@ -28,13 +28,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:33:9 + --> $DIR/await_holding_refcell_ref.rs:32:9 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:33:5 + --> $DIR/await_holding_refcell_ref.rs:32:5 | LL | / let b = x.borrow_mut(); LL | | @@ -46,13 +46,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:45:9 + --> $DIR/await_holding_refcell_ref.rs:44:9 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:45:5 + --> $DIR/await_holding_refcell_ref.rs:44:5 | LL | / let b = x.borrow_mut(); LL | | @@ -64,13 +64,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:60:13 + --> $DIR/await_holding_refcell_ref.rs:59:13 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:60:9 + --> $DIR/await_holding_refcell_ref.rs:59:9 | LL | / let b = x.borrow_mut(); LL | | baz().await @@ -78,13 +78,13 @@ LL | | }; | |_____^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:72:13 + --> $DIR/await_holding_refcell_ref.rs:71:13 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:72:9 + --> $DIR/await_holding_refcell_ref.rs:71:9 | LL | / let b = x.borrow_mut(); LL | | baz().await diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 8ee0969b0f0..ebc1ed5587f 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -92,4 +92,27 @@ fn main() { (1i64).checked_rem_euclid(-1i64).unwrap() as u64; (1i64).checked_rem_euclid(-1i64).unwrap() as u128; (1isize).checked_rem_euclid(-1isize).unwrap() as usize; + + // no lint for `cast_possible_truncation` + // with `signum` method call (see issue #5395) + let x: i64 = 5; + let _ = x.signum() as i32; + + let s = x.signum(); + let _ = s as i32; + + // Test for signed min + (-99999999999i64).min(1) as i8; // should be linted because signed + + // Test for various operations that remove enough bits for the result to fit + (999999u64 & 1) as u8; + (999999u64 % 15) as u8; + (999999u64 / 0x1_0000_0000_0000) as u16; + ({ 999999u64 >> 56 }) as u8; + ({ + let x = 999999u64; + x.min(1) + }) as u8; + 999999u64.clamp(0, 255) as u8; + 999999u64.clamp(0, 256) as u8; // should still be linted } diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 4c66d736494..edf8790cf33 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -138,5 +138,17 @@ error: casting `isize` to `usize` may lose the sign of the value LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ -error: aborting due to 22 previous errors +error: casting `i64` to `i8` may truncate the value + --> $DIR/cast.rs:105:5 + | +LL | (-99999999999i64).min(1) as i8; // should be linted because signed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: casting `u64` to `u8` may truncate the value + --> $DIR/cast.rs:117:5 + | +LL | 999999u64.clamp(0, 256) as u8; // should still be linted + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs new file mode 100644 index 00000000000..bee29894b63 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs @@ -0,0 +1,3 @@ +fn zero() { + unsafe { 0 }; +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.rs b/src/tools/clippy/tests/ui/crashes/ice-3969.rs index 4feab7910b7..9b68cac7ff4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3969.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.rs @@ -7,7 +7,6 @@ // in type inference. #![feature(trivial_bounds)] #![allow(unused)] - trait A {} impl A for i32 {} @@ -22,9 +21,9 @@ where fn unsized_local() where - for<'a> Dst<A + 'a>: Sized, + for<'a> Dst<dyn A + 'a>: Sized, { - let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); + let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>); } fn return_str() -> str diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr index 9a89047f072..79018080886 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr @@ -1,30 +1,34 @@ -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-3969.rs:25:17 +error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:20:10 | -LL | for<'a> Dst<A + 'a>: Sized, - | ^^^^^^ help: use `dyn`: `dyn A + 'a` +LL | str: Sized; + | ^^^^^ | - = note: `-D bare-trait-objects` implied by `-D warnings` - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> + = note: `-D trivial-bounds` implied by `-D warnings` -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-3969.rs:27:16 +error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:24:30 | -LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); - | ^ help: use `dyn`: `dyn A` +LL | for<'a> Dst<dyn A + 'a>: Sized, + | ^^^^^ + +error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:31:10 | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> +LL | str: Sized, + | ^^^^^ -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-3969.rs:27:57 +error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:38:13 | -LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); - | ^ help: use `dyn`: `dyn A` +LL | String: ::std::ops::Neg<Output = String>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:45:10 | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> +LL | i32: Iterator, + | ^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs index 1b20c9defac..f463f78a99a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5207.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs @@ -1,5 +1,3 @@ -// edition:2018 - // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 pub async fn bar<'a, T: 'a>(_: T) {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.rs b/src/tools/clippy/tests/ui/crashes/ice-6252.rs index 2e3d9fd1e92..0ccf0aae9d7 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.rs @@ -1,6 +1,5 @@ // originally from glacier fixed/77919.rs // encountered errors resolving bounds after type-checking - trait TypeVal<T> { const VAL: T; } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index eaa5e6f51cb..c8239897f3a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -1,16 +1,20 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/ice-6252.rs:9:9 + --> $DIR/ice-6252.rs:8:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope | -help: consider importing this struct +help: consider importing one of these items + | +LL | use core::marker::PhantomData; + | +LL | use serde::__private::PhantomData; | LL | use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/ice-6252.rs:11:63 + --> $DIR/ice-6252.rs:10:63 | LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | - ^^^ not found in this scope @@ -18,7 +22,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/ice-6252.rs:11:1 + --> $DIR/ice-6252.rs:10:1 | LL | const VAL: T; | ------------- `VAL` from trait diff --git a/src/tools/clippy/tests/ui/crashes/ice-7231.rs b/src/tools/clippy/tests/ui/crashes/ice-7231.rs index 5595d8d1d62..4ad0d351372 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7231.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7231.rs @@ -1,4 +1,3 @@ -// edition:2018 #![allow(clippy::never_loop)] async fn f() { diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.rs b/src/tools/clippy/tests/ui/crashes/ice-7868.rs new file mode 100644 index 00000000000..c6932164e3b --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7868.rs @@ -0,0 +1,7 @@ +#![warn(clippy::undocumented_unsafe_blocks)] +#![allow(clippy::no_effect)] + +#[path = "auxiliary/ice-7868-aux.rs"] +mod zero; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr new file mode 100644 index 00000000000..d7b49eb89a2 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr @@ -0,0 +1,15 @@ +error: unsafe block missing a safety comment + --> $DIR/auxiliary/ice-7868-aux.rs:2:5 + | +LL | unsafe { 0 }; + | ^^^^^^^^^^^^ + | + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL ~ unsafe { 0 }; + | + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.rs b/src/tools/clippy/tests/ui/crashes/ice-7869.rs new file mode 100644 index 00000000000..8f97a063a9a --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7869.rs @@ -0,0 +1,7 @@ +enum Tila { + TyöAlkoi, + TyöKeskeytyi, + TyöValmis, +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.stderr b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr new file mode 100644 index 00000000000..4fa9fb27e76 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr @@ -0,0 +1,15 @@ +error: all variants have the same prefix: `Työ` + --> $DIR/ice-7869.rs:1:1 + | +LL | / enum Tila { +LL | | TyöAlkoi, +LL | | TyöKeskeytyi, +LL | | TyöValmis, +LL | | } + | |_^ + | + = note: `-D clippy::enum-variant-names` implied by `-D warnings` + = help: remove the prefixes and use full paths to the variants instead of glob imports + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs index c57a45dc7aa..901eb4e5039 100644 --- a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs @@ -1,5 +1,3 @@ -// edition:2018 - use serde::Deserialize; /// Tests that we do not lint for unused underscores in a `MacroAttribute` diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs index 477a47118d4..c5de4125565 100644 --- a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs +++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs @@ -1,9 +1,9 @@ -// compile-flags: --edition=2018 #![feature(custom_inner_attributes)] #![rustfmt::skip] #![warn(clippy::debug_assert_with_mut_call)] #![allow(clippy::redundant_closure_call)] + struct S; impl S { diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index 1943d0092e6..39a2601fee9 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -1,19 +1,18 @@ -#[warn(clippy::unstable_as_slice)] -#[warn(clippy::unstable_as_mut_slice)] -#[warn(clippy::misaligned_transmute)] -#[warn(clippy::unused_collect)] -#[warn(clippy::invalid_ref)] -#[warn(clippy::into_iter_on_array)] -#[warn(clippy::unused_label)] -#[warn(clippy::regex_macro)] -#[warn(clippy::drop_bounds)] -#[warn(clippy::temporary_cstring_as_ptr)] -#[warn(clippy::panic_params)] -#[warn(clippy::unknown_clippy_lints)] -#[warn(clippy::find_map)] -#[warn(clippy::filter_map)] -#[warn(clippy::pub_enum_variant_names)] -#[warn(clippy::wrong_pub_self_convention)] -#[warn(clippy::invalid_atomic_ordering)] +#![warn(clippy::should_assert_eq)] +#![warn(clippy::extend_from_slice)] +#![warn(clippy::range_step_by_zero)] +#![warn(clippy::unstable_as_slice)] +#![warn(clippy::unstable_as_mut_slice)] +#![warn(clippy::misaligned_transmute)] +#![warn(clippy::assign_ops)] +#![warn(clippy::if_let_redundant_pattern_matching)] +#![warn(clippy::unsafe_vector_initialization)] +#![warn(clippy::unused_collect)] +#![warn(clippy::replace_consts)] +#![warn(clippy::regex_macro)] +#![warn(clippy::find_map)] +#![warn(clippy::filter_map)] +#![warn(clippy::pub_enum_variant_names)] +#![warn(clippy::wrong_pub_self_convention)] fn main() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index 51048e45c06..6095f134d55 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -1,106 +1,100 @@ -error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 - --> $DIR/deprecated.rs:1:8 +error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011 + --> $DIR/deprecated.rs:1:9 | -LL | #[warn(clippy::unstable_as_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::should_assert_eq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = 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 - --> $DIR/deprecated.rs:2:8 +error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice + --> $DIR/deprecated.rs:2:9 | -LL | #[warn(clippy::unstable_as_mut_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::extend_from_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -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 +error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays + --> $DIR/deprecated.rs:3:9 | -LL | #[warn(clippy::misaligned_transmute)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::range_step_by_zero)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -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 +error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 + --> $DIR/deprecated.rs:4:9 | -LL | #[warn(clippy::unused_collect)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/deprecated.rs:5:8 +error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 + --> $DIR/deprecated.rs:5:9 | -LL | #[warn(clippy::invalid_ref)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +LL | #![warn(clippy::unstable_as_mut_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/deprecated.rs:6:8 +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:6:9 | -LL | #[warn(clippy::into_iter_on_array)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` +LL | #![warn(clippy::misaligned_transmute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/deprecated.rs:7:8 +error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless + --> $DIR/deprecated.rs:7:9 | -LL | #[warn(clippy::unused_label)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` +LL | #![warn(clippy::assign_ops)] + | ^^^^^^^^^^^^^^^^^^ -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 +error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching + --> $DIR/deprecated.rs:8:9 | -LL | #[warn(clippy::regex_macro)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::if_let_redundant_pattern_matching)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/deprecated.rs:9:8 +error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior + --> $DIR/deprecated.rs:9:9 | -LL | #[warn(clippy::drop_bounds)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` +LL | #![warn(clippy::unsafe_vector_initialization)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/deprecated.rs:10:8 +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:10:9 | -LL | #[warn(clippy::temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` +LL | #![warn(clippy::unused_collect)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/deprecated.rs:11:8 +error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants + --> $DIR/deprecated.rs:11:9 | -LL | #[warn(clippy::panic_params)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` +LL | #![warn(clippy::replace_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/deprecated.rs:12:8 +error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018 + --> $DIR/deprecated.rs:12:9 | -LL | #[warn(clippy::unknown_clippy_lints)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` +LL | #![warn(clippy::regex_macro)] + | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint - --> $DIR/deprecated.rs:13:8 + --> $DIR/deprecated.rs:13:9 | -LL | #[warn(clippy::find_map)] - | ^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::find_map)] + | ^^^^^^^^^^^^^^^^ error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint - --> $DIR/deprecated.rs:14:8 + --> $DIR/deprecated.rs:14:9 | -LL | #[warn(clippy::filter_map)] - | ^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::filter_map)] + | ^^^^^^^^^^^^^^^^^^ error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items - --> $DIR/deprecated.rs:15:8 + --> $DIR/deprecated.rs:15:9 | -LL | #[warn(clippy::pub_enum_variant_names)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::pub_enum_variant_names)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items - --> $DIR/deprecated.rs:16:8 - | -LL | #[warn(clippy::wrong_pub_self_convention)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/deprecated.rs:17:8 + --> $DIR/deprecated.rs:16:9 | -LL | #[warn(clippy::invalid_atomic_ordering)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` +LL | #![warn(clippy::wrong_pub_self_convention)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs index 4df241c9fc3..e27f9fea708 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.rs +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs @@ -1,6 +1,5 @@ #![warn(clippy::diverging_sub_expression)] #![allow(clippy::match_same_arms, clippy::logic_bug)] - #[allow(clippy::empty_loop)] fn diverge() -> ! { loop {} diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr index 170e7d92de4..c712a6a7e38 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr @@ -1,5 +1,5 @@ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:20:10 + --> $DIR/diverging_sub_expression.rs:19:10 | LL | b || diverge(); | ^^^^^^^^^ @@ -7,34 +7,42 @@ LL | b || diverge(); = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:21:10 + --> $DIR/diverging_sub_expression.rs:20:10 | LL | b || A.foo(); | ^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:30:26 + --> $DIR/diverging_sub_expression.rs:29:26 | LL | 6 => true || return, | ^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:31:26 + --> $DIR/diverging_sub_expression.rs:30:26 | LL | 7 => true || continue, | ^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:34:26 + --> $DIR/diverging_sub_expression.rs:33:26 | LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:39:26 + --> $DIR/diverging_sub_expression.rs:36:30 + | +LL | _ => true || panic!("boo"), + | ^^^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:38:26 | LL | _ => true || break, | ^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed new file mode 100644 index 00000000000..747801b40ee --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -0,0 +1,215 @@ +// run-rustfix +//! This file tests for the `DOC_MARKDOWN` lint. + +#![allow(dead_code, incomplete_features)] +#![warn(clippy::doc_markdown)] +#![feature(custom_inner_attributes, generic_const_exprs, const_option)] +#![rustfmt::skip] + +/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there) +/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun` +/// which should be reported only once despite being __doubly bad__. +/// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though. +/// Import an item from `::awesome::global::blob::` (Intended postfix) +/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted) +/// That's not code ~`NotInCodeBlock`~. +/// `be_sure_we_got_to_the_end_of_it` +fn foo_bar() { +} + +/// That one tests multiline ticks. +/// ```rust +/// foo_bar FOO_BAR +/// _foo bar_ +/// ``` +/// +/// ~~~rust +/// foo_bar FOO_BAR +/// _foo bar_ +/// ~~~ +/// `be_sure_we_got_to_the_end_of_it` +fn multiline_codeblock() { +} + +/// This _is a test for +/// multiline +/// emphasis_. +/// `be_sure_we_got_to_the_end_of_it` +fn test_emphasis() { +} + +/// This tests units. See also #835. +/// kiB MiB GiB TiB PiB EiB +/// kib Mib Gib Tib Pib Eib +/// kB MB GB TB PB EB +/// kb Mb Gb Tb Pb Eb +/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB +/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib +/// 32kB 32MB 32GB 32TB 32PB 32EB +/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb +/// NaN +/// `be_sure_we_got_to_the_end_of_it` +fn test_units() { +} + +/// This tests allowed identifiers. +/// KiB MiB GiB TiB PiB EiB +/// DirectX +/// ECMAScript +/// GPLv2 GPLv3 +/// GitHub GitLab +/// IPv4 IPv6 +/// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// NaN NaNs +/// OAuth GraphQL +/// OCaml +/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS +/// WebGL +/// TensorFlow +/// TrueType +/// iOS macOS FreeBSD +/// TeX LaTeX BibTeX BibLaTeX +/// MinGW +/// CamelCase (see also #2395) +/// `be_sure_we_got_to_the_end_of_it` +fn test_allowed() { +} + +/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823. +/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues) +/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. +/// It can also be [`inline_link2`]. +/// +/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example +/// [inline_link]: https://foobar +/// [inline_link2]: https://foobar +/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and +/// `multiline_ticks` functions. +/// +/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` +/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , +/// `be_sure_we_got_to_the_end_of_it` +fn main() { + foo_bar(); + multiline_codeblock(); + test_emphasis(); + test_units(); +} + +/// ## `CamelCaseThing` +/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897. +/// +/// # `CamelCaseThing` +/// +/// Not a title #897 `CamelCaseThing` +/// `be_sure_we_got_to_the_end_of_it` +fn issue897() { +} + +/// I am confused by brackets? (`x_y`) +/// I am confused by brackets? (foo `x_y`) +/// I am confused by brackets? (`x_y` foo) +/// `be_sure_we_got_to_the_end_of_it` +fn issue900() { +} + +/// Diesel queries also have a similar problem to [Iterator][iterator], where +/// /// More talking +/// returning them from a function requires exposing the implementation of that +/// function. The [`helper_types`][helper_types] module exists to help with this, +/// but you might want to hide the return type or have it conditionally change. +/// Boxing can achieve both. +/// +/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html +/// [helper_types]: ../helper_types/index.html +/// `be_sure_we_got_to_the_end_of_it` +fn issue883() { +} + +/// `foo_bar +/// baz_quz` +/// [foo +/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html) +fn multiline() { +} + +/** E.g., serialization of an empty list: `FooBar` +``` +That's in a code block: `PackedNode` +``` + +And `BarQuz` too. +`be_sure_we_got_to_the_end_of_it` +*/ +fn issue1073() { +} + +/** E.g., serialization of an empty list: `FooBar` +``` +That's in a code block: PackedNode +``` + +And `BarQuz` too. +`be_sure_we_got_to_the_end_of_it` +*/ +fn issue1073_alt() { +} + +/// Tests more than three quotes: +/// ```` +/// DoNotWarn +/// ``` +/// StillDont +/// ```` +/// `be_sure_we_got_to_the_end_of_it` +fn four_quotes() { +} + +#[cfg_attr(feature = "a", doc = " ```")] +#[cfg_attr(not(feature = "a"), doc = " ```ignore")] +/// fn main() { +/// let s = "localhost:10000".to_string(); +/// println!("{}", s); +/// } +/// ``` +fn issue_1469() {} + +/** + * This is a doc comment that should not be a list + *This would also be an error under a strict common mark interpretation + */ +fn issue_1920() {} + +/// An iterator over `mycrate::Collection`'s values. +/// It should not lint a `'static` lifetime in ticks. +fn issue_2210() {} + +/// This should not cause the lint to trigger: +/// #REQ-data-family.lint_partof_exists +fn issue_2343() {} + +/// This should not cause an ICE: +/// __|_ _|__||_| +fn pulldown_cmark_crash() {} + +/// This should not lint +/// (regression test for #7758) +/// [plain text][path::to::item] +fn intra_doc_link() {} + +// issue #7033 - generic_const_exprs ICE +struct S<T, const N: usize> +where [(); N.checked_next_power_of_two().unwrap()]: { + arr: [T; N.checked_next_power_of_two().unwrap()], + n: usize, +} + +impl<T: Copy + Default, const N: usize> S<T, N> +where [(); N.checked_next_power_of_two().unwrap()]: { + fn new() -> Self { + Self { + arr: [T::default(); N.checked_next_power_of_two().unwrap()], + n: 0, + } + } +} diff --git a/src/tools/clippy/tests/ui/doc/doc.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 342208e52b8..f3cf966157a 100644 --- a/src/tools/clippy/tests/ui/doc/doc.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -1,3 +1,4 @@ +// run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] @@ -8,7 +9,9 @@ /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun /// which should be reported only once despite being __doubly bad__. -/// Here be ::a::global:path. +/// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. +/// Import an item from ::awesome::global::blob:: (Intended postfix) +/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) /// That's not code ~NotInCodeBlock~. /// be_sure_we_got_to_the_end_of_it fn foo_bar() { @@ -162,12 +165,6 @@ fn issue1073_alt() { fn four_quotes() { } -/// See [NIST SP 800-56A, revision 2]. -/// -/// [NIST SP 800-56A, revision 2]: -/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419 -fn issue_902_comment() {} - #[cfg_attr(feature = "a", doc = " ```")] #[cfg_attr(not(feature = "a"), doc = " ```ignore")] /// fn main() { @@ -183,14 +180,6 @@ fn issue_1469() {} */ fn issue_1920() {} -/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels> -/// -/// Not ok: http://www.unicode.org -/// Not ok: https://www.unicode.org -/// Not ok: http://www.unicode.org/ -/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels -fn issue_1832() {} - /// An iterator over mycrate::Collection's values. /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr new file mode 100644 index 00000000000..31132f86edb --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr @@ -0,0 +1,184 @@ +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:9:9 + | +LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) + | ^^^^^^^ help: try: ``foo_bar`` + | + = note: `-D clippy::doc-markdown` implied by `-D warnings` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:9:51 + | +LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) + | ^^^^^^^^ help: try: ``foo::bar`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:10:83 + | +LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun + | ^^^^^^^^^^^^^ help: try: ``Foo::some_fun`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:12:13 + | +LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. + | ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:12:36 + | +LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:13:25 + | +LL | /// Import an item from ::awesome::global::blob:: (Intended postfix) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:14:31 + | +LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) + | ^^^^^ help: try: ``::Cat`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:15:22 + | +LL | /// That's not code ~NotInCodeBlock~. + | ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:16:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:30:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:37:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:51:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:74:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:78:22 + | +LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. + | ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:81:21 + | +LL | /// It can also be [inline_link2]. + | ^^^^^^^^^^^^ help: try: ``inline_link2`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:91:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:99:8 + | +LL | /// ## CamelCaseThing + | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:102:7 + | +LL | /// # CamelCaseThing + | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:104:22 + | +LL | /// Not a title #897 CamelCaseThing + | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:105:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:112:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:125:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:136:43 + | +LL | /** E.g., serialization of an empty list: FooBar + | ^^^^^^ help: try: ``FooBar`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:141:5 + | +LL | And BarQuz too. + | ^^^^^^ help: try: ``BarQuz`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:142:1 + | +LL | be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:147:43 + | +LL | /** E.g., serialization of an empty list: FooBar + | ^^^^^^ help: try: ``FooBar`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:152:5 + | +LL | And BarQuz too. + | ^^^^^^ help: try: ``BarQuz`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:153:1 + | +LL | be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:164:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:183:22 + | +LL | /// An iterator over mycrate::Collection's values. + | ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection`` + +error: aborting due to 30 previous errors + diff --git a/src/tools/clippy/tests/ui/doc/doc.stderr b/src/tools/clippy/tests/ui/doc/doc.stderr deleted file mode 100644 index 7eab8a85f09..00000000000 --- a/src/tools/clippy/tests/ui/doc/doc.stderr +++ /dev/null @@ -1,190 +0,0 @@ -error: you should put `foo_bar` between ticks in the documentation - --> $DIR/doc.rs:8:9 - | -LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) - | ^^^^^^^ - | - = note: `-D clippy::doc-markdown` implied by `-D warnings` - -error: you should put `foo::bar` between ticks in the documentation - --> $DIR/doc.rs:8:51 - | -LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) - | ^^^^^^^^ - -error: you should put `Foo::some_fun` between ticks in the documentation - --> $DIR/doc.rs:9:83 - | -LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun - | ^^^^^^^^^^^^^ - -error: you should put `a::global:path` between ticks in the documentation - --> $DIR/doc.rs:11:15 - | -LL | /// Here be ::a::global:path. - | ^^^^^^^^^^^^^^ - -error: you should put `NotInCodeBlock` between ticks in the documentation - --> $DIR/doc.rs:12:22 - | -LL | /// That's not code ~NotInCodeBlock~. - | ^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:13:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:27:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:34:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:48:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:71:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:75:22 - | -LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. - | ^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:78:21 - | -LL | /// It can also be [inline_link2]. - | ^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:88:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:96:8 - | -LL | /// ## CamelCaseThing - | ^^^^^^^^^^^^^^ - -error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:99:7 - | -LL | /// # CamelCaseThing - | ^^^^^^^^^^^^^^ - -error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:101:22 - | -LL | /// Not a title #897 CamelCaseThing - | ^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:102:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:109:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:122:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:133:43 - | -LL | /** E.g., serialization of an empty list: FooBar - | ^^^^^^ - -error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:138:5 - | -LL | And BarQuz too. - | ^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:139:1 - | -LL | be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:144:43 - | -LL | /** E.g., serialization of an empty list: FooBar - | ^^^^^^ - -error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:149:5 - | -LL | And BarQuz too. - | ^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:150:1 - | -LL | be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:161:5 - | -LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:188:13 - | -LL | /// Not ok: http://www.unicode.org - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:189:13 - | -LL | /// Not ok: https://www.unicode.org - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:190:13 - | -LL | /// Not ok: http://www.unicode.org/ - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:191:13 - | -LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:194:22 - | -LL | /// An iterator over mycrate::Collection's values. - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 31 previous errors - diff --git a/src/tools/clippy/tests/ui/doc/issue_1832.rs b/src/tools/clippy/tests/ui/doc/issue_1832.rs new file mode 100644 index 00000000000..10586f16d46 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/issue_1832.rs @@ -0,0 +1,9 @@ +/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels> +/// +/// Not ok: http://www.unicode.org +/// Not ok: https://www.unicode.org +/// Not ok: http://www.unicode.org/ +/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels +fn issue_1832() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/issue_902.rs b/src/tools/clippy/tests/ui/doc/issue_902.rs new file mode 100644 index 00000000000..4b0c835dd3f --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/issue_902.rs @@ -0,0 +1,7 @@ +/// See [NIST SP 800-56A, revision 2]. +/// +/// [NIST SP 800-56A, revision 2]: +/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419 +fn issue_902_comment() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr index 45ca34e2a8c..9670e5c24fb 100644 --- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr +++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr @@ -18,11 +18,11 @@ LL | /// This paragraph has `unbalanced_tick marks and should stop_linting. | = help: a backtick may be missing a pair -error: you should put `should_be` between ticks in the documentation +error: item in documentation is missing backticks --> $DIR/unbalanced_ticks.rs:15:32 | LL | /// This paragraph is fine and should_be linted normally. - | ^^^^^^^^^ + | ^^^^^^^^^ help: try: ``should_be`` error: backticks are unbalanced --> $DIR/unbalanced_ticks.rs:17:1 @@ -32,11 +32,11 @@ LL | /// Double unbalanced backtick from ``here to here` should lint. | = help: a backtick may be missing a pair -error: you should put `not_fine` between ticks in the documentation +error: item in documentation is missing backticks --> $DIR/unbalanced_ticks.rs:30:8 | LL | /// ## not_fine - | ^^^^^^^^ + | ^^^^^^^^ help: try: ``not_fine`` error: backticks are unbalanced --> $DIR/unbalanced_ticks.rs:32:1 @@ -54,11 +54,11 @@ LL | /// - This `item has unbalanced tick marks | = help: a backtick may be missing a pair -error: you should put `backticks_here` between ticks in the documentation +error: item in documentation is missing backticks --> $DIR/unbalanced_ticks.rs:35:23 | LL | /// - This item needs backticks_here - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: try: ``backticks_here`` error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/doc_errors.rs b/src/tools/clippy/tests/ui/doc_errors.rs index c77a74a58f2..30fdd3b0873 100644 --- a/src/tools/clippy/tests/ui/doc_errors.rs +++ b/src/tools/clippy/tests/ui/doc_errors.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::missing_errors_doc)] #![allow(clippy::result_unit_err)] #![allow(clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr index b5a81419dae..c7b616e2897 100644 --- a/src/tools/clippy/tests/ui/doc_errors.stderr +++ b/src/tools/clippy/tests/ui/doc_errors.stderr @@ -1,5 +1,5 @@ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:8:1 + --> $DIR/doc_errors.rs:7:1 | LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-errors-doc` implied by `-D warnings` error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:12:1 + --> $DIR/doc_errors.rs:11:1 | LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:17:1 + --> $DIR/doc_errors.rs:16:1 | LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:22:1 + --> $DIR/doc_errors.rs:21:1 | LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:52:5 + --> $DIR/doc_errors.rs:51:5 | LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:57:5 + --> $DIR/doc_errors.rs:56:5 | LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -49,7 +49,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:86:5 + --> $DIR/doc_errors.rs:85:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs index 03bb30f9083..4464a21b3b6 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.rs +++ b/src/tools/clippy/tests/ui/doc_unsafe.rs @@ -125,3 +125,8 @@ pub mod __macro { pub unsafe fn f() {} } } + +/// # Implementation safety +pub unsafe trait DocumentedUnsafeTraitWithImplementationHeader { + fn method(); +} diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index 447fbb9e1bf..add8a91e26b 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -60,7 +60,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: all variants have the same prefix: `With` +error: all variants have the same prefix: `WithOut` --> $DIR/enum_variants.rs:81:1 | LL | / enum Seallll { diff --git a/src/tools/clippy/tests/ui/eval_order_dependence.rs b/src/tools/clippy/tests/ui/eval_order_dependence.rs index 8e6a32b7be3..aad78319d48 100644 --- a/src/tools/clippy/tests/ui/eval_order_dependence.rs +++ b/src/tools/clippy/tests/ui/eval_order_dependence.rs @@ -1,5 +1,3 @@ -// edition:2018 - #[warn(clippy::eval_order_dependence)] #[allow( unused_assignments, diff --git a/src/tools/clippy/tests/ui/eval_order_dependence.stderr b/src/tools/clippy/tests/ui/eval_order_dependence.stderr index 4f611e308e1..7c6265a0879 100644 --- a/src/tools/clippy/tests/ui/eval_order_dependence.stderr +++ b/src/tools/clippy/tests/ui/eval_order_dependence.stderr @@ -1,48 +1,48 @@ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:16:9 + --> $DIR/eval_order_dependence.rs:14:9 | LL | } + x; | ^ | = note: `-D clippy::eval-order-dependence` implied by `-D warnings` note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:14:9 + --> $DIR/eval_order_dependence.rs:12:9 | LL | x = 1; | ^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:19:5 + --> $DIR/eval_order_dependence.rs:17:5 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:20:9 + --> $DIR/eval_order_dependence.rs:18:9 | LL | x = 20; | ^^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:32:12 + --> $DIR/eval_order_dependence.rs:30:12 | LL | a: x, | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:34:13 + --> $DIR/eval_order_dependence.rs:32:13 | LL | x = 6; | ^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:41:9 + --> $DIR/eval_order_dependence.rs:39:9 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:42:13 + --> $DIR/eval_order_dependence.rs:40:13 | LL | x = 20; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.rs b/src/tools/clippy/tests/ui/fallible_impl_from.rs index 495cd97e05e..5d5af4e4632 100644 --- a/src/tools/clippy/tests/ui/fallible_impl_from.rs +++ b/src/tools/clippy/tests/ui/fallible_impl_from.rs @@ -1,5 +1,4 @@ #![deny(clippy::fallible_impl_from)] -#![allow(clippy::if_then_panic)] // docs example struct Foo(i32); diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.stderr b/src/tools/clippy/tests/ui/fallible_impl_from.stderr index f5d0b98c108..4e0f08a1215 100644 --- a/src/tools/clippy/tests/ui/fallible_impl_from.stderr +++ b/src/tools/clippy/tests/ui/fallible_impl_from.stderr @@ -1,5 +1,5 @@ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:6:1 + --> $DIR/fallible_impl_from.rs:5:1 | LL | / impl From<String> for Foo { LL | | fn from(s: String) -> Self { @@ -15,13 +15,13 @@ LL | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:8:13 + --> $DIR/fallible_impl_from.rs:7:13 | LL | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:27:1 + --> $DIR/fallible_impl_from.rs:26:1 | LL | / impl From<usize> for Invalid { LL | | fn from(i: usize) -> Invalid { @@ -34,14 +34,14 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:30:13 + --> $DIR/fallible_impl_from.rs:29:13 | LL | panic!(); | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:36:1 + --> $DIR/fallible_impl_from.rs:35:1 | LL | / impl From<Option<String>> for Invalid { LL | | fn from(s: Option<String>) -> Invalid { @@ -54,7 +54,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:38:17 + --> $DIR/fallible_impl_from.rs:37:17 | LL | let s = s.unwrap(); | ^^^^^^^^^^ @@ -65,10 +65,10 @@ LL | } else if s.parse::<u32>().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); | ^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:54:1 + --> $DIR/fallible_impl_from.rs:53:1 | LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid { LL | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid { @@ -81,13 +81,13 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:56:12 + --> $DIR/fallible_impl_from.rs:55:12 | LL | if s.parse::<u32>().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); | ^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed index 73fc750511c..64cb7b1cfb8 100644 --- a/src/tools/clippy/tests/ui/format.fixed +++ b/src/tools/clippy/tests/ui/format.fixed @@ -16,6 +16,8 @@ fn main() { r##"foo {} " bar"##.to_string(); + let _ = String::new(); + "foo".to_string(); format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs index 2f4595650cb..a065b1b5683 100644 --- a/src/tools/clippy/tests/ui/format.rs +++ b/src/tools/clippy/tests/ui/format.rs @@ -18,6 +18,8 @@ fn main() { " bar"## ); + let _ = format!(""); + format!("{}", "foo"); format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr index 701399b32d6..58ad7499bb2 100644 --- a/src/tools/clippy/tests/ui/format.stderr +++ b/src/tools/clippy/tests/ui/format.stderr @@ -34,64 +34,70 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> $DIR/format.rs:21:5 + --> $DIR/format.rs:21:13 + | +LL | let _ = format!(""); + | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` + +error: useless use of `format!` + --> $DIR/format.rs:23:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:25:5 + --> $DIR/format.rs:27:5 | LL | format!("{:+}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:26:5 + --> $DIR/format.rs:28:5 | LL | format!("{:<}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:31:5 + --> $DIR/format.rs:33:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:35:5 + --> $DIR/format.rs:37:5 | LL | format!("{:+}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:36:5 + --> $DIR/format.rs:38:5 | LL | format!("{:<}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:63:5 + --> $DIR/format.rs:65:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:65:5 + --> $DIR/format.rs:67:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:69:18 + --> $DIR/format.rs:71:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:73:22 + --> $DIR/format.rs:75:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index 8376566c4d6..69b5e1c722e 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed @@ -5,6 +5,7 @@ #![allow(unused_variables)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] +#![allow(clippy::print_literal)] #![warn(clippy::to_string_in_format_args)] use std::io::{stdout, Write}; @@ -97,9 +98,20 @@ fn main() { println!("{}", Z(1)); println!("{}", **x); println!("{}", ***x_ref); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{bar}", foo = "foo", bar = "bar"); + println!("{foo}{bar}", foo = "foo", bar = "bar"); + println!("{foo}{bar}", bar = "bar", foo = "foo"); + println!("{foo}{bar}", bar = "bar", foo = "foo"); + // negative tests println!("error: something failed at {}", Somewhere.to_string()); + // The next two tests are negative because caching the string might be faster than calling `<X as + // Display>::fmt` twice. println!("{} and again {0}", x.to_string()); + println!("{foo}{foo}", foo = "foo".to_string()); my_macro!(); println!("error: something failed at {}", my_other_macro!()); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{foo:?}", foo = "foo".to_string()); } diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index 164cc07066d..3a434c5bf00 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs @@ -5,6 +5,7 @@ #![allow(unused_variables)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] +#![allow(clippy::print_literal)] #![warn(clippy::to_string_in_format_args)] use std::io::{stdout, Write}; @@ -97,9 +98,20 @@ fn main() { println!("{}", Z(1).to_string()); println!("{}", x.to_string()); println!("{}", x_ref.to_string()); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); + println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); + println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); + println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + // negative tests println!("error: something failed at {}", Somewhere.to_string()); + // The next two tests are negative because caching the string might be faster than calling `<X as + // Display>::fmt` twice. println!("{} and again {0}", x.to_string()); + println!("{foo}{foo}", foo = "foo".to_string()); my_macro!(); println!("error: something failed at {}", my_other_macro!()); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{foo:?}", foo = "foo".to_string()); } diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr index 9cfc97edeaf..c0cbca50795 100644 --- a/src/tools/clippy/tests/ui/format_args.stderr +++ b/src/tools/clippy/tests/ui/format_args.stderr @@ -1,5 +1,5 @@ error: `to_string` applied to a type that implements `Display` in `format!` args - --> $DIR/format_args.rs:75:72 + --> $DIR/format_args.rs:76:72 | LL | let _ = format!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this @@ -7,100 +7,124 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` error: `to_string` applied to a type that implements `Display` in `write!` args - --> $DIR/format_args.rs:79:27 + --> $DIR/format_args.rs:80:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `writeln!` args - --> $DIR/format_args.rs:84:27 + --> $DIR/format_args.rs:85:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> $DIR/format_args.rs:86:63 + --> $DIR/format_args.rs:87:63 | LL | print!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:87:65 + --> $DIR/format_args.rs:88:65 | LL | println!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprint!` args - --> $DIR/format_args.rs:88:64 + --> $DIR/format_args.rs:89:64 | LL | eprint!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprintln!` args - --> $DIR/format_args.rs:89:66 + --> $DIR/format_args.rs:90:66 | LL | eprintln!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format_args!` args - --> $DIR/format_args.rs:90:77 + --> $DIR/format_args.rs:91:77 | LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert!` args - --> $DIR/format_args.rs:91:70 + --> $DIR/format_args.rs:92:70 | LL | assert!(true, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_eq!` args - --> $DIR/format_args.rs:92:73 + --> $DIR/format_args.rs:93:73 | LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_ne!` args - --> $DIR/format_args.rs:93:73 + --> $DIR/format_args.rs:94:73 | LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `panic!` args - --> $DIR/format_args.rs:94:63 + --> $DIR/format_args.rs:95:63 | LL | panic!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:95:20 + --> $DIR/format_args.rs:96:20 | LL | println!("{}", X(1).to_string()); | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:96:20 + --> $DIR/format_args.rs:97:20 | LL | println!("{}", Y(&X(1)).to_string()); | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:97:24 + --> $DIR/format_args.rs:98:24 | LL | println!("{}", Z(1).to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:98:20 + --> $DIR/format_args.rs:99:20 | LL | println!("{}", x.to_string()); | ^^^^^^^^^^^^^ help: use this: `**x` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:99:20 + --> $DIR/format_args.rs:100:20 | LL | println!("{}", x_ref.to_string()); | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` -error: aborting due to 17 previous errors +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:102:39 + | +LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:103:52 + | +LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:104:39 + | +LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:105:52 + | +LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.rs b/src/tools/clippy/tests/ui/format_args_unfixable.rs index a8c06c2bde6..b24ddf7321e 100644 --- a/src/tools/clippy/tests/ui/format_args_unfixable.rs +++ b/src/tools/clippy/tests/ui/format_args_unfixable.rs @@ -51,6 +51,7 @@ fn main() { assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); panic!("error: {}", format!("something failed at {}", Location::caller())); + // negative tests println!("error: {}", format_args!("something failed at {}", Location::caller())); println!("error: {:>70}", format!("something failed at {}", Location::caller())); println!("error: {} {0}", format!("something failed at {}", Location::caller())); diff --git a/src/tools/clippy/tests/ui/future_not_send.rs b/src/tools/clippy/tests/ui/future_not_send.rs index d3a920de4b6..858036692d6 100644 --- a/src/tools/clippy/tests/ui/future_not_send.rs +++ b/src/tools/clippy/tests/ui/future_not_send.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::future_not_send)] use std::cell::Cell; diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr index c734051ccf3..3cc05e2fdbe 100644 --- a/src/tools/clippy/tests/ui/future_not_send.stderr +++ b/src/tools/clippy/tests/ui/future_not_send.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:8:62 + --> $DIR/future_not_send.rs:7:62 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ^^^^ future returned by `private_future` is not `Send` | = note: `-D clippy::future-not-send` implied by `-D warnings` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:9:5 + --> $DIR/future_not_send.rs:8:5 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` @@ -16,7 +16,7 @@ LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:9:5 + --> $DIR/future_not_send.rs:8:5 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ---- has type `&std::cell::Cell<usize>` which is not `Send` @@ -27,13 +27,13 @@ LL | } = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:12:42 + --> $DIR/future_not_send.rs:11:42 | LL | pub async fn public_future(rc: Rc<[u8]>) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:13:5 + --> $DIR/future_not_send.rs:12:5 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` @@ -44,45 +44,45 @@ LL | } = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:20:63 + --> $DIR/future_not_send.rs:19:63 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` - --> $DIR/future_not_send.rs:20:26 + --> $DIR/future_not_send.rs:19:26 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> $DIR/future_not_send.rs:20:40 + --> $DIR/future_not_send.rs:19:40 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync` = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:24:43 + --> $DIR/future_not_send.rs:23:43 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` - --> $DIR/future_not_send.rs:24:29 + --> $DIR/future_not_send.rs:23:29 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:35:39 + --> $DIR/future_not_send.rs:34:39 | LL | async fn private_future(&self) -> usize { | ^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:36:9 + --> $DIR/future_not_send.rs:35:9 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` @@ -94,13 +94,13 @@ LL | } = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:40:39 + --> $DIR/future_not_send.rs:39:39 | LL | pub async fn public_future(&self) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:41:9 + --> $DIR/future_not_send.rs:40:9 | LL | pub async fn public_future(&self) { | ----- has type `&Dummy` which is not `Send` @@ -111,13 +111,13 @@ LL | } = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:50:37 + --> $DIR/future_not_send.rs:49:37 | LL | async fn generic_future<T>(t: T) -> T | ^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:55:5 + --> $DIR/future_not_send.rs:54:5 | LL | let rt = &t; | -- has type `&T` which is not `Send` @@ -129,13 +129,13 @@ LL | } = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:66:34 + --> $DIR/future_not_send.rs:65:34 | LL | async fn unclear_future<T>(t: T) {} | ^ future returned by `unclear_future` is not `Send` | note: captured value is not `Send` - --> $DIR/future_not_send.rs:66:28 + --> $DIR/future_not_send.rs:65:28 | LL | async fn unclear_future<T>(t: T) {} | ^ has type `T` which is not `Send` diff --git a/src/tools/clippy/tests/ui/if_not_else.rs b/src/tools/clippy/tests/ui/if_not_else.rs index dc3fb1ceac9..b7012b43d29 100644 --- a/src/tools/clippy/tests/ui/if_not_else.rs +++ b/src/tools/clippy/tests/ui/if_not_else.rs @@ -1,6 +1,9 @@ #![warn(clippy::all)] #![warn(clippy::if_not_else)] +fn foo() -> bool { + unimplemented!() +} fn bla() -> bool { unimplemented!() } @@ -16,4 +19,11 @@ fn main() { } else { println!("Bunny"); } + if !foo() { + println!("Foo"); + } else if !bla() { + println!("Bugs"); + } else { + println!("Bunny"); + } } diff --git a/src/tools/clippy/tests/ui/if_not_else.stderr b/src/tools/clippy/tests/ui/if_not_else.stderr index 53d1b86d02a..8c8cc44bb03 100644 --- a/src/tools/clippy/tests/ui/if_not_else.stderr +++ b/src/tools/clippy/tests/ui/if_not_else.stderr @@ -1,5 +1,5 @@ error: unnecessary boolean `not` operation - --> $DIR/if_not_else.rs:9:5 + --> $DIR/if_not_else.rs:12:5 | LL | / if !bla() { LL | | println!("Bugs"); @@ -12,7 +12,7 @@ LL | | } = help: remove the `!` and swap the blocks of the `if`/`else` error: unnecessary `!=` operation - --> $DIR/if_not_else.rs:14:5 + --> $DIR/if_not_else.rs:17:5 | LL | / if 4 != 5 { LL | | println!("Bugs"); diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs index aa69b097410..fd96ca3f466 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.rs +++ b/src/tools/clippy/tests/ui/implicit_hasher.rs @@ -1,4 +1,3 @@ -// edition:2018 // aux-build:implicit_hasher_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr index 3f5f56b923f..59b0fba2a4c 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.stderr +++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr @@ -1,11 +1,11 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:17:35 + --> $DIR/implicit_hasher.rs:16:35 | LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:3:9 + --> $DIR/implicit_hasher.rs:2:9 | LL | #![deny(clippy::implicit_hasher)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:26:36 + --> $DIR/implicit_hasher.rs:25:36 | LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) { | ^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:31:19 + --> $DIR/implicit_hasher.rs:30:19 | LL | impl Foo<i16> for HashMap<String, String> { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:48:32 + --> $DIR/implicit_hasher.rs:47:32 | LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> { | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:53:19 + --> $DIR/implicit_hasher.rs:52:19 | LL | impl Foo<i16> for HashSet<String> { | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:70:23 + --> $DIR/implicit_hasher.rs:69:23 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _s | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:70:53 + --> $DIR/implicit_hasher.rs:69:53 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:74:43 + --> $DIR/implicit_hasher.rs:73:43 | LL | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { | ^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:82:33 + --> $DIR/implicit_hasher.rs:81:33 | LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:82:63 + --> $DIR/implicit_hasher.rs:81:63 | LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:101:35 + --> $DIR/implicit_hasher.rs:100:35 | LL | pub async fn election_vote(_data: HashMap<i32, i32>) {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed index 7698b88a88c..a51f7bc6a29 100644 --- a/src/tools/clippy/tests/ui/implicit_return.fixed +++ b/src/tools/clippy/tests/ui/implicit_return.fixed @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::implicit_return)] diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs index 45bbc2ec670..03f8ec49d51 100644 --- a/src/tools/clippy/tests/ui/implicit_return.rs +++ b/src/tools/clippy/tests/ui/implicit_return.rs @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::implicit_return)] diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr index 5e078b15ce3..522bc3bf895 100644 --- a/src/tools/clippy/tests/ui/implicit_return.stderr +++ b/src/tools/clippy/tests/ui/implicit_return.stderr @@ -1,5 +1,5 @@ error: missing `return` statement - --> $DIR/implicit_return.rs:13:5 + --> $DIR/implicit_return.rs:12:5 | LL | true | ^^^^ help: add `return` as shown: `return true` @@ -7,85 +7,85 @@ LL | true = note: `-D clippy::implicit-return` implied by `-D warnings` error: missing `return` statement - --> $DIR/implicit_return.rs:17:15 + --> $DIR/implicit_return.rs:16:15 | LL | if true { true } else { false } | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:17:29 + --> $DIR/implicit_return.rs:16:29 | LL | if true { true } else { false } | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:23:17 + --> $DIR/implicit_return.rs:22:17 | LL | true => false, | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:24:20 + --> $DIR/implicit_return.rs:23:20 | LL | false => { true }, | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:37:9 + --> $DIR/implicit_return.rs:36:9 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:44:13 + --> $DIR/implicit_return.rs:43:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:52:13 + --> $DIR/implicit_return.rs:51:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:70:18 + --> $DIR/implicit_return.rs:69:18 | LL | let _ = || { true }; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:71:16 + --> $DIR/implicit_return.rs:70:16 | LL | let _ = || true; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:79:5 + --> $DIR/implicit_return.rs:78:5 | LL | format!("test {}", "test") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")` error: missing `return` statement - --> $DIR/implicit_return.rs:88:5 + --> $DIR/implicit_return.rs:87:5 | LL | m!(true, false) | ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)` error: missing `return` statement - --> $DIR/implicit_return.rs:94:13 + --> $DIR/implicit_return.rs:93:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:99:17 + --> $DIR/implicit_return.rs:98:17 | LL | break 'outer false; | ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:114:5 + --> $DIR/implicit_return.rs:113:5 | LL | / loop { LL | | m!(true); @@ -100,7 +100,7 @@ LL + } | error: missing `return` statement - --> $DIR/implicit_return.rs:128:5 + --> $DIR/implicit_return.rs:127:5 | LL | true | ^^^^ help: add `return` as shown: `return true` diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed index d1025743790..eb66d1afddc 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs index b095aa64a21..5caadc7c620 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr index ef308dedb16..c90189e964f 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:34:9 + --> $DIR/inconsistent_struct_constructor.rs:33:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -7,7 +7,7 @@ LL | Foo { y, x, z }; = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:56:9 + --> $DIR/inconsistent_struct_constructor.rs:55:9 | LL | / Foo { LL | | z, diff --git a/src/tools/clippy/tests/ui/issue-7447.stderr b/src/tools/clippy/tests/ui/issue-7447.stderr new file mode 100644 index 00000000000..463a48b24a3 --- /dev/null +++ b/src/tools/clippy/tests/ui/issue-7447.stderr @@ -0,0 +1,19 @@ +error: sub-expression diverges + --> $DIR/issue-7447.rs:23:15 + | +LL | byte_view(panic!()); + | ^^^^^^^^ + | + = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: sub-expression diverges + --> $DIR/issue-7447.rs:24:19 + | +LL | group_entries(panic!()); + | ^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/issue_4266.rs b/src/tools/clippy/tests/ui/issue_4266.rs index cc699b79e43..d9d48189bd7 100644 --- a/src/tools/clippy/tests/ui/issue_4266.rs +++ b/src/tools/clippy/tests/ui/issue_4266.rs @@ -1,4 +1,3 @@ -// edition:2018 #![allow(dead_code)] async fn sink1<'a>(_: &'a str) {} // lint diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr index 0426508e622..20419457b47 100644 --- a/src/tools/clippy/tests/ui/issue_4266.stderr +++ b/src/tools/clippy/tests/ui/issue_4266.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/issue_4266.rs:4:1 + --> $DIR/issue_4266.rs:3:1 | LL | async fn sink1<'a>(_: &'a str) {} // lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/issue_4266.rs:8:1 + --> $DIR/issue_4266.rs:7:1 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs index b9d66347c27..1e938e72b57 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty.rs +++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::len_without_is_empty)] #![allow(dead_code, unused)] diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.stderr b/src/tools/clippy/tests/ui/len_without_is_empty.stderr index 3282709bcd6..a1f48f7610b 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty.stderr +++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr @@ -1,5 +1,5 @@ error: struct `PubOne` has a public `len` method, but no `is_empty` method - --> $DIR/len_without_is_empty.rs:9:5 + --> $DIR/len_without_is_empty.rs:7:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pub fn len(&self) -> isize { = note: `-D clippy::len-without-is-empty` implied by `-D warnings` error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_without_is_empty.rs:57:1 + --> $DIR/len_without_is_empty.rs:55:1 | LL | / pub trait PubTraitsToo { LL | | fn len(&self) -> isize; @@ -15,45 +15,45 @@ LL | | } | |_^ error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method - --> $DIR/len_without_is_empty.rs:70:5 + --> $DIR/len_without_is_empty.rs:68:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:74:5 + --> $DIR/len_without_is_empty.rs:72:5 | LL | fn is_empty(&self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:82:5 + --> $DIR/len_without_is_empty.rs:80:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:86:5 + --> $DIR/len_without_is_empty.rs:84:5 | LL | pub fn is_empty(&self, x: u32) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:94:5 + --> $DIR/len_without_is_empty.rs:92:5 | LL | pub fn len(self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:98:5 + --> $DIR/len_without_is_empty.rs:96:5 | LL | pub fn is_empty(&self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(self) -> bool` error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_without_is_empty.rs:173:1 + --> $DIR/len_without_is_empty.rs:171:1 | LL | / pub trait DependsOnFoo: Foo { LL | | fn len(&mut self) -> usize; @@ -61,33 +61,33 @@ LL | | } | |_^ error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:218:5 + --> $DIR/len_without_is_empty.rs:216:5 | LL | pub fn len(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:223:5 + --> $DIR/len_without_is_empty.rs:221:5 | LL | pub fn is_empty(&self) -> Option<bool> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:230:5 + --> $DIR/len_without_is_empty.rs:228:5 | LL | pub fn len(&self) -> Result<usize, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:235:5 + --> $DIR/len_without_is_empty.rs:233:5 | LL | pub fn is_empty(&self) -> Option<bool> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` or `(&self) -> Result<bool> error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:230:5 + --> $DIR/len_without_is_empty.rs:228:5 | LL | pub fn len(&self) -> Result<usize, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | pub fn len(&self) -> Result<usize, ()> { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:242:5 + --> $DIR/len_without_is_empty.rs:240:5 | LL | pub fn len(&self) -> Result<usize, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | pub fn len(&self) -> Result<usize, ()> { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:246:5 + --> $DIR/len_without_is_empty.rs:244:5 | LL | pub fn is_empty(&self) -> Result<bool, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | pub fn is_empty(&self) -> Result<bool, ()> { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:253:5 + --> $DIR/len_without_is_empty.rs:251:5 | LL | pub fn len(&self) -> Result<usize, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/literals.rs b/src/tools/clippy/tests/ui/literals.rs index a72a74b9131..e60ce8492fc 100644 --- a/src/tools/clippy/tests/ui/literals.rs +++ b/src/tools/clippy/tests/ui/literals.rs @@ -2,7 +2,8 @@ #![warn(clippy::mixed_case_hex_literals)] #![warn(clippy::zero_prefixed_literal)] -#![allow(clippy::unseparated_literal_suffix)] +#![warn(clippy::unseparated_literal_suffix)] +#![warn(clippy::separated_literal_suffix)] #![allow(dead_code)] fn main() { diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr index 99542e20f78..365b2407473 100644 --- a/src/tools/clippy/tests/ui/literals.stderr +++ b/src/tools/clippy/tests/ui/literals.stderr @@ -1,25 +1,65 @@ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:12:15 + | +LL | let ok4 = 0xab_cd_i32; + | ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32` + | + = note: `-D clippy::separated-literal-suffix` implied by `-D warnings` + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:13:15 + | +LL | let ok5 = 0xAB_CD_u32; + | ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32` + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:14:15 + | +LL | let ok5 = 0xAB_CD_isize; + | ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:14:17 + --> $DIR/literals.rs:15:17 | LL | let fail1 = 0xabCD; | ^^^^^^ | = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:16:17 + | +LL | let fail2 = 0xabCD_u32; + | ^^^^^^^^^^ help: remove the underscore: `0xabCDu32` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:15:17 + --> $DIR/literals.rs:16:17 | LL | let fail2 = 0xabCD_u32; | ^^^^^^^^^^ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:17:17 + | +LL | let fail2 = 0xabCD_isize; + | ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:16:17 + --> $DIR/literals.rs:17:17 | LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ +error: integer type suffix should be separated by an underscore + --> $DIR/literals.rs:18:27 + | +LL | let fail_multi_zero = 000_123usize; + | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize` + | + = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` + error: this is a decimal constant - --> $DIR/literals.rs:17:27 + --> $DIR/literals.rs:18:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ @@ -34,8 +74,14 @@ help: if you mean to use an octal constant, use `0o` LL | let fail_multi_zero = 0o123usize; | ~~~~~~~~~~ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:21:16 + | +LL | let ok10 = 0_i64; + | ^^^^^ help: remove the underscore: `0i64` + error: this is a decimal constant - --> $DIR/literals.rs:21:17 + --> $DIR/literals.rs:22:17 | LL | let fail8 = 0123; | ^^^^ @@ -49,8 +95,14 @@ help: if you mean to use an octal constant, use `0o` LL | let fail8 = 0o123; | ~~~~~ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:31:16 + | +LL | let ok17 = 0x123_4567_8901_usize; + | ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize` + error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:33:18 + --> $DIR/literals.rs:34:18 | LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` @@ -58,19 +110,19 @@ LL | let fail19 = 12_3456_21; = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:34:18 + --> $DIR/literals.rs:35:18 | LL | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:35:18 + --> $DIR/literals.rs:36:18 | LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:37:18 + --> $DIR/literals.rs:38:18 | LL | let fail24 = 0xAB_ABC_AB; | ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB` @@ -78,10 +130,10 @@ LL | let fail24 = 0xAB_ABC_AB; = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:38:18 + --> $DIR/literals.rs:39:18 | LL | let fail25 = 0b01_100_101; | ^^^^^^^^^^^^ help: consider: `0b0110_0101` -error: aborting due to 10 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 70d49d9f2c4..9171558f3a2 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -1,4 +1,3 @@ -// compile-flags: --edition 2018 // aux-build:macro_rules.rs // aux-build:macro_use_helper.rs // aux-build:proc_macro_derive.rs diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index 68370023861..cd01fd43f6d 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -1,4 +1,3 @@ -// compile-flags: --edition 2018 // aux-build:macro_rules.rs // aux-build:macro_use_helper.rs // aux-build:proc_macro_derive.rs diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index 49314b7506d..f8c86c8d917 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -1,5 +1,5 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:19:5 + --> $DIR/macro_use_imports.rs:18:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` @@ -7,22 +7,22 @@ LL | #[macro_use] = note: `-D clippy::macro-use-imports` implied by `-D warnings` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:25:5 + --> $DIR/macro_use_imports.rs:20:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:21:5 + --> $DIR/macro_use_imports.rs:22:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:23:5 + --> $DIR/macro_use_imports.rs:24:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/if_then_panic.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed index 0998f8ffa9d..11fe06c5724 100644 --- a/src/tools/clippy/tests/ui/if_then_panic.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed @@ -1,5 +1,8 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 // run-rustfix -#![warn(clippy::if_then_panic)] +#![warn(clippy::manual_assert)] fn main() { let a = vec![1, 2, 3]; diff --git a/src/tools/clippy/tests/ui/if_then_panic.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr index 5bb62f87566..03c03472f90 100644 --- a/src/tools/clippy/tests/ui/if_then_panic.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr @@ -1,15 +1,15 @@ error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:19:5 + --> $DIR/manual_assert.rs:22:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` | - = note: `-D clippy::if-then-panic` implied by `-D warnings` + = note: `-D clippy::manual-assert` implied by `-D warnings` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:22:5 + --> $DIR/manual_assert.rs:25:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:39:5 + --> $DIR/manual_assert.rs:42:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:42:5 + --> $DIR/manual_assert.rs:45:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:45:5 + --> $DIR/manual_assert.rs:48:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:48:5 + --> $DIR/manual_assert.rs:51:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -49,7 +49,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:51:5 + --> $DIR/manual_assert.rs:54:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed new file mode 100644 index 00000000000..11fe06c5724 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed @@ -0,0 +1,43 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 +// run-rustfix +#![warn(clippy::manual_assert)] + +fn main() { + let a = vec![1, 2, 3]; + let c = Some(2); + if !a.is_empty() + && a.len() == 3 + && c != None + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + { + panic!("qaqaq{:?}", a); + } + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); + if a.len() == 3 { + println!("qwq"); + println!("qwq"); + println!("qwq"); + } + if let Some(b) = c { + panic!("orz {}", b); + } + if a.len() == 3 { + panic!("qaqaq"); + } else { + println!("qwq"); + } + let b = vec![1, 2, 3]; + assert!(!b.is_empty(), "panic1"); + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); +} diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr new file mode 100644 index 00000000000..03c03472f90 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr @@ -0,0 +1,60 @@ +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:22:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qaqaq{:?}", a); +LL | | } + | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | + = note: `-D clippy::manual-assert` implied by `-D warnings` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:25:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qwqwq"); +LL | | } + | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:42:5 + | +LL | / if b.is_empty() { +LL | | panic!("panic1"); +LL | | } + | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:45:5 + | +LL | / if b.is_empty() && a.is_empty() { +LL | | panic!("panic2"); +LL | | } + | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:48:5 + | +LL | / if a.is_empty() && !b.is_empty() { +LL | | panic!("panic3"); +LL | | } + | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:51:5 + | +LL | / if b.is_empty() || a.is_empty() { +LL | | panic!("panic4"); +LL | | } + | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:54:5 + | +LL | / if a.is_empty() || !b.is_empty() { +LL | | panic!("panic5"); +LL | | } + | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_assert.fixed b/src/tools/clippy/tests/ui/manual_assert.fixed new file mode 100644 index 00000000000..11fe06c5724 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_assert.fixed @@ -0,0 +1,43 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 +// run-rustfix +#![warn(clippy::manual_assert)] + +fn main() { + let a = vec![1, 2, 3]; + let c = Some(2); + if !a.is_empty() + && a.len() == 3 + && c != None + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + { + panic!("qaqaq{:?}", a); + } + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); + if a.len() == 3 { + println!("qwq"); + println!("qwq"); + println!("qwq"); + } + if let Some(b) = c { + panic!("orz {}", b); + } + if a.len() == 3 { + panic!("qaqaq"); + } else { + println!("qwq"); + } + let b = vec![1, 2, 3]; + assert!(!b.is_empty(), "panic1"); + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); +} diff --git a/src/tools/clippy/tests/ui/if_then_panic.rs b/src/tools/clippy/tests/ui/manual_assert.rs index 10433c8d54f..8713426fc88 100644 --- a/src/tools/clippy/tests/ui/if_then_panic.rs +++ b/src/tools/clippy/tests/ui/manual_assert.rs @@ -1,5 +1,8 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 // run-rustfix -#![warn(clippy::if_then_panic)] +#![warn(clippy::manual_assert)] fn main() { let a = vec![1, 2, 3]; diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed index 5184f6fdb88..136cc96be70 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.fixed +++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs index 68c0e591f0b..ddc453ffdb7 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.rs +++ b/src/tools/clippy/tests/ui/manual_async_fn.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index 51f1a52b6dd..7435f46074c 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -1,5 +1,5 @@ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:8:1 + --> $DIR/manual_async_fn.rs:7:1 | LL | fn fut() -> impl Future<Output = i32> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | fn fut() -> impl Future<Output = i32> { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:13:1 + --> $DIR/manual_async_fn.rs:12:1 | LL | fn fut2() ->impl Future<Output = i32> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | fn fut2() ->impl Future<Output = i32> { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:18:1 + --> $DIR/manual_async_fn.rs:17:1 | LL | fn fut3()-> impl Future<Output = i32> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn fut3()-> impl Future<Output = i32> { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:22:1 + --> $DIR/manual_async_fn.rs:21:1 | LL | fn empty_fut() -> impl Future<Output = ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | fn empty_fut() -> impl Future<Output = ()> {} | ~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:27:1 + --> $DIR/manual_async_fn.rs:26:1 | LL | fn empty_fut2() ->impl Future<Output = ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | fn empty_fut2() ->impl Future<Output = ()> {} | ~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:32:1 + --> $DIR/manual_async_fn.rs:31:1 | LL | fn empty_fut3()-> impl Future<Output = ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | fn empty_fut3()-> impl Future<Output = ()> {} | ~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:36:1 + --> $DIR/manual_async_fn.rs:35:1 | LL | fn core_fut() -> impl core::future::Future<Output = i32> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future<Output = i32> { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:58:5 + --> $DIR/manual_async_fn.rs:57:5 | LL | fn inh_fut() -> impl Future<Output = i32> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL + let c = 21; ... error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:93:1 + --> $DIR/manual_async_fn.rs:92:1 | LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:102:1 + --> $DIR/manual_async_fn.rs:101:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed index 40d01df6379..294d79abc04 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option.fixed @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::manual_map)] diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs index cfef0c5cc4e..d11bf5ecb82 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.rs +++ b/src/tools/clippy/tests/ui/manual_map_option.rs @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::manual_map)] diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr index cdc2c0e62a9..0036b8151de 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option.stderr @@ -1,5 +1,5 @@ error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:15:5 + --> $DIR/manual_map_option.rs:14:5 | LL | / match Some(0) { LL | | Some(_) => Some(2), @@ -10,7 +10,7 @@ LL | | }; = note: `-D clippy::manual-map` implied by `-D warnings` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:20:5 + --> $DIR/manual_map_option.rs:19:5 | LL | / match Some(0) { LL | | Some(x) => Some(x + 1), @@ -19,7 +19,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| x + 1)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:25:5 + --> $DIR/manual_map_option.rs:24:5 | LL | / match Some("") { LL | | Some(x) => Some(x.is_empty()), @@ -28,7 +28,7 @@ LL | | }; | |_____^ help: try this: `Some("").map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:30:5 + --> $DIR/manual_map_option.rs:29:5 | LL | / if let Some(x) = Some(0) { LL | | Some(!x) @@ -38,7 +38,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| !x)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:37:5 + --> $DIR/manual_map_option.rs:36:5 | LL | / match Some(0) { LL | | Some(x) => { Some(std::convert::identity(x)) } @@ -47,7 +47,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(std::convert::identity)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:42:5 + --> $DIR/manual_map_option.rs:41:5 | LL | / match Some(&String::new()) { LL | | Some(x) => Some(str::len(x)), @@ -56,7 +56,7 @@ LL | | }; | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:52:5 + --> $DIR/manual_map_option.rs:51:5 | LL | / match &Some([0, 1]) { LL | | Some(x) => Some(x[0]), @@ -65,7 +65,7 @@ LL | | }; | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:57:5 + --> $DIR/manual_map_option.rs:56:5 | LL | / match &Some(0) { LL | | &Some(x) => Some(x * 2), @@ -74,7 +74,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| x * 2)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:62:5 + --> $DIR/manual_map_option.rs:61:5 | LL | / match Some(String::new()) { LL | | Some(ref x) => Some(x.is_empty()), @@ -83,7 +83,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:67:5 + --> $DIR/manual_map_option.rs:66:5 | LL | / match &&Some(String::new()) { LL | | Some(x) => Some(x.len()), @@ -92,7 +92,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:72:5 + --> $DIR/manual_map_option.rs:71:5 | LL | / match &&Some(0) { LL | | &&Some(x) => Some(x + x), @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| x + x)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:85:9 + --> $DIR/manual_map_option.rs:84:9 | LL | / match &mut Some(String::new()) { LL | | Some(x) => Some(x.push_str("")), @@ -110,7 +110,7 @@ LL | | }; | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:91:5 + --> $DIR/manual_map_option.rs:90:5 | LL | / match &mut Some(String::new()) { LL | | Some(ref x) => Some(x.len()), @@ -119,7 +119,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:96:5 + --> $DIR/manual_map_option.rs:95:5 | LL | / match &mut &Some(String::new()) { LL | | Some(x) => Some(x.is_empty()), @@ -128,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:101:5 + --> $DIR/manual_map_option.rs:100:5 | LL | / match Some((0, 1, 2)) { LL | | Some((x, y, z)) => Some(x + y + z), @@ -137,7 +137,7 @@ LL | | }; | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:106:5 + --> $DIR/manual_map_option.rs:105:5 | LL | / match Some([1, 2, 3]) { LL | | Some([first, ..]) => Some(first), @@ -146,7 +146,7 @@ LL | | }; | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:111:5 + --> $DIR/manual_map_option.rs:110:5 | LL | / match &Some((String::new(), "test")) { LL | | Some((x, y)) => Some((y, x)), @@ -155,7 +155,7 @@ LL | | }; | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:169:5 + --> $DIR/manual_map_option.rs:168:5 | LL | / match Some(0) { LL | | Some(x) => Some(vec![x]), @@ -164,7 +164,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| vec![x])` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:174:5 + --> $DIR/manual_map_option.rs:173:5 | LL | / match option_env!("") { LL | | Some(x) => Some(String::from(x)), @@ -173,7 +173,7 @@ LL | | }; | |_____^ help: try this: `option_env!("").map(String::from)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:194:12 + --> $DIR/manual_map_option.rs:193:12 | LL | } else if let Some(x) = Some(0) { | ____________^ @@ -184,7 +184,7 @@ LL | | }; | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:202:12 + --> $DIR/manual_map_option.rs:201:12 | LL | } else if let Some(x) = Some(0) { | ____________^ diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs index ff91c4498ec..845986a4ead 100644 --- a/src/tools/clippy/tests/ui/match_overlapping_arm.rs +++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs @@ -100,6 +100,13 @@ fn overlapping() { _ => (), } + // Issue #7829 + match 0 { + -1..=1 => (), + -2..=2 => (), + _ => (), + } + if let None = Some(42) { // nothing } else if let None = Some(42) { diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs index 50246486bb6..7e3674ab8c9 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.rs +++ b/src/tools/clippy/tests/ui/match_ref_pats.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_ref_pats)] -#![allow(clippy::equatable_if_let)] +#![allow(clippy::equatable_if_let, clippy::enum_variant_names)] fn ref_pats() { { diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs index 208a4bba3d2..ac555c87d83 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs @@ -12,6 +12,49 @@ fn as_str_match() { } } +fn non_alphabetic() { + let var = "~!@#$%^&*()-_=+FOO"; + + match var.to_ascii_lowercase().as_str() { + "1234567890" => {}, + "~!@#$%^&*()-_=+foo" => {}, + "\n\r\t\x7F" => {}, + _ => {}, + } +} + +fn unicode_cased() { + let var = "ВОДЫ"; + + match var.to_lowercase().as_str() { + "水" => {}, + "νερό" => {}, + "воды" => {}, + "물" => {}, + _ => {}, + } +} + +fn titlecase() { + let var = "BarDz"; + + match var.to_lowercase().as_str() { + "foolj" => {}, + "bardz" => {}, + _ => {}, + } +} + +fn no_case_equivalent() { + let var = "barʁ"; + + match var.to_uppercase().as_str() { + "FOOɕ" => {}, + "BARʁ" => {}, + _ => {}, + } +} + fn addrof_unary_match() { let var = "BAR"; @@ -70,6 +113,49 @@ fn as_str_match_mismatch() { } } +fn non_alphabetic_mismatch() { + let var = "~!@#$%^&*()-_=+FOO"; + + match var.to_ascii_lowercase().as_str() { + "1234567890" => {}, + "~!@#$%^&*()-_=+Foo" => {}, + "\n\r\t\x7F" => {}, + _ => {}, + } +} + +fn unicode_cased_mismatch() { + let var = "ВОДЫ"; + + match var.to_lowercase().as_str() { + "水" => {}, + "νερό" => {}, + "Воды" => {}, + "물" => {}, + _ => {}, + } +} + +fn titlecase_mismatch() { + let var = "BarDz"; + + match var.to_lowercase().as_str() { + "foolj" => {}, + "barDz" => {}, + _ => {}, + } +} + +fn no_case_equivalent_mismatch() { + let var = "barʁ"; + + match var.to_uppercase().as_str() { + "FOOɕ" => {}, + "bARʁ" => {}, + _ => {}, + } +} + fn addrof_unary_match_mismatch() { let var = "BAR"; diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index fa023477a9c..92baa40ef28 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -1,5 +1,5 @@ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:68:9 + --> $DIR/match_str_case_mismatch.rs:111:9 | LL | "Bar" => {}, | ^^^^^ @@ -11,7 +11,51 @@ LL | "bar" => {}, | ~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:78:9 + --> $DIR/match_str_case_mismatch.rs:121:9 + | +LL | "~!@#$%^&*()-_=+Foo" => {}, + | ^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the case of this arm to respect `to_ascii_lowercase` + | +LL | "~!@#$%^&*()-_=+foo" => {}, + | ~~~~~~~~~~~~~~~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:133:9 + | +LL | "Воды" => {}, + | ^^^^^^ + | +help: consider changing the case of this arm to respect `to_lowercase` + | +LL | "воды" => {}, + | ~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:144:9 + | +LL | "barDz" => {}, + | ^^^^^^ + | +help: consider changing the case of this arm to respect `to_lowercase` + | +LL | "bardz" => {}, + | ~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:154:9 + | +LL | "bARʁ" => {}, + | ^^^^^^ + | +help: consider changing the case of this arm to respect `to_uppercase` + | +LL | "BARʁ" => {}, + | ~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:164:9 | LL | "Bar" => {}, | ^^^^^ @@ -22,7 +66,7 @@ LL | "bar" => {}, | ~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:93:9 + --> $DIR/match_str_case_mismatch.rs:179:9 | LL | "bAR" => {}, | ^^^^^ @@ -32,5 +76,5 @@ help: consider changing the case of this arm to respect `to_ascii_uppercase` LL | "BAR" => {}, | ~~~~~ -error: aborting due to 3 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr index 6a2a02987de..2a4012039ba 100644 --- a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr +++ b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr @@ -1,5 +1,5 @@ error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:11:9 + --> $DIR/match_wild_err_arm.rs:14:9 | LL | Err(_) => panic!("err"), | ^^^^^^ @@ -8,7 +8,7 @@ LL | Err(_) => panic!("err"), = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:17:9 + --> $DIR/match_wild_err_arm.rs:20:9 | LL | Err(_) => panic!(), | ^^^^^^ @@ -16,7 +16,7 @@ LL | Err(_) => panic!(), = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:23:9 + --> $DIR/match_wild_err_arm.rs:26:9 | LL | Err(_) => { | ^^^^^^ @@ -24,7 +24,7 @@ LL | Err(_) => { = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_e)` matches all errors - --> $DIR/match_wild_err_arm.rs:31:9 + --> $DIR/match_wild_err_arm.rs:34:9 | LL | Err(_e) => panic!(), | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr new file mode 100644 index 00000000000..2a4012039ba --- /dev/null +++ b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr @@ -0,0 +1,35 @@ +error: `Err(_)` matches all errors + --> $DIR/match_wild_err_arm.rs:14:9 + | +LL | Err(_) => panic!("err"), + | ^^^^^^ + | + = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: `Err(_)` matches all errors + --> $DIR/match_wild_err_arm.rs:20:9 + | +LL | Err(_) => panic!(), + | ^^^^^^ + | + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: `Err(_)` matches all errors + --> $DIR/match_wild_err_arm.rs:26:9 + | +LL | Err(_) => { + | ^^^^^^ + | + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: `Err(_e)` matches all errors + --> $DIR/match_wild_err_arm.rs:34:9 + | +LL | Err(_e) => panic!(), + | ^^^^^^^ + | + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.rs b/src/tools/clippy/tests/ui/match_wild_err_arm.rs index 823be65efe0..0a86144b95d 100644 --- a/src/tools/clippy/tests/ui/match_wild_err_arm.rs +++ b/src/tools/clippy/tests/ui/match_wild_err_arm.rs @@ -1,3 +1,6 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 #![feature(exclusive_range_pattern)] #![allow(clippy::match_same_arms)] #![warn(clippy::match_wild_err_arm)] diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index c441b35b992..977ce54327b 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -1,5 +1,4 @@ // aux-build:option_helpers.rs -// edition:2018 #![warn(clippy::all, clippy::pedantic)] #![allow( diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr index 4643e09e270..b63672dd6fd 100644 --- a/src/tools/clippy/tests/ui/methods.stderr +++ b/src/tools/clippy/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:105:5 + --> $DIR/methods.rs:104:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:126:13 + --> $DIR/methods.rs:125:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing-doc.rs index a9bf7140a1e..148531c285d 100644 --- a/src/tools/clippy/tests/ui/missing-doc.rs +++ b/src/tools/clippy/tests/ui/missing-doc.rs @@ -3,7 +3,6 @@ // injected intrinsics by the compiler. #![allow(dead_code)] #![feature(global_asm)] - //! Some garbage docs for the crate here #![doc = "More garbage"] @@ -90,10 +89,10 @@ mod internal_impl { } /// dox pub mod public_interface { - pub use internal_impl::documented as foo; - pub use internal_impl::globbed::*; - pub use internal_impl::undocumented1 as bar; - pub use internal_impl::{documented, undocumented2}; + pub use crate::internal_impl::documented as foo; + pub use crate::internal_impl::globbed::*; + pub use crate::internal_impl::undocumented1 as bar; + pub use crate::internal_impl::{documented, undocumented2}; } fn main() {} diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing-doc.stderr index a876dc078eb..7a3a448c9d6 100644 --- a/src/tools/clippy/tests/ui/missing-doc.stderr +++ b/src/tools/clippy/tests/ui/missing-doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:10:1 + --> $DIR/missing-doc.rs:9:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | type Typedef = String; = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:11:1 + --> $DIR/missing-doc.rs:10:1 | LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:13:1 + --> $DIR/missing-doc.rs:12:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:14:1 + --> $DIR/missing-doc.rs:13:1 | LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:18:1 + --> $DIR/missing-doc.rs:17:1 | LL | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:19:1 + --> $DIR/missing-doc.rs:18:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:33:1 + --> $DIR/missing-doc.rs:32:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -46,31 +46,31 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:34:5 + --> $DIR/missing-doc.rs:33:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:12 + --> $DIR/missing-doc.rs:33:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:22 + --> $DIR/missing-doc.rs:33:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:35:5 + --> $DIR/missing-doc.rs:34:5 | LL | BarB, | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:38:1 + --> $DIR/missing-doc.rs:37:1 | LL | / pub enum PubBaz { LL | | PubBazA { a: isize }, @@ -78,43 +78,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:39:5 + --> $DIR/missing-doc.rs:38:5 | LL | PubBazA { a: isize }, | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:39:15 + --> $DIR/missing-doc.rs:38:15 | LL | PubBazA { a: isize }, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:59:1 + --> $DIR/missing-doc.rs:58:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:66:1 + --> $DIR/missing-doc.rs:65:1 | LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:68:1 + --> $DIR/missing-doc.rs:67:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:75:1 + --> $DIR/missing-doc.rs:74:1 | LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:77:1 + --> $DIR/missing-doc.rs:76:1 | LL | / mod internal_impl { LL | | /// dox @@ -126,31 +126,31 @@ LL | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:80:5 + --> $DIR/missing-doc.rs:79:5 | LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:81:5 + --> $DIR/missing-doc.rs:80:5 | LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:82:5 + --> $DIR/missing-doc.rs:81:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:87:9 + --> $DIR/missing-doc.rs:86:9 | LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:88:9 + --> $DIR/missing-doc.rs:87:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs index 2e1379a58a6..7dc44529206 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.rs +++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs @@ -1,6 +1,5 @@ #![warn(clippy::missing_panics_doc)] #![allow(clippy::option_map_unit_fn)] - fn main() {} /// This needs to be documented diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr index b863063b626..60282939ef0 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.stderr +++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr @@ -1,5 +1,5 @@ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:7:1 + --> $DIR/missing_panics_doc.rs:6:1 | LL | / pub fn unwrap() { LL | | let result = Err("Hi"); @@ -9,13 +9,13 @@ LL | | } | = note: `-D clippy::missing-panics-doc` implied by `-D warnings` note: first possible panic found here - --> $DIR/missing_panics_doc.rs:9:5 + --> $DIR/missing_panics_doc.rs:8:5 | LL | result.unwrap() | ^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:13:1 + --> $DIR/missing_panics_doc.rs:12:1 | LL | / pub fn panic() { LL | | panic!("This function panics") @@ -23,14 +23,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:14:5 + --> $DIR/missing_panics_doc.rs:13:5 | LL | panic!("This function panics") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:18:1 + --> $DIR/missing_panics_doc.rs:17:1 | LL | / pub fn todo() { LL | | todo!() @@ -38,14 +38,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:19:5 + --> $DIR/missing_panics_doc.rs:18:5 | LL | todo!() | ^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:23:1 + --> $DIR/missing_panics_doc.rs:22:1 | LL | / pub fn inner_body(opt: Option<u32>) { LL | | opt.map(|x| { @@ -57,14 +57,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:26:13 + --> $DIR/missing_panics_doc.rs:25:13 | LL | panic!() | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:32:1 + --> $DIR/missing_panics_doc.rs:31:1 | LL | / pub fn unreachable_and_panic() { LL | | if true { unreachable!() } else { panic!() } @@ -72,14 +72,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:33:39 + --> $DIR/missing_panics_doc.rs:32:39 | LL | if true { unreachable!() } else { panic!() } | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:37:1 + --> $DIR/missing_panics_doc.rs:36:1 | LL | / pub fn assert_eq() { LL | | let x = 0; @@ -88,14 +88,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:39:5 + --> $DIR/missing_panics_doc.rs:38:5 | LL | assert_eq!(x, 0); | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:43:1 + --> $DIR/missing_panics_doc.rs:42:1 | LL | / pub fn assert_ne() { LL | | let x = 0; @@ -104,7 +104,7 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:45:5 + --> $DIR/missing_panics_doc.rs:44:5 | LL | assert_ne!(x, 0); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs index 7a8137778b4..04b6283da3c 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.rs +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs @@ -1,4 +1,3 @@ -// edition:2018 // FIXME: run-rustfix waiting on multi-span suggestions #![warn(clippy::needless_borrow)] diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr index 365ecd68d8f..db3b52b8850 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr @@ -1,5 +1,5 @@ error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:60:14 + --> $DIR/needless_borrow_pat.rs:59:14 | LL | Some(ref x) => x, | ^^^^^ help: try this: `x` @@ -7,7 +7,7 @@ LL | Some(ref x) => x, = note: `-D clippy::needless-borrow` implied by `-D warnings` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:66:14 + --> $DIR/needless_borrow_pat.rs:65:14 | LL | Some(ref x) => *x, | ^^^^^ @@ -18,7 +18,7 @@ LL | Some(x) => x, | ~ ~ error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:72:14 + --> $DIR/needless_borrow_pat.rs:71:14 | LL | Some(ref x) => { | ^^^^^ @@ -31,19 +31,19 @@ LL ~ f1(x); | error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:82:14 + --> $DIR/needless_borrow_pat.rs:81:14 | LL | Some(ref x) => m1!(x), | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:87:15 + --> $DIR/needless_borrow_pat.rs:86:15 | LL | let _ = |&ref x: &&String| { | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:92:10 + --> $DIR/needless_borrow_pat.rs:91:10 | LL | let (ref y,) = (&x,); | ^^^^^ @@ -55,13 +55,13 @@ LL ~ let _: &String = y; | error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:102:14 + --> $DIR/needless_borrow_pat.rs:101:14 | LL | Some(ref x) => x.0, | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:112:14 + --> $DIR/needless_borrow_pat.rs:111:14 | LL | E::A(ref x) | E::B(ref x) => *x, | ^^^^^ ^^^^^ @@ -72,13 +72,13 @@ LL | E::A(x) | E::B(x) => x, | ~ ~ ~ error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:118:21 + --> $DIR/needless_borrow_pat.rs:117:21 | LL | if let Some(ref x) = Some(&String::new()); | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:126:12 + --> $DIR/needless_borrow_pat.rs:125:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -91,13 +91,13 @@ LL ~ x | error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:133:11 + --> $DIR/needless_borrow_pat.rs:132:11 | LL | fn f(&ref x: &&String) { | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:141:11 + --> $DIR/needless_borrow_pat.rs:140:11 | LL | fn f(&ref x: &&String) { | ^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 1d77382bf2c..b07c4a23810 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -27,6 +27,11 @@ fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } +// No error; multiple input refs +async fn func<'a>(args: &[&'a str]) -> Option<&'a str> { + args.get(0).cloned() +} + // No error; static involved. fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index 33a6de1618d..4114e6f1832 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -19,133 +19,133 @@ LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:45:1 + --> $DIR/needless_lifetimes.rs:50:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:50:1 + --> $DIR/needless_lifetimes.rs:55:1 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:62:1 + --> $DIR/needless_lifetimes.rs:67:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:86:1 + --> $DIR/needless_lifetimes.rs:91:1 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:116:5 + --> $DIR/needless_lifetimes.rs:121:5 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:125:5 + --> $DIR/needless_lifetimes.rs:130:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:144:1 + --> $DIR/needless_lifetimes.rs:149:1 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:174:1 + --> $DIR/needless_lifetimes.rs:179:1 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:180:1 + --> $DIR/needless_lifetimes.rs:185:1 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:199:1 + --> $DIR/needless_lifetimes.rs:204:1 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:207:1 + --> $DIR/needless_lifetimes.rs:212:1 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:243:1 + --> $DIR/needless_lifetimes.rs:248:1 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:250:9 + --> $DIR/needless_lifetimes.rs:255:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:254:9 + --> $DIR/needless_lifetimes.rs:259:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:267:9 + --> $DIR/needless_lifetimes.rs:272:9 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:296:5 + --> $DIR/needless_lifetimes.rs:301:5 | LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:299:5 + --> $DIR/needless_lifetimes.rs:304:5 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:308:5 + --> $DIR/needless_lifetimes.rs:313:5 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:320:5 + --> $DIR/needless_lifetimes.rs:325:5 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:335:5 + --> $DIR/needless_lifetimes.rs:340:5 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:348:5 + --> $DIR/needless_lifetimes.rs:353:5 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:351:5 + --> $DIR/needless_lifetimes.rs:356:5 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index 9c999e12b4c..812ce7163cd 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(let_else)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index da7dcf4f0a9..c42567b517c 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(let_else)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 2e802cff1e6..74dda971fda 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:25:5 + --> $DIR/needless_return.rs:24:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` @@ -7,187 +7,187 @@ LL | return true; = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded `return` statement - --> $DIR/needless_return.rs:29:5 + --> $DIR/needless_return.rs:28:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:34:9 + --> $DIR/needless_return.rs:33:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:36:9 + --> $DIR/needless_return.rs:35:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:42:17 + --> $DIR/needless_return.rs:41:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:44:13 + --> $DIR/needless_return.rs:43:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:51:9 + --> $DIR/needless_return.rs:50:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:53:16 + --> $DIR/needless_return.rs:52:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:61:5 + --> $DIR/needless_return.rs:60:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:66:9 + --> $DIR/needless_return.rs:65:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:68:9 + --> $DIR/needless_return.rs:67:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:75:14 + --> $DIR/needless_return.rs:74:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:90:9 + --> $DIR/needless_return.rs:89:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:92:9 + --> $DIR/needless_return.rs:91:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:113:32 + --> $DIR/needless_return.rs:112:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:118:13 + --> $DIR/needless_return.rs:117:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:120:20 + --> $DIR/needless_return.rs:119:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:126:32 + --> $DIR/needless_return.rs:125:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:135:5 + --> $DIR/needless_return.rs:134:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:139:5 + --> $DIR/needless_return.rs:138:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:144:9 + --> $DIR/needless_return.rs:143:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:146:9 + --> $DIR/needless_return.rs:145:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:152:17 + --> $DIR/needless_return.rs:151:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:154:13 + --> $DIR/needless_return.rs:153:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:161:9 + --> $DIR/needless_return.rs:160:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:163:16 + --> $DIR/needless_return.rs:162:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:171:5 + --> $DIR/needless_return.rs:170:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:176:9 + --> $DIR/needless_return.rs:175:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:178:9 + --> $DIR/needless_return.rs:177:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:185:14 + --> $DIR/needless_return.rs:184:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:200:9 + --> $DIR/needless_return.rs:199:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:202:9 + --> $DIR/needless_return.rs:201:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` diff --git a/src/tools/clippy/tests/ui/non_expressive_names.rs b/src/tools/clippy/tests/ui/non_expressive_names.rs index 58415b4aede..961f6f409dd 100644 --- a/src/tools/clippy/tests/ui/non_expressive_names.rs +++ b/src/tools/clippy/tests/ui/non_expressive_names.rs @@ -15,8 +15,8 @@ struct InstSplit { impl MaybeInst { fn fill(&mut self) { let filled = match *self { - MaybeInst::Split1(goto1) => panic!(1), - MaybeInst::Split2(goto2) => panic!(2), + MaybeInst::Split1(goto1) => panic!("1"), + MaybeInst::Split2(goto2) => panic!("2"), _ => unimplemented!(), }; unimplemented!() diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed index 4077f1920a3..9cb6a9d1ecc 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)] diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs index 2f414e129d5..b3ba5eb870a 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)] diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr index 803d941c36d..685bb48ea37 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:7:5 + --> $DIR/option_if_let_else.rs:6:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,19 +11,19 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:25:13 + --> $DIR/option_if_let_else.rs:24:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:26:13 + --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:27:13 + --> $DIR/option_if_let_else.rs:26:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -43,13 +43,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:33:13 + --> $DIR/option_if_let_else.rs:32:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:34:13 + --> $DIR/option_if_let_else.rs:33:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -69,7 +69,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:40:13 + --> $DIR/option_if_let_else.rs:39:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -89,7 +89,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:49:5 + --> $DIR/option_if_let_else.rs:48:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -108,7 +108,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:62:13 + --> $DIR/option_if_let_else.rs:61:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -120,7 +120,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:71:13 + --> $DIR/option_if_let_else.rs:70:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -143,13 +143,13 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:100:13 + --> $DIR/option_if_let_else.rs:99:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:109:13 + --> $DIR/option_if_let_else.rs:108:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -171,13 +171,13 @@ LL ~ }); | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:137:13 + --> $DIR/option_if_let_else.rs:136:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:141:13 + --> $DIR/option_if_let_else.rs:140:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.rs b/src/tools/clippy/tests/ui/panic_in_result_fn.rs index 3d3c19a1be5..e75eb1b6ead 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.rs @@ -1,6 +1,5 @@ #![warn(clippy::panic_in_result_fn)] #![allow(clippy::unnecessary_wraps)] - struct A; impl A { diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr index f56c2d03c66..78d09b8b210 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr @@ -1,5 +1,5 @@ error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:7:5 + --> $DIR/panic_in_result_fn.rs:6:5 | LL | / fn result_with_panic() -> Result<bool, String> // should emit lint LL | | { @@ -10,14 +10,14 @@ LL | | } = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:9:9 + --> $DIR/panic_in_result_fn.rs:8:9 | LL | panic!("error"); | ^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:12:5 + --> $DIR/panic_in_result_fn.rs:11:5 | LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint LL | | { @@ -27,14 +27,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:14:9 + --> $DIR/panic_in_result_fn.rs:13:9 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:17:5 + --> $DIR/panic_in_result_fn.rs:16:5 | LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint LL | | { @@ -44,14 +44,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:19:9 + --> $DIR/panic_in_result_fn.rs:18:9 | LL | unreachable!(); | ^^^^^^^^^^^^^^ = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:22:5 + --> $DIR/panic_in_result_fn.rs:21:5 | LL | / fn result_with_todo() -> Result<bool, String> // should emit lint LL | | { @@ -61,14 +61,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:24:9 + --> $DIR/panic_in_result_fn.rs:23:9 | LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:53:1 + --> $DIR/panic_in_result_fn.rs:52:1 | LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint LL | | { @@ -78,14 +78,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:55:5 + --> $DIR/panic_in_result_fn.rs:54:5 | LL | panic!("error"); | ^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:68:1 + --> $DIR/panic_in_result_fn.rs:67:1 | LL | / fn main() -> Result<(), String> { LL | | todo!("finish main method"); @@ -95,7 +95,7 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:69:5 + --> $DIR/panic_in_result_fn.rs:68:5 | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 99e6d2aad8d..67bfef06a05 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -1,9 +1,4 @@ -#![allow( - unused, - clippy::many_single_char_names, - clippy::redundant_clone, - clippy::if_then_panic -)] +#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] #![warn(clippy::ptr_arg)] use std::borrow::Cow; @@ -160,3 +155,7 @@ mod issue6509 { let _ = str.clone().clone(); } } + +// No error for types behind an alias (#7699) +type A = Vec<u8>; +fn aliased(a: &A) {} diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 42183447ead..64594eb870c 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:12:14 + --> $DIR/ptr_arg.rs:7:14 | LL | fn do_vec(x: &Vec<i64>) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -7,25 +7,25 @@ LL | fn do_vec(x: &Vec<i64>) { = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:21:14 + --> $DIR/ptr_arg.rs:16:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:30:15 + --> $DIR/ptr_arg.rs:25:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:43:18 + --> $DIR/ptr_arg.rs:38:18 | LL | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:56:14 + --> $DIR/ptr_arg.rs:51:14 | LL | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ @@ -44,7 +44,7 @@ LL | x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:65:18 + --> $DIR/ptr_arg.rs:60:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -67,7 +67,7 @@ LL | x.to_string() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:73:19 + --> $DIR/ptr_arg.rs:68:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -90,7 +90,7 @@ LL | x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:81:44 + --> $DIR/ptr_arg.rs:76:44 | LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ @@ -109,13 +109,13 @@ LL | let c = y; | ~ error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:95:25 + --> $DIR/ptr_arg.rs:90:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:148:21 + --> $DIR/ptr_arg.rs:143:21 | LL | fn foo_vec(vec: &Vec<u8>) { | ^^^^^^^^ @@ -134,7 +134,7 @@ LL | let _ = vec.to_owned().clone(); | ~~~~~~~~~~~~~~ error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:153:23 + --> $DIR/ptr_arg.rs:148:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -153,7 +153,7 @@ LL | let _ = path.to_path_buf().clone(); | ~~~~~~~~~~~~~~~~~~ error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:158:21 + --> $DIR/ptr_arg.rs:153:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index ccb2e5a302e..e93469e5f55 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -104,7 +104,11 @@ fn func() -> Option<i32> { Some(0) } -fn result_func(x: Result<i32, &str>) -> Result<i32, &str> { +fn func_returning_result() -> Result<i32, i32> { + Ok(1) +} + +fn result_func(x: Result<i32, i32>) -> Result<i32, i32> { let _ = x?; x?; @@ -113,9 +117,22 @@ fn result_func(x: Result<i32, &str>) -> Result<i32, &str> { let y = if let Ok(x) = x { x } else { - return Err("some error"); + return Err(0); + }; + + // issue #7859 + // no warning + let _ = if let Ok(x) = func_returning_result() { + x + } else { + return Err(0); }; + // no warning + if func_returning_result().is_err() { + return func_returning_result(); + } + Ok(y) } diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index ca3722371f5..dd179e9bee8 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -134,7 +134,11 @@ fn func() -> Option<i32> { Some(0) } -fn result_func(x: Result<i32, &str>) -> Result<i32, &str> { +fn func_returning_result() -> Result<i32, i32> { + Ok(1) +} + +fn result_func(x: Result<i32, i32>) -> Result<i32, i32> { let _ = if let Ok(x) = x { x } else { return x }; if x.is_err() { @@ -145,9 +149,22 @@ fn result_func(x: Result<i32, &str>) -> Result<i32, &str> { let y = if let Ok(x) = x { x } else { - return Err("some error"); + return Err(0); + }; + + // issue #7859 + // no warning + let _ = if let Ok(x) = func_returning_result() { + x + } else { + return Err(0); }; + // no warning + if func_returning_result().is_err() { + return func_returning_result(); + } + Ok(y) } diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 161588cb73c..8d782b71dd6 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -101,13 +101,13 @@ LL | | } | |_____^ help: replace it with: `f()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:138:13 + --> $DIR/question_mark.rs:142:13 | LL | let _ = if let Ok(x) = x { x } else { return x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:140:5 + --> $DIR/question_mark.rs:144:5 | LL | / if x.is_err() { LL | | return x; diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index 2d711082746..16b40dcd902 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -196,7 +196,7 @@ fn clone_then_move_cloned() { fn foo<F: Fn()>(_: &Alpha, _: F) {} let x = Alpha; // ok, data is moved while the clone is in use. - foo(&x.clone(), move || { + foo(&x, move || { let _ = x; }); diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index fbc90493ae9..9f59017b261 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -167,5 +167,17 @@ note: cloned value is neither consumed nor mutated LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ -error: aborting due to 14 previous errors +error: redundant clone + --> $DIR/redundant_clone.rs:199:11 + | +LL | foo(&x.clone(), move || { + | ^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:199:10 + | +LL | foo(&x.clone(), move || { + | ^ + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs index cd6db8ddc88..fe742a4c2f4 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -1,4 +1,3 @@ -// edition:2018 // FIXME: run-rustfix waiting on multi-span suggestions #![warn(clippy::ref_binding_to_reference)] diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr index eb36cd516a2..c5856e15fa9 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr @@ -1,5 +1,5 @@ error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:31:14 + --> $DIR/ref_binding_to_reference.rs:30:14 | LL | Some(ref x) => x, | ^^^^^ @@ -11,7 +11,7 @@ LL | Some(x) => &x, | ~ ~~ error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:37:14 + --> $DIR/ref_binding_to_reference.rs:36:14 | LL | Some(ref x) => { | ^^^^^ @@ -25,7 +25,7 @@ LL ~ &x | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:47:14 + --> $DIR/ref_binding_to_reference.rs:46:14 | LL | Some(ref x) => m2!(x), | ^^^^^ @@ -36,7 +36,7 @@ LL | Some(x) => m2!(&x), | ~ ~~ error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:52:15 + --> $DIR/ref_binding_to_reference.rs:51:15 | LL | let _ = |&ref x: &&String| { | ^^^^^ @@ -48,7 +48,7 @@ LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:58:12 + --> $DIR/ref_binding_to_reference.rs:57:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -61,7 +61,7 @@ LL ~ x | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:65:11 + --> $DIR/ref_binding_to_reference.rs:64:11 | LL | fn f(&ref x: &&String) { | ^^^^^ @@ -73,7 +73,7 @@ LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:73:11 + --> $DIR/ref_binding_to_reference.rs:72:11 | LL | fn f(&ref x: &&String) { | ^^^^^ diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index a66c2e587c8..cc295b509bc 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -6,15 +6,58 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::new_without_default)] #![allow(clippy::redundant_static_lifetimes)] +#![allow(clippy::bind_instead_of_map)] +#![allow(clippy::box_collection)] +#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::map_unwrap_or)] +#![allow(clippy::unwrap_used)] +#![allow(clippy::expect_used)] +#![allow(clippy::for_loops_over_fallibles)] +#![allow(clippy::useless_conversion)] +#![allow(clippy::invisible_characters)] +#![allow(clippy::single_char_add_str)] +#![allow(clippy::match_result_ok)] +// uplifted lints +#![allow(invalid_value)] +#![allow(array_into_iter)] +#![allow(unused_labels)] +#![allow(drop_bounds)] +#![allow(temporary_cstring_as_ptr)] +#![allow(non_fmt_panics)] +#![allow(unknown_lints)] +#![allow(invalid_atomic_ordering)] +#![allow(enum_intrinsics_non_enums)] // warn for the old lint name here, to test if the renaming worked +#![warn(clippy::module_name_repetitions)] +#![warn(clippy::new_without_default)] +#![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] +#![warn(clippy::bind_instead_of_map)] +#![warn(clippy::box_collection)] +#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::map_unwrap_or)] +#![warn(clippy::map_unwrap_or)] +#![warn(clippy::map_unwrap_or)] +#![warn(clippy::unwrap_used)] +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] +#![warn(clippy::expect_used)] +#![warn(clippy::for_loops_over_fallibles)] +#![warn(clippy::for_loops_over_fallibles)] +#![warn(clippy::useless_conversion)] +#![warn(clippy::invisible_characters)] +#![warn(clippy::single_char_add_str)] +#![warn(clippy::match_result_ok)] +// uplifted lints +#![warn(invalid_value)] +#![warn(array_into_iter)] +#![warn(unused_labels)] +#![warn(drop_bounds)] +#![warn(temporary_cstring_as_ptr)] +#![warn(non_fmt_panics)] +#![warn(unknown_lints)] +#![warn(invalid_atomic_ordering)] #![warn(enum_intrinsics_non_enums)] -#[warn(clippy::module_name_repetitions)] fn main() {} - -#[warn(clippy::new_without_default)] -struct Foo; - -#[warn(clippy::redundant_static_lifetimes)] -fn foo() {} diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index fa81201a2da..377075c0246 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -6,15 +6,58 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::new_without_default)] #![allow(clippy::redundant_static_lifetimes)] +#![allow(clippy::bind_instead_of_map)] +#![allow(clippy::box_collection)] +#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::map_unwrap_or)] +#![allow(clippy::unwrap_used)] +#![allow(clippy::expect_used)] +#![allow(clippy::for_loops_over_fallibles)] +#![allow(clippy::useless_conversion)] +#![allow(clippy::invisible_characters)] +#![allow(clippy::single_char_add_str)] +#![allow(clippy::match_result_ok)] +// uplifted lints +#![allow(invalid_value)] +#![allow(array_into_iter)] +#![allow(unused_labels)] +#![allow(drop_bounds)] +#![allow(temporary_cstring_as_ptr)] +#![allow(non_fmt_panics)] +#![allow(unknown_lints)] +#![allow(invalid_atomic_ordering)] +#![allow(enum_intrinsics_non_enums)] // warn for the old lint name here, to test if the renaming worked +#![warn(clippy::stutter)] +#![warn(clippy::new_without_default_derive)] +#![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] +#![warn(clippy::option_and_then_some)] +#![warn(clippy::box_vec)] +#![warn(clippy::block_in_if_condition_expr)] +#![warn(clippy::block_in_if_condition_stmt)] +#![warn(clippy::option_map_unwrap_or)] +#![warn(clippy::option_map_unwrap_or_else)] +#![warn(clippy::result_map_unwrap_or_else)] +#![warn(clippy::option_unwrap_used)] +#![warn(clippy::result_unwrap_used)] +#![warn(clippy::option_expect_used)] +#![warn(clippy::result_expect_used)] +#![warn(clippy::for_loop_over_option)] +#![warn(clippy::for_loop_over_result)] +#![warn(clippy::identity_conversion)] +#![warn(clippy::zero_width_space)] +#![warn(clippy::single_char_push_str)] +#![warn(clippy::if_let_some_result)] +// uplifted lints +#![warn(clippy::invalid_ref)] +#![warn(clippy::into_iter_on_array)] +#![warn(clippy::unused_label)] +#![warn(clippy::drop_bounds)] +#![warn(clippy::temporary_cstring_as_ptr)] +#![warn(clippy::panic_params)] +#![warn(clippy::unknown_clippy_lints)] +#![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::mem_discriminant_non_enum)] -#[warn(clippy::stutter)] fn main() {} - -#[warn(clippy::new_without_default_derive)] -struct Foo; - -#[warn(clippy::const_static_lifetime)] -fn foo() {} diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 05c7854074c..d720f10d117 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,34 +1,184 @@ +error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` + --> $DIR/rename.rs:31:9 + | +LL | #![warn(clippy::stutter)] + | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` + +error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` + --> $DIR/rename.rs:32:9 + | +LL | #![warn(clippy::new_without_default_derive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` + +error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` + --> $DIR/rename.rs:33:9 + | +LL | #![warn(clippy::const_static_lifetime)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` + error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:10:9 + --> $DIR/rename.rs:34:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` + +error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` + --> $DIR/rename.rs:35:9 | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` +LL | #![warn(clippy::option_and_then_some)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` -error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:11:9 +error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` + --> $DIR/rename.rs:36:9 | -LL | #![warn(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` +LL | #![warn(clippy::box_vec)] + | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` -error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:13:8 +error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:37:9 | -LL | #[warn(clippy::stutter)] - | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` +LL | #![warn(clippy::block_in_if_condition_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` -error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:16:8 +error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:38:9 | -LL | #[warn(clippy::new_without_default_derive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` +LL | #![warn(clippy::block_in_if_condition_stmt)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` -error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:19:8 +error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` + --> $DIR/rename.rs:39:9 + | +LL | #![warn(clippy::option_map_unwrap_or)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` + +error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` + --> $DIR/rename.rs:40:9 + | +LL | #![warn(clippy::option_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` + +error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` + --> $DIR/rename.rs:41:9 + | +LL | #![warn(clippy::result_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` + +error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` + --> $DIR/rename.rs:42:9 + | +LL | #![warn(clippy::option_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` + +error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` + --> $DIR/rename.rs:43:9 + | +LL | #![warn(clippy::result_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` + +error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` + --> $DIR/rename.rs:44:9 + | +LL | #![warn(clippy::option_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` + +error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` + --> $DIR/rename.rs:45:9 + | +LL | #![warn(clippy::result_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` + +error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` + --> $DIR/rename.rs:46:9 + | +LL | #![warn(clippy::for_loop_over_option)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` + +error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` + --> $DIR/rename.rs:47:9 + | +LL | #![warn(clippy::for_loop_over_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` + +error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` + --> $DIR/rename.rs:48:9 + | +LL | #![warn(clippy::identity_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` + +error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` + --> $DIR/rename.rs:49:9 + | +LL | #![warn(clippy::zero_width_space)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` + +error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` + --> $DIR/rename.rs:50:9 + | +LL | #![warn(clippy::single_char_push_str)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` + +error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` + --> $DIR/rename.rs:51:9 + | +LL | #![warn(clippy::if_let_some_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` + +error: lint `clippy::invalid_ref` has been renamed to `invalid_value` + --> $DIR/rename.rs:53:9 + | +LL | #![warn(clippy::invalid_ref)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` + +error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` + --> $DIR/rename.rs:54:9 + | +LL | #![warn(clippy::into_iter_on_array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` + +error: lint `clippy::unused_label` has been renamed to `unused_labels` + --> $DIR/rename.rs:55:9 + | +LL | #![warn(clippy::unused_label)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` + +error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` + --> $DIR/rename.rs:56:9 + | +LL | #![warn(clippy::drop_bounds)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` + +error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` + --> $DIR/rename.rs:57:9 + | +LL | #![warn(clippy::temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` + +error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` + --> $DIR/rename.rs:58:9 + | +LL | #![warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` + +error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` + --> $DIR/rename.rs:59:9 + | +LL | #![warn(clippy::unknown_clippy_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` + +error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` + --> $DIR/rename.rs:60:9 + | +LL | #![warn(clippy::invalid_atomic_ordering)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` + +error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` + --> $DIR/rename.rs:61:9 | -LL | #[warn(clippy::const_static_lifetime)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` +LL | #![warn(clippy::mem_discriminant_non_enum)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` -error: aborting due to 5 previous errors +error: aborting due to 30 previous errors diff --git a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs index a7f8f54f2be..d7e8d02bd19 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs index 69a3390b03b..ea962f94317 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr index 86c63946516..bf8b47d5626 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr @@ -1,5 +1,5 @@ error: method `add` can be confused for the standard trait method `std::ops::Add::add` - --> $DIR/method_list_1.rs:26:5 + --> $DIR/method_list_1.rs:24:5 | LL | / pub fn add(self, other: T) -> T { LL | | unimplemented!() @@ -10,7 +10,7 @@ LL | | } = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` - --> $DIR/method_list_1.rs:30:5 + --> $DIR/method_list_1.rs:28:5 | LL | / pub fn as_mut(&mut self) -> &mut T { LL | | unimplemented!() @@ -20,7 +20,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` - --> $DIR/method_list_1.rs:34:5 + --> $DIR/method_list_1.rs:32:5 | LL | / pub fn as_ref(&self) -> &T { LL | | unimplemented!() @@ -30,7 +30,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` - --> $DIR/method_list_1.rs:38:5 + --> $DIR/method_list_1.rs:36:5 | LL | / pub fn bitand(self, rhs: T) -> T { LL | | unimplemented!() @@ -40,7 +40,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` - --> $DIR/method_list_1.rs:42:5 + --> $DIR/method_list_1.rs:40:5 | LL | / pub fn bitor(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -50,7 +50,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` - --> $DIR/method_list_1.rs:46:5 + --> $DIR/method_list_1.rs:44:5 | LL | / pub fn bitxor(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -60,7 +60,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` - --> $DIR/method_list_1.rs:50:5 + --> $DIR/method_list_1.rs:48:5 | LL | / pub fn borrow(&self) -> &str { LL | | unimplemented!() @@ -70,7 +70,7 @@ LL | | } = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` - --> $DIR/method_list_1.rs:54:5 + --> $DIR/method_list_1.rs:52:5 | LL | / pub fn borrow_mut(&mut self) -> &mut str { LL | | unimplemented!() @@ -80,7 +80,7 @@ LL | | } = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` - --> $DIR/method_list_1.rs:58:5 + --> $DIR/method_list_1.rs:56:5 | LL | / pub fn clone(&self) -> Self { LL | | unimplemented!() @@ -90,7 +90,7 @@ LL | | } = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` - --> $DIR/method_list_1.rs:62:5 + --> $DIR/method_list_1.rs:60:5 | LL | / pub fn cmp(&self, other: &Self) -> Self { LL | | unimplemented!() @@ -100,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` - --> $DIR/method_list_1.rs:70:5 + --> $DIR/method_list_1.rs:68:5 | LL | / pub fn deref(&self) -> &Self { LL | | unimplemented!() @@ -110,7 +110,7 @@ LL | | } = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` - --> $DIR/method_list_1.rs:74:5 + --> $DIR/method_list_1.rs:72:5 | LL | / pub fn deref_mut(&mut self) -> &mut Self { LL | | unimplemented!() @@ -120,7 +120,7 @@ LL | | } = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name error: method `div` can be confused for the standard trait method `std::ops::Div::div` - --> $DIR/method_list_1.rs:78:5 + --> $DIR/method_list_1.rs:76:5 | LL | / pub fn div(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -130,7 +130,7 @@ LL | | } = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` - --> $DIR/method_list_1.rs:82:5 + --> $DIR/method_list_1.rs:80:5 | LL | / pub fn drop(&mut self) { LL | | unimplemented!() diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs index 2cdc1a06fe6..b663568806d 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr index 0142e299108..426fe3b1adc 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr @@ -1,5 +1,5 @@ error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq` - --> $DIR/method_list_2.rs:27:5 + --> $DIR/method_list_2.rs:25:5 | LL | / pub fn eq(&self, other: &Self) -> bool { LL | | unimplemented!() @@ -10,7 +10,7 @@ LL | | } = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` - --> $DIR/method_list_2.rs:31:5 + --> $DIR/method_list_2.rs:29:5 | LL | / pub fn from_iter<T>(iter: T) -> Self { LL | | unimplemented!() @@ -20,7 +20,7 @@ LL | | } = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` - --> $DIR/method_list_2.rs:35:5 + --> $DIR/method_list_2.rs:33:5 | LL | / pub fn from_str(s: &str) -> Result<Self, Self> { LL | | unimplemented!() @@ -30,7 +30,7 @@ LL | | } = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` - --> $DIR/method_list_2.rs:39:5 + --> $DIR/method_list_2.rs:37:5 | LL | / pub fn hash(&self, state: &mut T) { LL | | unimplemented!() @@ -40,7 +40,7 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> $DIR/method_list_2.rs:43:5 + --> $DIR/method_list_2.rs:41:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | unimplemented!() @@ -50,7 +50,7 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> $DIR/method_list_2.rs:47:5 + --> $DIR/method_list_2.rs:45:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | unimplemented!() @@ -60,7 +60,7 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> $DIR/method_list_2.rs:51:5 + --> $DIR/method_list_2.rs:49:5 | LL | / pub fn into_iter(self) -> Self { LL | | unimplemented!() @@ -70,7 +70,7 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> $DIR/method_list_2.rs:55:5 + --> $DIR/method_list_2.rs:53:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -80,7 +80,7 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> $DIR/method_list_2.rs:59:5 + --> $DIR/method_list_2.rs:57:5 | LL | / pub fn neg(self) -> Self { LL | | unimplemented!() @@ -90,7 +90,7 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> $DIR/method_list_2.rs:63:5 + --> $DIR/method_list_2.rs:61:5 | LL | / pub fn next(&mut self) -> Option<Self> { LL | | unimplemented!() @@ -100,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> $DIR/method_list_2.rs:67:5 + --> $DIR/method_list_2.rs:65:5 | LL | / pub fn not(self) -> Self { LL | | unimplemented!() @@ -110,7 +110,7 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> $DIR/method_list_2.rs:71:5 + --> $DIR/method_list_2.rs:69:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -120,7 +120,7 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> $DIR/method_list_2.rs:75:5 + --> $DIR/method_list_2.rs:73:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -130,7 +130,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> $DIR/method_list_2.rs:79:5 + --> $DIR/method_list_2.rs:77:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -140,7 +140,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> $DIR/method_list_2.rs:83:5 + --> $DIR/method_list_2.rs:81:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | unimplemented!() diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.fixed b/src/tools/clippy/tests/ui/single_component_path_imports.fixed index f66b445b7b6..4c40739d6f5 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.fixed +++ b/src/tools/clippy/tests/ui/single_component_path_imports.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.rs b/src/tools/clippy/tests/ui/single_component_path_imports.rs index 09d48658595..9280bab3c71 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.stderr b/src/tools/clippy/tests/ui/single_component_path_imports.stderr index 7005fa8f125..509c88ac256 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports.rs:24:5 + --> $DIR/single_component_path_imports.rs:23:5 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely @@ -7,7 +7,7 @@ LL | use regex; = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports.rs:6:1 + --> $DIR/single_component_path_imports.rs:5:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_macro.fixed b/src/tools/clippy/tests/ui/single_component_path_imports_macro.fixed index 05863f9a2bf..e43f5d381aa 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_macro.fixed +++ b/src/tools/clippy/tests/ui/single_component_path_imports_macro.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs b/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs index 633deea348b..3c65ca3054c 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_macro.stderr b/src/tools/clippy/tests/ui/single_component_path_imports_macro.stderr index 239efb393b1..37d5176129f 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_macro.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports_macro.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports_macro.rs:16:1 + --> $DIR/single_component_path_imports_macro.rs:15:1 | LL | use m2; // fail | ^^^^^^^ help: remove it entirely diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs index 94117061b27..c75beb74786 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr index 0c3256c1ce4..cf990be1b9f 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:14:10 + --> $DIR/single_component_path_imports_nested_first.rs:13:10 | LL | use {regex, serde}; | ^^^^^ @@ -8,7 +8,7 @@ LL | use {regex, serde}; = help: remove this import error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:14:17 + --> $DIR/single_component_path_imports_nested_first.rs:13:17 | LL | use {regex, serde}; | ^^^^^ @@ -16,7 +16,7 @@ LL | use {regex, serde}; = help: remove this import error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:5:1 + --> $DIR/single_component_path_imports_nested_first.rs:4:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs b/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs index 94319ade0ac..48e8e530261 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs b/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs index c7437b23456..4fb0cf40b6e 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/string_slice.rs b/src/tools/clippy/tests/ui/string_slice.rs new file mode 100644 index 00000000000..be4dfc8816c --- /dev/null +++ b/src/tools/clippy/tests/ui/string_slice.rs @@ -0,0 +1,10 @@ +#[warn(clippy::string_slice)] +#[allow(clippy::no_effect)] + +fn main() { + &"Ölkanne"[1..]; + let m = "Mötörhead"; + &m[2..5]; + let s = String::from(m); + &s[0..2]; +} diff --git a/src/tools/clippy/tests/ui/string_slice.stderr b/src/tools/clippy/tests/ui/string_slice.stderr new file mode 100644 index 00000000000..55040bf5df2 --- /dev/null +++ b/src/tools/clippy/tests/ui/string_slice.stderr @@ -0,0 +1,22 @@ +error: indexing into a string may panic if the index is within a UTF-8 character + --> $DIR/string_slice.rs:5:6 + | +LL | &"Ölkanne"[1..]; + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::string-slice` implied by `-D warnings` + +error: indexing into a string may panic if the index is within a UTF-8 character + --> $DIR/string_slice.rs:7:6 + | +LL | &m[2..5]; + | ^^^^^^^ + +error: indexing into a string may panic if the index is within a UTF-8 character + --> $DIR/string_slice.rs:9:6 + | +LL | &s[0..2]; + | ^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unit_hash.rs b/src/tools/clippy/tests/ui/unit_hash.rs new file mode 100644 index 00000000000..989916c239b --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_hash.rs @@ -0,0 +1,27 @@ +#![warn(clippy::unit_hash)] + +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; + +enum Foo { + Empty, + WithValue(u8), +} + +fn do_nothing() {} + +fn main() { + let mut state = DefaultHasher::new(); + let my_enum = Foo::Empty; + + match my_enum { + Foo::Empty => ().hash(&mut state), + Foo::WithValue(x) => x.hash(&mut state), + } + + let res = (); + res.hash(&mut state); + + #[allow(clippy::unit_arg)] + do_nothing().hash(&mut state); +} diff --git a/src/tools/clippy/tests/ui/unit_hash.stderr b/src/tools/clippy/tests/ui/unit_hash.stderr new file mode 100644 index 00000000000..da276296e02 --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_hash.stderr @@ -0,0 +1,27 @@ +error: this call to `hash` on the unit type will do nothing + --> $DIR/unit_hash.rs:18:23 + | +LL | Foo::Empty => ().hash(&mut state), + | ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` + | + = note: `-D clippy::unit-hash` implied by `-D warnings` + = note: the implementation of `Hash` for `()` is a no-op + +error: this call to `hash` on the unit type will do nothing + --> $DIR/unit_hash.rs:23:5 + | +LL | res.hash(&mut state); + | ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` + | + = note: the implementation of `Hash` for `()` is a no-op + +error: this call to `hash` on the unit type will do nothing + --> $DIR/unit_hash.rs:26:5 + | +LL | do_nothing().hash(&mut state); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` + | + = note: the implementation of `Hash` for `()` is a no-op + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs index 4f4203f5fdb..2a3a506a57b 100644 --- a/src/tools/clippy/tests/ui/unused_async.rs +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::unused_async)] async fn foo() -> i32 { diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr index 8b834d205b1..cc6096d65d9 100644 --- a/src/tools/clippy/tests/ui/unused_async.stderr +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:4:1 + --> $DIR/unused_async.rs:3:1 | LL | / async fn foo() -> i32 { LL | | 4 diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index dcf818f8076..4e33e343ce0 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 // aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index 9da6fef7a38..7b621ff9bca 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 // aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index e14368a11aa..ecb78b3f972 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> $DIR/use_self.rs:23:21 + --> $DIR/use_self.rs:22:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -7,163 +7,163 @@ LL | fn new() -> Foo { = note: `-D clippy::use-self` implied by `-D warnings` error: unnecessary structure name repetition - --> $DIR/use_self.rs:24:13 + --> $DIR/use_self.rs:23:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:26:22 + --> $DIR/use_self.rs:25:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:27:13 + --> $DIR/use_self.rs:26:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:32:25 + --> $DIR/use_self.rs:31:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:33:13 + --> $DIR/use_self.rs:32:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:98:24 + --> $DIR/use_self.rs:97:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:98:55 + --> $DIR/use_self.rs:97:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:113:13 + --> $DIR/use_self.rs:112:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:148:29 + --> $DIR/use_self.rs:147:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:149:21 + --> $DIR/use_self.rs:148:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:160:21 + --> $DIR/use_self.rs:159:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:161:13 + --> $DIR/use_self.rs:160:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:178:21 + --> $DIR/use_self.rs:177:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:179:21 + --> $DIR/use_self.rs:178:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:180:21 + --> $DIR/use_self.rs:179:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:222:13 + --> $DIR/use_self.rs:221:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:223:13 + --> $DIR/use_self.rs:222:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:225:13 + --> $DIR/use_self.rs:224:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:244:13 + --> $DIR/use_self.rs:243:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:258:25 + --> $DIR/use_self.rs:257:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:259:13 + --> $DIR/use_self.rs:258:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:263:16 + --> $DIR/use_self.rs:262:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:263:22 + --> $DIR/use_self.rs:262:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:286:29 + --> $DIR/use_self.rs:285:29 | LL | fn foo(value: T) -> Foo<T> { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:287:13 + --> $DIR/use_self.rs:286:13 | LL | Foo::<T> { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:459:13 + --> $DIR/use_self.rs:458:13 | LL | A::new::<submod::B>(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:496:13 + --> $DIR/use_self.rs:495:13 | LL | S2::new() | ^^ help: use the applicable keyword: `Self` diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs index d8bda7e8f48..21d66d5df79 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.rs +++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs @@ -1,4 +1,3 @@ -// edition:2018 // aux-build:proc_macro_derive.rs #![feature(rustc_private)] diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr index 2cbfc5ca2e2..790b849210c 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr +++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr @@ -1,5 +1,5 @@ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:26:5 + --> $DIR/used_underscore_binding.rs:25:5 | LL | _foo + 1 | ^^^^ @@ -7,31 +7,31 @@ LL | _foo + 1 = note: `-D clippy::used-underscore-binding` implied by `-D warnings` error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:31:20 + --> $DIR/used_underscore_binding.rs:30:20 | LL | println!("{}", _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:32:16 + --> $DIR/used_underscore_binding.rs:31:16 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:32:22 + --> $DIR/used_underscore_binding.rs:31:22 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:45:5 + --> $DIR/used_underscore_binding.rs:44:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:100:16 + --> $DIR/used_underscore_binding.rs:99:16 | LL | uses_i(_i); | ^^ diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index 98bc1e80731..8402c33a4cd 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -1,8 +1,13 @@ +// edition:2015 // run-rustfix // aux-build:wildcard_imports_helper.rs +// the 2015 edition here is needed because edition 2018 changed the module system +// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint +// no longer detects some of the cases starting with Rust 2018. +// FIXME: We should likely add another edition 2021 test case for this lint + #![warn(clippy::wildcard_imports)] -//#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs index 4ef61f9245b..faaeaade9b0 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports.rs @@ -1,8 +1,13 @@ +// edition:2015 // run-rustfix // aux-build:wildcard_imports_helper.rs +// the 2015 edition here is needed because edition 2018 changed the module system +// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint +// no longer detects some of the cases starting with Rust 2018. +// FIXME: We should likely add another edition 2021 test case for this lint + #![warn(clippy::wildcard_imports)] -//#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index d7af0c046e8..7534a65ec9b 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:12:5 + --> $DIR/wildcard_imports.rs:17:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:13:5 + --> $DIR/wildcard_imports.rs:18:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:14:5 + --> $DIR/wildcard_imports.rs:19:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:16:5 + --> $DIR/wildcard_imports.rs:21:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:25:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:21:5 + --> $DIR/wildcard_imports.rs:26:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:92:13 + --> $DIR/wildcard_imports.rs:97:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:98:75 + --> $DIR/wildcard_imports.rs:103:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:99:13 + --> $DIR/wildcard_imports.rs:104:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:110:20 + --> $DIR/wildcard_imports.rs:115:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:110:30 + --> $DIR/wildcard_imports.rs:115:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:117:13 + --> $DIR/wildcard_imports.rs:122:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:146:9 + --> $DIR/wildcard_imports.rs:151:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:155:9 + --> $DIR/wildcard_imports.rs:160:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:156:9 + --> $DIR/wildcard_imports.rs:161:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:167:13 + --> $DIR/wildcard_imports.rs:172:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:202:17 + --> $DIR/wildcard_imports.rs:207:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:210:13 + --> $DIR/wildcard_imports.rs:215:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:219:17 + --> $DIR/wildcard_imports.rs:224:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:228:13 + --> $DIR/wildcard_imports.rs:233:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:236:13 + --> $DIR/wildcard_imports.rs:241:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs index 151dd0c27d5..1b9da8a55e5 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::wrong_self_convention)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr index ce23317abf6..590ee6d9c52 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:17:17 + --> $DIR/wrong_self_convention.rs:16:17 | LL | fn from_i32(self) {} | ^^^^ @@ -8,7 +8,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:23:21 + --> $DIR/wrong_self_convention.rs:22:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -16,7 +16,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:35:15 + --> $DIR/wrong_self_convention.rs:34:15 | LL | fn as_i32(self) {} | ^^^^ @@ -24,7 +24,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:37:17 + --> $DIR/wrong_self_convention.rs:36:17 | LL | fn into_i32(&self) {} | ^^^^^ @@ -32,7 +32,7 @@ LL | fn into_i32(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:39:15 + --> $DIR/wrong_self_convention.rs:38:15 | LL | fn is_i32(self) {} | ^^^^ @@ -40,7 +40,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:41:15 + --> $DIR/wrong_self_convention.rs:40:15 | LL | fn to_i32(self) {} | ^^^^ @@ -48,7 +48,7 @@ LL | fn to_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:43:17 + --> $DIR/wrong_self_convention.rs:42:17 | LL | fn from_i32(self) {} | ^^^^ @@ -56,7 +56,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:45:19 + --> $DIR/wrong_self_convention.rs:44:19 | LL | pub fn as_i64(self) {} | ^^^^ @@ -64,7 +64,7 @@ LL | pub fn as_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:46:21 + --> $DIR/wrong_self_convention.rs:45:21 | LL | pub fn into_i64(&self) {} | ^^^^^ @@ -72,7 +72,7 @@ LL | pub fn into_i64(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:47:19 + --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn is_i64(self) {} | ^^^^ @@ -80,7 +80,7 @@ LL | pub fn is_i64(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:48:19 + --> $DIR/wrong_self_convention.rs:47:19 | LL | pub fn to_i64(self) {} | ^^^^ @@ -88,7 +88,7 @@ LL | pub fn to_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:49:21 + --> $DIR/wrong_self_convention.rs:48:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -96,7 +96,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:94:19 + --> $DIR/wrong_self_convention.rs:93:19 | LL | fn as_i32(self) {} | ^^^^ @@ -104,7 +104,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:97:25 + --> $DIR/wrong_self_convention.rs:96:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ @@ -112,7 +112,7 @@ LL | fn into_i32_ref(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:99:19 + --> $DIR/wrong_self_convention.rs:98:19 | LL | fn is_i32(self) {} | ^^^^ @@ -120,7 +120,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:103:21 + --> $DIR/wrong_self_convention.rs:102:21 | LL | fn from_i32(self) {} | ^^^^ @@ -128,7 +128,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:118:19 + --> $DIR/wrong_self_convention.rs:117:19 | LL | fn as_i32(self); | ^^^^ @@ -136,7 +136,7 @@ LL | fn as_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:121:25 + --> $DIR/wrong_self_convention.rs:120:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -144,7 +144,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:123:19 + --> $DIR/wrong_self_convention.rs:122:19 | LL | fn is_i32(self); | ^^^^ @@ -152,7 +152,7 @@ LL | fn is_i32(self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:127:21 + --> $DIR/wrong_self_convention.rs:126:21 | LL | fn from_i32(self); | ^^^^ @@ -160,7 +160,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:145:25 + --> $DIR/wrong_self_convention.rs:144:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -168,7 +168,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:151:21 + --> $DIR/wrong_self_convention.rs:150:21 | LL | fn from_i32(self); | ^^^^ @@ -176,7 +176,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value - --> $DIR/wrong_self_convention.rs:175:22 + --> $DIR/wrong_self_convention.rs:174:22 | LL | fn to_u64_v2(&self) -> u64 { | ^^^^^ @@ -184,7 +184,7 @@ LL | fn to_u64_v2(&self) -> u64 { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:184:19 + --> $DIR/wrong_self_convention.rs:183:19 | LL | fn to_u64(self) -> u64 { | ^^^^ diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs index 0d827c1feb3..a8fe8331133 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::wrong_self_convention)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr index 0e0d066d656..5bdc47f91f6 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention2.rs:55:29 + --> $DIR/wrong_self_convention2.rs:54:29 | LL | pub fn from_be_self(self) -> Self { | ^^^^ @@ -8,7 +8,7 @@ LL | pub fn from_be_self(self) -> Self { = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention2.rs:64:25 + --> $DIR/wrong_self_convention2.rs:63:25 | LL | fn from_be_self(self) -> Self; | ^^^^ diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs index 486a0d77235..5bb2116bd33 100644 --- a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::wrong_self_convention)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr index 6ce37c59491..8665d8dc9a9 100644 --- a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr @@ -1,5 +1,5 @@ error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_conventions_mut.rs:15:24 + --> $DIR/wrong_self_conventions_mut.rs:14:24 | LL | pub fn to_many(&mut self) -> Option<&mut [T]> { | ^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn to_many(&mut self) -> Option<&mut [T]> { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference - --> $DIR/wrong_self_conventions_mut.rs:23:28 + --> $DIR/wrong_self_conventions_mut.rs:22:28 | LL | pub fn to_many_mut(&self) -> Option<&[T]> { | ^^^^^ diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 98d1ee19f69..5fcaa452ca3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -242,9 +242,6 @@ impl TestProps { if let Some(edition) = config.parse_edition(ln) { self.compile_flags.push(format!("--edition={}", edition)); has_edition = true; - if edition == "2021" { - self.compile_flags.push("-Zunstable-options".to_string()); - } } config.parse_and_update_revisions(ln, &mut self.revisions); diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 2485dbadab5..157b42e2d17 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -168,7 +168,7 @@ fn only_target() { let mut config = config(); config.target = "x86_64-pc-windows-gnu".to_owned(); - assert!(check_ignore(&config, "// only-i686")); + assert!(check_ignore(&config, "// only-x86")); assert!(check_ignore(&config, "// only-linux")); assert!(check_ignore(&config, "// only-msvc")); assert!(check_ignore(&config, "// only-32bit")); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 4470272a9f8..3c85b9076dd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1607,9 +1607,6 @@ impl<'test> TestCx<'test> { get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib); rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name)); } - if !self.props.aux_crates.is_empty() { - rustc.arg("-Zunstable-options"); - } aux_dir } diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject 1f47693e02809c97db61b51247ae4e4d46744c6 +Subproject 04f03a360ab8fef3d9c0ff84de2d39b8a196c71 diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index bb9cd00f3f5..a673e425dff 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -414,7 +414,7 @@ function parseOptions(args) { "test_folder": "", "test_file": "", }; - var correspondances = { + var correspondences = { "--resource-suffix": "resource_suffix", "--doc-folder": "doc_folder", "--test-folder": "test_folder", @@ -423,17 +423,13 @@ function parseOptions(args) { }; for (var i = 0; i < args.length; ++i) { - if (args[i] === "--resource-suffix" - || args[i] === "--doc-folder" - || args[i] === "--test-folder" - || args[i] === "--test-file" - || args[i] === "--crate-name") { + if (correspondences.hasOwnProperty(args[i])) { i += 1; if (i >= args.length) { console.log("Missing argument after `" + args[i - 1] + "` option."); return null; } - opts[correspondances[args[i - 1]]] = args[i]; + opts[correspondences[args[i - 1]]] = args[i]; } else if (args[i] === "--help") { showHelp(); process.exit(0); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 338dfd11310..129237775fe 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -97,6 +97,7 @@ pub fn check( &src_path.join("test/ui"), &src_path.join("test/ui-fulldeps"), &src_path.join("test/rustdoc-ui"), + &src_path.join("test/rustdoc"), ], &mut |path| super::filter_dirs(path), &mut |entry, contents| { diff --git a/triagebot.toml b/triagebot.toml index 48c7a00de78..7a9908fe8c0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -2,6 +2,8 @@ allow-unauthenticated = [ "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*", "D-*", + "needs-fcp", + "relnotes", "requires-nightly", "regression-*", "perf-*", |
