diff options
932 files changed, 8988 insertions, 7534 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f14cd36ce4..8cc26d2995e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,9 @@ jobs: os: ubuntu-20.04-4core-16gb env: {} - name: x86_64-gnu-llvm-15 + env: + ENABLE_GCC_CODEGEN: "1" os: ubuntu-20.04-16core-64gb - env: {} - name: x86_64-gnu-tools os: ubuntu-20.04-16core-64gb env: {} diff --git a/Cargo.lock b/Cargo.lock index 6aee143feab..54d315c47cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -556,6 +556,7 @@ name = "clippy" version = "0.1.75" dependencies = [ "anstream", + "clippy_config", "clippy_lints", "clippy_utils", "color-print", @@ -579,6 +580,16 @@ dependencies = [ ] [[package]] +name = "clippy_config" +version = "0.1.75" +dependencies = [ + "rustc-semver", + "serde", + "toml 0.7.5", + "walkdir", +] + +[[package]] name = "clippy_dev" version = "0.0.1" dependencies = [ @@ -597,6 +608,7 @@ version = "0.1.75" dependencies = [ "arrayvec", "cargo_metadata 0.15.4", + "clippy_config", "clippy_utils", "declare_clippy_lint", "if_chain", @@ -621,10 +633,10 @@ name = "clippy_utils" version = "0.1.75" dependencies = [ "arrayvec", + "clippy_config", "if_chain", "itertools", "rustc-semver", - "serde", ] [[package]] @@ -710,9 +722,9 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "compiler_builtins" -version = "0.1.101" +version = "0.1.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a6d58e9c3408138099a396a98fd0d0e6cfb25d723594d2ae48b5004513fd5b" +checksum = "a3b73c3443a5fd2438d7ba4853c64e4c8efc2404a9e28a9234cc2d5eebc6c242" dependencies = [ "cc", "rustc-std-workspace-core", @@ -3784,7 +3796,6 @@ dependencies = [ "rustc_monomorphize", "rustc_parse", "rustc_passes", - "rustc_plugin_impl", "rustc_privacy", "rustc_query_system", "rustc_resolve", @@ -4073,7 +4084,6 @@ dependencies = [ "rustc_monomorphize", "rustc_parse", "rustc_passes", - "rustc_plugin_impl", "rustc_privacy", "rustc_query_impl", "rustc_query_system", @@ -4384,21 +4394,6 @@ dependencies = [ ] [[package]] -name = "rustc_plugin_impl" -version = "0.0.0" -dependencies = [ - "libloading 0.7.4", - "rustc_ast", - "rustc_errors", - "rustc_fluent_macro", - "rustc_lint", - "rustc_macros", - "rustc_metadata", - "rustc_session", - "rustc_span", -] - -[[package]] name = "rustc_privacy" version = "0.0.0" dependencies = [ diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 93805710cb5..0fff9a6be92 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -15,9 +15,10 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; use rustc_session::errors::report_lit_error; -use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; +use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::DUMMY_SP; +use rustc_span::{DesugaringKind, Span}; use thin_vec::{thin_vec, ThinVec}; impl<'hir> LoweringContext<'_, 'hir> { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 299ca91460d..c73d2382db8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -16,9 +16,8 @@ use rustc_hir::PredicateOrigin; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, Symbol}; +use rustc_span::{DesugaringKind, Span, Symbol}; use rustc_target::spec::abi; use smallvec::{smallvec, SmallVec}; use thin_vec::ThinVec; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bc656585d47..a88493acf98 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -71,9 +71,8 @@ use rustc_middle::{ }; use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DesugaringKind, Span, DUMMY_SP}; use smallvec::SmallVec; use std::collections::hash_map::Entry; use thin_vec::ThinVec; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 003254b8da1..dde46eef6a0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -9,9 +9,8 @@ use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, }; -use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; use crate::diagnostics::BorrowedContentSource; diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 8832d345df2..3a104c52431 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -6,8 +6,8 @@ use crate::Upvar; use rustc_index::IndexSlice; use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{RegionVid, TyCtxt}; -use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; +use rustc_span::Span; impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn get_var_name_and_span_for_region( diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 26f91b714b4..2d5043112b6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -6,9 +6,10 @@ pub use Ty::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; use rustc_expand::base::ExtCtxt; -use rustc_span::source_map::{respan, DUMMY_SP}; +use rustc_span::source_map::respan; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::DUMMY_SP; use thin_vec::ThinVec; /// A path, e.g., `::std::option::Option::<i32>` (global). Has support diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index b485f2571cc..a299b6de6b1 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -68,7 +68,6 @@ rm -r tests/run-make/split-debuginfo # same rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same -rm -r tests/run-make/use-extern-for-plugins # same rm tests/ui/asm/x86_64/issue-82869.rs # vector regs in inline asm not yet supported rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 51fab147aa2..b0b3aeecdbd 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -18,7 +18,6 @@ path = "tests/lang_tests_release.rs" harness = false [features] -default = ["master"] master = ["gccjit/master"] [dependencies] diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh index 006758e19e1..7ae2175d41d 100644 --- a/compiler/rustc_codegen_gcc/config.sh +++ b/compiler/rustc_codegen_gcc/config.sh @@ -25,7 +25,7 @@ else exit 1 fi -HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") +HOST_TRIPLE=$($RUSTC -vV | grep host | cut -d: -f2 | tr -d " ") # TODO: remove $OVERWRITE_TARGET_TRIPLE when config.sh is removed. TARGET_TRIPLE="${OVERWRITE_TARGET_TRIPLE:-$HOST_TRIPLE}" @@ -54,6 +54,10 @@ if [[ -z "$BUILTIN_BACKEND" ]]; then export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS" else export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=gcc $TEST_FLAGS -Cpanic=abort" + + if [[ ! -z "$RUSTC_SYSROOT" ]]; then + export RUSTFLAGS="$RUSTFLAGS --sysroot $RUSTC_SYSROOT" + fi fi # FIXME(antoyo): remove once the atomic shim is gone diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs index f1954a30cf8..6ed8b9157f2 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_example.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -18,7 +18,7 @@ extern "C" { } #[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo) -> ! { +fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { core::intrinsics::abort(); } diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs index 201e4c73675..945d34063a6 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_system.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -3,7 +3,6 @@ #![no_std] #![feature(allocator_api, rustc_private)] -#![cfg_attr(any(unix, target_os = "redox"), feature(libc))] // The minimum alignment guaranteed by the architecture. This value is used to // add fast paths for low alignment values. @@ -48,7 +47,18 @@ mod realloc_fallback { } #[cfg(any(unix, target_os = "redox"))] mod platform { - extern crate libc; + mod libc { + use core::ffi::{c_void, c_int}; + + #[link(name = "c")] + extern "C" { + pub fn malloc(size: usize) -> *mut c_void; + pub fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void; + pub fn calloc(nmemb: usize, size: usize) -> *mut c_void; + pub fn free(ptr: *mut u8); + pub fn posix_memalign(memptr: *mut *mut c_void, alignment: usize, size: usize) -> c_int; + } + } use core::ptr; use MIN_ALIGN; use System; @@ -82,12 +92,12 @@ mod platform { } #[inline] unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) + libc::free(ptr as *mut _) } #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + libc::realloc(ptr as *mut _, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs index c60bc7fb724..cae911c1073 100644 --- a/compiler/rustc_codegen_gcc/example/mod_bench.rs +++ b/compiler/rustc_codegen_gcc/example/mod_bench.rs @@ -6,7 +6,7 @@ extern {} #[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo) -> ! { +fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { core::intrinsics::abort(); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 73821b1685d..307c1264dc1 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -374,15 +374,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { let g = self.get_static(def_id); - // boolean SSA values are i1, but they have to be stored in i8 slots, - // otherwise some LLVM optimization passes don't work as expected - let mut val_llty = self.val_ty(v); - let v = if val_llty == self.type_i1() { - val_llty = self.type_i8(); - llvm::LLVMConstZExt(v, val_llty) - } else { - v - }; + let val_llty = self.val_ty(v); let instance = Instance::mono(self.tcx, def_id); let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index b4b2ab1e1f8..4dd6372b5e0 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -26,8 +26,8 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::{BranchProtection, CFGuard, CFProtection}; use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; -use rustc_span::source_map::Span; use rustc_span::source_map::Spanned; +use rustc_span::Span; use rustc_target::abi::{ call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, }; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a038b3af03d..7fc02a95be0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -969,7 +969,6 @@ extern "C" { ConstantIndices: *const &'a Value, NumIndices: c_uint, ) -> &'a Value; - pub fn LLVMConstZExt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 22afb406326..3d2d8f8b509 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -17,8 +17,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_session::config::OptLevel; -use rustc_span::source_map::Span; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index b0f757898e3..8e5019967a4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt}; use rustc_session::config::OptLevel; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, FIRST_VARIANT}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 7782cb8fd38..13937a94198 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -10,7 +10,7 @@ use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_target::abi::{self, Abi}; use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter}; diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index e53282ffaeb..f6942366cbd 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -6,7 +6,7 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; mod error; mod eval_queries; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 3aaaf08c856..bda6a905503 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -10,7 +10,7 @@ use crate::interpret::{ use rustc_middle::mir; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use rustc_target::abi::VariantIdx; #[instrument(skip(ecx), level = "debug")] diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 39dddb59569..5695d839d3e 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -77,12 +77,12 @@ mod disabled { }) } - pub fn try_par_for_each_in<T: IntoIterator, E: Copy>( + pub fn try_par_for_each_in<T: IntoIterator, E>( t: T, mut for_each: impl FnMut(T::Item) -> Result<(), E>, ) -> Result<(), E> { parallel_guard(|guard| { - t.into_iter().fold(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret)) + t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and) }) } @@ -178,7 +178,7 @@ mod enabled { pub fn try_par_for_each_in< T: IntoIterator + IntoParallelIterator<Item = <T as IntoIterator>::Item>, - E: Copy + Send, + E: Send, >( t: T, for_each: impl Fn(<T as IntoIterator>::Item) -> Result<(), E> + DynSync + DynSend, @@ -187,11 +187,10 @@ mod enabled { if mode::is_dyn_thread_safe() { let for_each = FromDyn::from(for_each); t.into_par_iter() - .fold_with(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret)) - .reduce(|| Ok(()), |a, b| a.and(b)) + .filter_map(|i| guard.run(|| for_each(i))) + .reduce(|| Ok(()), Result::and) } else { - t.into_iter() - .fold(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret)) + t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and) } }) } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 252803e3cba..da7c2440faa 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -39,7 +39,6 @@ rustc_mir_transform = { path = "../rustc_mir_transform" } rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_parse = { path = "../rustc_parse" } rustc_passes = { path = "../rustc_passes" } -rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index e4cb3fd25cd..ee4337754a9 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -20,8 +20,6 @@ #[macro_use] extern crate tracing; -pub extern crate rustc_plugin_impl as plugin; - use rustc_ast as ast; use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ @@ -43,8 +41,9 @@ use rustc_session::cstore::MetadataLoader; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, EarlyErrorHandler, Session}; -use rustc_span::source_map::{FileLoader, FileName}; +use rustc_span::source_map::FileLoader; use rustc_span::symbol::sym; +use rustc_span::FileName; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTriple}; @@ -131,7 +130,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_monomorphize::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE, rustc_passes::DEFAULT_LOCALE_RESOURCE, - rustc_plugin_impl::DEFAULT_LOCALE_RESOURCE, rustc_privacy::DEFAULT_LOCALE_RESOURCE, rustc_query_system::DEFAULT_LOCALE_RESOURCE, rustc_resolve::DEFAULT_LOCALE_RESOURCE, @@ -993,16 +991,14 @@ the command line flag directly. } /// Write to stdout lint command options, together with a list of all available lints -pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) { +pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_lints: bool) { safe_println!( " Available lint options: -W <foo> Warn about <foo> - -A <foo> \ - Allow <foo> + -A <foo> Allow <foo> -D <foo> Deny <foo> - -F <foo> Forbid <foo> \ - (deny <foo> and all attempts to override) + -F <foo> Forbid <foo> (deny <foo> and all attempts to override) " ); @@ -1021,18 +1017,18 @@ Available lint options: lints } - let (plugin, builtin): (Vec<_>, _) = - lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_plugin); - let plugin = sort_lints(sess, plugin); + let (loaded, builtin): (Vec<_>, _) = + lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_loaded); + let loaded = sort_lints(sess, loaded); let builtin = sort_lints(sess, builtin); - let (plugin_groups, builtin_groups): (Vec<_>, _) = + let (loaded_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups().partition(|&(.., p)| p); - let plugin_groups = sort_lint_groups(plugin_groups); + let loaded_groups = sort_lint_groups(loaded_groups); let builtin_groups = sort_lint_groups(builtin_groups); let max_name_len = - plugin.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0); + loaded.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0); let padded = |x: &str| { let mut s = " ".repeat(max_name_len - x.chars().count()); s.push_str(x); @@ -1060,7 +1056,7 @@ Available lint options: let max_name_len = max( "warnings".len(), - plugin_groups + loaded_groups .iter() .chain(&builtin_groups) .map(|&(s, _)| s.chars().count()) @@ -1098,20 +1094,22 @@ Available lint options: print_lint_groups(builtin_groups, true); - match (loaded_plugins, plugin.len(), plugin_groups.len()) { + match (loaded_lints, loaded.len(), loaded_groups.len()) { (false, 0, _) | (false, _, 0) => { - safe_println!("Lint tools like Clippy can provide additional lints and lint groups."); + safe_println!("Lint tools like Clippy can load additional lints and lint groups."); + } + (false, ..) => panic!("didn't load additional lints but got them anyway!"), + (true, 0, 0) => { + safe_println!("This crate does not load any additional lints or lint groups.") } - (false, ..) => panic!("didn't load lint plugins but got them anyway!"), - (true, 0, 0) => safe_println!("This crate does not load any lint plugins or lint groups."), (true, l, g) => { if l > 0 { - safe_println!("Lint checks provided by plugins loaded by this crate:\n"); - print_lints(plugin); + safe_println!("Lint checks loaded by this crate:\n"); + print_lints(loaded); } if g > 0 { - safe_println!("Lint groups provided by plugins loaded by this crate:\n"); - print_lint_groups(plugin_groups, false); + safe_println!("Lint groups loaded by this crate:\n"); + print_lint_groups(loaded_groups, false); } } } @@ -1128,7 +1126,7 @@ pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches) rustc_errors::FatalError.raise(); } - // Don't handle -W help here, because we might first load plugins. + // Don't handle -W help here, because we might first load additional lints. let debug_flags = matches.opt_strs("Z"); if debug_flags.iter().any(|x| *x == "help") { describe_debug_flags(); diff --git a/compiler/rustc_error_codes/src/error_codes/E0457.md b/compiler/rustc_error_codes/src/error_codes/E0457.md index 2c33d1e6a24..e2dbf53a0f8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0457.md +++ b/compiler/rustc_error_codes/src/error_codes/E0457.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler` + Plugin `..` only found in rlib format, but must be available in dylib format. Erroneous code example: diff --git a/compiler/rustc_error_codes/src/error_codes/E0463.md b/compiler/rustc_error_codes/src/error_codes/E0463.md index d0cd1b1dcb7..9bd8d0e834b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0463.md +++ b/compiler/rustc_error_codes/src/error_codes/E0463.md @@ -1,16 +1,13 @@ -A plugin/crate was declared but cannot be found. +A crate was declared but cannot be found. Erroneous code example: ```compile_fail,E0463 -#![feature(plugin)] -#![plugin(cookie_monster)] // error: can't find crate for `cookie_monster` -extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie` +extern crate foo; // error: can't find crate ``` You need to link your code to the relevant crate in order to be able to use it -(through Cargo or the `-L` option of rustc example). Plugins are crates as -well, and you link to them the same way. +(through Cargo or the `-L` option of rustc, for example). ## Common causes diff --git a/compiler/rustc_error_codes/src/error_codes/E0498.md b/compiler/rustc_error_codes/src/error_codes/E0498.md index c9ea4a7947f..a67a9317db4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0498.md +++ b/compiler/rustc_error_codes/src/error_codes/E0498.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The `plugin` attribute was malformed. Erroneous code example: -```compile_fail,E0498 +```ignore (E0498 is no longer emitted) #![feature(plugin)] #![plugin(foo(args))] // error: invalid argument #![plugin(bar="test")] // error: invalid argument diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 82cac229284..1292a855230 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -4,8 +4,8 @@ use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_data_structures::fx::FxHashMap; -use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::Ident; +use rustc_span::DUMMY_SP; use smallvec::{smallvec, SmallVec}; use thin_vec::ThinVec; diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 8e3219c138c..9f52669e188 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; use rustc_parse::{new_parser_from_source_str, parser::Parser, source_file_to_stream}; use rustc_session::parse::ParseSess; -use rustc_span::create_default_session_if_not_set_then; +use rustc_span::create_default_session_globals_then; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{BytePos, Span}; @@ -181,7 +181,7 @@ impl<T: Write> Write for Shared<T> { } fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) { - create_default_session_if_not_set_then(|_| { + create_default_session_globals_then(|| { let (handler, source_map, output) = create_test_handler(); source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e808e4815fe..214de3ca402 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -417,24 +417,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ naked_functions, experimental!(naked) ), - // Plugins: - BuiltinAttribute { - name: sym::plugin, - only_local: false, - type_: CrateLevel, - template: template!(List: "name"), - duplicates: DuplicatesOk, - gate: Gated( - Stability::Deprecated( - "https://github.com/rust-lang/rust/pull/64675", - Some("may be removed in a future compiler version"), - ), - sym::plugin, - "compiler plugins are deprecated", - cfg_fn!(plugin) - ), - }, - // Testing: gated!( test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks, diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index ed19274a7cc..03f92f69b41 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -152,9 +152,12 @@ declare_features! ( Some("removed in favor of `#![feature(marker_trait_attr)]`")), (removed, panic_implementation, "1.28.0", Some(44489), None, Some("subsumed by `#[panic_handler]`")), + /// Allows using `#![plugin(myplugin)]`. + (removed, plugin, "CURRENT_RUSTC_VERSION", Some(29597), None, + Some("plugins are no longer supported")), /// Allows using `#[plugin_registrar]` on functions. (removed, plugin_registrar, "1.54.0", Some(29597), None, - Some("a __rustc_plugin_registrar symbol must now be defined instead")), + Some("plugins are no longer supported")), (removed, proc_macro_expr, "1.27.0", Some(54727), None, Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, proc_macro_gen, "1.27.0", Some(54727), None, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 72100863bb5..11782e33d84 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -528,8 +528,6 @@ declare_features! ( (unstable, object_safe_for_dispatch, "1.40.0", Some(43561), None), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882), None), - /// Allows using `#![plugin(myplugin)]`. - (unstable, plugin, "1.0.0", Some(29597), None), /// Allows exhaustive integer pattern matching on `usize` and `isize`. (unstable, precise_pointer_size_matching, "1.32.0", Some(56354), None), /// Allows macro attributes on expressions, statements and non-inline modules. diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index a40a0178710..74b8e88a977 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -2,7 +2,7 @@ use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData}; use rustc_data_structures::stable_hasher::Hash64; use rustc_span::def_id::{DefPathHash, StableCrateId}; use rustc_span::edition::Edition; -use rustc_span::{create_session_if_not_set_then, Symbol}; +use rustc_span::{create_session_globals_then, Symbol}; #[test] fn def_path_hash_depends_on_crate_id() { @@ -14,7 +14,7 @@ fn def_path_hash_depends_on_crate_id() { // the crate by changing the crate disambiguator (e.g. via bumping the // crate's version number). - create_session_if_not_set_then(Edition::Edition2024, |_| { + create_session_globals_then(Edition::Edition2024, || { let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], ""); let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], ""); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 74e2b157dd0..90babbb63a0 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2162,128 +2162,10 @@ pub(super) fn check_type_bounds<'tcx>( impl_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let param_env = tcx.param_env(impl_ty.def_id); - let container_id = impl_ty.container_id(tcx); - // Given - // - // impl<A, B> Foo<u32> for (A, B) { - // type Bar<C> = Wrapper<A, B, C> - // } - // - // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` - // - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) - // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>` - // - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from - // the *trait* with the generic associated type parameters (as bound vars). - // - // A note regarding the use of bound vars here: - // Imagine as an example - // ``` - // trait Family { - // type Member<C: Eq>; - // } - // - // impl Family for VecFamily { - // type Member<C: Eq> = i32; - // } - // ``` - // Here, we would generate - // ```notrust - // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) } - // ``` - // when we really would like to generate - // ```notrust - // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) } - // ``` - // But, this is probably fine, because although the first clause can be used with types C that - // do not implement Eq, for it to cause some kind of problem, there would have to be a - // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type - // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing - // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in - // the trait (notably, that X: Eq and T: Family). - let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); - // Extend the impl's identity args with late-bound GAT vars - let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id).extend_to( - tcx, - impl_ty.def_id, - |param, _| match param.kind { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - ty::Region::new_late_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() - } - }, - ); - // When checking something like - // - // trait X { type Y: PartialEq<<Self as X>::Y> } - // impl X for T { default type Y = S; } - // - // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case - // we want <T as X>::Y to normalize to S. This is valid because we are - // checking the default value specifically here. Add this equality to the - // ParamEnv for normalization specifically. - let normalize_impl_ty = tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); - let rebased_args = normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); - let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); - let normalize_param_env = { - let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>(); - match normalize_impl_ty.kind() { - ty::Alias(ty::Projection, proj) - if proj.def_id == trait_ty.def_id && proj.args == rebased_args => - { - // Don't include this predicate if the projected type is - // exactly the same as the projection. This can occur in - // (somewhat dubious) code like this: - // - // impl<T> X for T where T: X { type Y = <T as X>::Y; } - } - _ => predicates.push( - ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), - term: normalize_impl_ty.into(), - }, - bound_vars, - ) - .to_predicate(tcx), - ), - }; - ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) - }; - debug!(?normalize_param_env); + let param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref); + debug!(?param_env); + let container_id = impl_ty.container_id(tcx); let impl_ty_def_id = impl_ty.def_id.expect_local(); let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); @@ -2336,8 +2218,7 @@ pub(super) fn check_type_bounds<'tcx>( debug!("check_type_bounds: item_bounds={:?}", obligations); for mut obligation in util::elaborate(tcx, obligations) { - let normalized_predicate = - ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); + let normalized_predicate = ocx.normalize(&normalize_cause, param_env, obligation.predicate); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; @@ -2358,6 +2239,171 @@ pub(super) fn check_type_bounds<'tcx>( ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } +/// Install projection predicates that allow GATs to project to their own +/// definition types. This is not allowed in general in cases of default +/// associated types in trait definitions, or when specialization is involved, +/// but is needed when checking these definition types actually satisfy the +/// trait bounds of the GAT. +/// +/// # How it works +/// +/// ```ignore (example) +/// impl<A, B> Foo<u32> for (A, B) { +/// type Bar<C> = Wrapper<A, B, C> +/// } +/// ``` +/// +/// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` +/// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) +/// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>` +/// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from +/// the *trait* with the generic associated type parameters (as bound vars). +/// +/// A note regarding the use of bound vars here: +/// Imagine as an example +/// ``` +/// trait Family { +/// type Member<C: Eq>; +/// } +/// +/// impl Family for VecFamily { +/// type Member<C: Eq> = i32; +/// } +/// ``` +/// Here, we would generate +/// ```ignore (pseudo-rust) +/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) } +/// ``` +/// +/// when we really would like to generate +/// ```ignore (pseudo-rust) +/// forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) } +/// ``` +/// +/// But, this is probably fine, because although the first clause can be used with types `C` that +/// do not implement `Eq`, for it to cause some kind of problem, there would have to be a +/// `VecFamily::Member<X>` for some type `X` where `!(X: Eq)`, that appears in the value of type +/// `Member<C: Eq> = ....` That type would fail a well-formedness check that we ought to be doing +/// elsewhere, which would check that any `<T as Family>::Member<X>` meets the bounds declared in +/// the trait (notably, that `X: Eq` and `T: Family`). +fn param_env_with_gat_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + impl_ty: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> ty::ParamEnv<'tcx> { + let param_env = tcx.param_env(impl_ty.def_id); + let container_id = impl_ty.container_id(tcx); + let mut predicates = param_env.caller_bounds().to_vec(); + + // for RPITITs, we should install predicates that allow us to project all + // of the RPITITs associated with the same body. This is because checking + // the item bounds of RPITITs often involves nested RPITITs having to prove + // bounds about themselves. + let impl_tys_to_install = match impl_ty.opt_rpitit_info { + None => vec![impl_ty], + Some( + ty::ImplTraitInTraitData::Impl { fn_def_id } + | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, + ) => tcx + .associated_types_for_impl_traits_in_associated_fn(fn_def_id) + .iter() + .map(|def_id| tcx.associated_item(*def_id)) + .collect(), + }; + + for impl_ty in impl_tys_to_install { + let trait_ty = match impl_ty.container { + ty::AssocItemContainer::TraitContainer => impl_ty, + ty::AssocItemContainer::ImplContainer => { + tcx.associated_item(impl_ty.trait_item_def_id.unwrap()) + } + }; + + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + // Extend the impl's identity args with late-bound GAT vars + let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id) + .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }); + // When checking something like + // + // trait X { type Y: PartialEq<<Self as X>::Y> } + // impl X for T { default type Y = S; } + // + // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case + // we want <T as X>::Y to normalize to S. This is valid because we are + // checking the default value specifically here. Add this equality to the + // ParamEnv for normalization specifically. + let normalize_impl_ty = + tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); + let rebased_args = + normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); + let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); + + match normalize_impl_ty.kind() { + ty::Alias(ty::Projection, proj) + if proj.def_id == trait_ty.def_id && proj.args == rebased_args => + { + // Don't include this predicate if the projected type is + // exactly the same as the projection. This can occur in + // (somewhat dubious) code like this: + // + // impl<T> X for T where T: X { type Y = <T as X>::Y; } + } + _ => predicates.push( + ty::Binder::bind_with_vars( + ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), + term: normalize_impl_ty.into(), + }, + bound_vars, + ) + .to_predicate(tcx), + ), + }; + } + + ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 8da953e6e2e..15c5558fc0b 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -90,9 +90,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::parse::feature_err; -use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol}; +use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index ebb9e6f42d9..6424d1c7931 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -880,7 +880,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { (pair, r) }) .unzip(); - self.record_late_bound_vars(hir_id, binders.clone()); + self.record_late_bound_vars(hir_id, binders); // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 5591fa6f2a5..ed5e9dd2b5a 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::source_map::Span; +use rustc_span::Span; use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d6073dbc128..a70ead8e57d 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -14,8 +14,7 @@ use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::ArgKind; diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 963a93a95c2..29fcc61cbb5 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,5 +1,4 @@ -use rustc_span::source_map::DUMMY_SP; -use rustc_span::{self, Span}; +use rustc_span::{self, Span, DUMMY_SP}; use std::{cmp, ops}; /// Tracks whether executing a node may exit normally (versus diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index bdac886bf9e..a11fe10c01c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -52,8 +52,9 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::Span; use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e0ccf04ab63..50684482c0d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -17,8 +17,9 @@ use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; use rustc_span::{BytePos, DUMMY_SP}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::{ObligationCause, Pattern}; diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 280dcae3451..3c4c4644fe6 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -27,7 +27,7 @@ use rustc_index::IndexVec; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, List, Ty, TyCtxt}; -use rustc_span::source_map::Span; +use rustc_span::Span; pub use rustc_middle::infer::canonical::*; pub use substitute::CanonicalExt; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e4be435fded..26d071a0139 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2444,18 +2444,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let suggestion = if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") }; suggs.push((sp, suggestion)) - } else { - let generics = self.tcx.hir().get_generics(suggestion_scope).unwrap(); + } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) { let pred = format!("{bound_kind}: {lt_name}"); - let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,); + let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred); suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion)) + } else { + let consider = format!("{msg} `{bound_kind}: {sub}`..."); + err.help(consider); } - err.multipart_suggestion_verbose( - format!("{msg}"), - suggs, - Applicability::MaybeIncorrect, // Issue #41966 - ); + if !suggs.is_empty() { + err.multipart_suggestion_verbose( + format!("{msg}"), + suggs, + Applicability::MaybeIncorrect, // Issue #41966 + ); + } } err diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 59fb74eb543..2a70c4673b0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -3,7 +3,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError::*; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::source_map::Span; +use rustc_span::Span; mod different_lifetimes; pub mod find_anon_type; diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs index ebc51b98be5..398ac94ee36 100644 --- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs +++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs @@ -1,4 +1,6 @@ -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use std::ops::ControlFlow; @@ -49,6 +51,12 @@ where return ControlFlow::Continue(()); } + // FIXME: Don't consider alias bounds on types that have escaping bound + // vars. See #117455. + if ty.has_escaping_bound_vars() { + return ty.super_visit_with(self); + } + match ty.kind() { // We can prove that an alias is live two ways: // 1. All the components are live. diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index a73152601b3..fd587e53f91 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -36,7 +36,6 @@ rustc_mir_transform = { path = "../rustc_mir_transform" } rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_parse = { path = "../rustc_parse" } rustc_passes = { path = "../rustc_passes" } -rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } rustc_query_impl = { path = "../rustc_query_impl" } rustc_query_system = { path = "../rustc_query_system" } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index ffdc05526f2..c4962707f69 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -21,8 +21,9 @@ use rustc_session::config::{ use rustc_session::filesearch::sysroot_candidates; use rustc_session::parse::ParseSess; use rustc_session::{lint, CompilerIO, EarlyErrorHandler, Session}; -use rustc_span::source_map::{FileLoader, FileName}; +use rustc_span::source_map::FileLoader; use rustc_span::symbol::sym; +use rustc_span::FileName; use std::path::PathBuf; use std::result; use std::sync::Arc; @@ -353,7 +354,7 @@ pub struct Config { pub hash_untracked_state: Option<Box<dyn FnOnce(&Session, &mut StableHasher) + Send>>, /// This is a callback from the driver that is called when we're registering lints; - /// it is called during plugin registration when we have the LintStore in a non-shared state. + /// it is called during lint loading when we have the LintStore in a non-shared state. /// /// Note that if you find a Some here you probably want to call that function in the new /// function being registered. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 2099a6d59cb..7d14d088e59 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -23,11 +23,10 @@ use rustc_middle::util::Providers; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_passes::{self, abi_test, hir_stats, layout_test}; -use rustc_plugin_impl as plugin; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; -use rustc_session::cstore::{MetadataLoader, Untracked}; +use rustc_session::cstore::Untracked; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; @@ -75,25 +74,12 @@ fn count_nodes(krate: &ast::Crate) -> usize { pub(crate) fn create_lint_store( sess: &Session, - metadata_loader: &dyn MetadataLoader, register_lints: Option<impl Fn(&Session, &mut LintStore)>, - pre_configured_attrs: &[ast::Attribute], ) -> LintStore { let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); if let Some(register_lints) = register_lints { register_lints(sess, &mut lint_store); } - - let registrars = sess.time("plugin_loading", || { - plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs) - }); - sess.time("plugin_registration", || { - let mut registry = plugin::Registry { lint_store: &mut lint_store }; - for registrar in registrars { - registrar(&mut registry); - } - }); - lint_store } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 4fb295da640..3a5f788e8dd 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -148,12 +148,8 @@ impl<'tcx> Queries<'tcx> { ); let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?; - let lint_store = Lrc::new(passes::create_lint_store( - sess, - &*self.codegen_backend().metadata_loader(), - self.compiler.register_lints.as_deref(), - &pre_configured_attrs, - )); + let lint_store = + Lrc::new(passes::create_lint_store(sess, self.compiler.register_lints.as_deref())); let cstore = FreezeLock::new(Box::new(CStore::new( self.codegen_backend().metadata_loader(), stable_crate_id, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 594283168c9..8e66083a390 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -817,7 +817,6 @@ fn test_unstable_options_tracking_hash() { tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); tracked!(stack_protector, StackProtector::All); - tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(thir_unsafeck, true); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5b7ba03d9ad..a5f4c5ff045 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -109,7 +109,7 @@ struct LintAlias { struct LintGroup { lint_ids: Vec<LintId>, - from_plugin: bool, + is_loaded: bool, depr: Option<LintAlias>, } @@ -160,9 +160,7 @@ impl LintStore { // Don't display deprecated lint groups. depr.is_none() }) - .map(|(k, LintGroup { lint_ids, from_plugin, .. })| { - (*k, lint_ids.clone(), *from_plugin) - }) + .map(|(k, LintGroup { lint_ids, is_loaded, .. })| (*k, lint_ids.clone(), *is_loaded)) } pub fn register_early_pass( @@ -221,7 +219,7 @@ impl LintStore { .entry(edition.lint_name()) .or_insert(LintGroup { lint_ids: vec![], - from_plugin: lint.is_plugin, + is_loaded: lint.is_loaded, depr: None, }) .lint_ids @@ -234,7 +232,7 @@ impl LintStore { .entry("future_incompatible") .or_insert(LintGroup { lint_ids: vec![], - from_plugin: lint.is_plugin, + is_loaded: lint.is_loaded, depr: None, }) .lint_ids @@ -249,7 +247,7 @@ impl LintStore { alias, LintGroup { lint_ids: vec![], - from_plugin: false, + is_loaded: false, depr: Some(LintAlias { name: lint_name, silent: true }), }, ); @@ -257,21 +255,21 @@ impl LintStore { pub fn register_group( &mut self, - from_plugin: bool, + is_loaded: bool, name: &'static str, deprecated_name: Option<&'static str>, to: Vec<LintId>, ) { let new = self .lint_groups - .insert(name, LintGroup { lint_ids: to, from_plugin, depr: None }) + .insert(name, LintGroup { lint_ids: to, is_loaded, depr: None }) .is_none(); if let Some(deprecated) = deprecated_name { self.lint_groups.insert( deprecated, LintGroup { lint_ids: vec![], - from_plugin, + is_loaded, depr: Some(LintAlias { name, silent: false }), }, ); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d61c59af1e0..54adedd3c09 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -10,7 +10,7 @@ //! all other analyses. The `LintPass`es built into rustc are defined //! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. -//! rustc can also load user-defined lint plugins via the plugin mechanism. +//! rustc can also load external lint plugins, as is done for Clippy. //! //! Some of rustc's lints are defined elsewhere in the compiler and work by //! calling `add_lint()` on the overall `Session` object. This works when diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7ba589c3b5a..878c1a65dbf 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -321,7 +321,7 @@ pub struct Lint { pub future_incompatible: Option<FutureIncompatibleInfo>, - pub is_plugin: bool, + pub is_loaded: bool, /// `Some` if this lint is feature gated, otherwise `None`. pub feature_gate: Option<Symbol>, @@ -399,7 +399,7 @@ impl Lint { default_level: Level::Forbid, desc: "", edition_lint_opts: None, - is_plugin: false, + is_loaded: false, report_in_external_macro: false, future_incompatible: None, feature_gate: None, @@ -735,7 +735,7 @@ macro_rules! declare_lint { name: stringify!($NAME), default_level: $crate::$Level, desc: $desc, - is_plugin: false, + is_loaded: false, $($v: true,)* $(feature_gate: Some($gate),)? $(future_incompatible: Some($crate::FutureIncompatibleInfo { @@ -777,7 +777,7 @@ macro_rules! declare_tool_lint { edition_lint_opts: None, report_in_external_macro: $external, future_incompatible: None, - is_plugin: true, + is_loaded: true, $(feature_gate: Some($gate),)? crate_level_only: false, ..$crate::Lint::default_fields_for_macro() diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 633004fdddf..d1815717e22 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -196,9 +196,6 @@ metadata_newer_crate_version = metadata_no_crate_with_triple = couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info} -metadata_no_dylib_plugin = - plugin `{$crate_name}` only found in rlib format, but must be available in dylib format - metadata_no_link_mod_override = overriding linking modifiers from command line is not supported diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 59b35a6406d..70daee291e7 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -683,14 +683,6 @@ impl IntoDiagnostic<'_> for CannotFindCrate { } #[derive(Diagnostic)] -#[diag(metadata_no_dylib_plugin, code = "E0457")] -pub struct NoDylibPlugin { - #[primary_span] - pub span: Span, - pub crate_name: Symbol, -} - -#[derive(Diagnostic)] #[diag(metadata_crate_location_unknown_type)] pub struct CrateLocationUnknownType<'a> { #[primary_span] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 3062939d8da..3a99ddc1b7a 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; -use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_fs_util::try_canonicalize; use rustc_session::config; use rustc_session::cstore::{CrateSource, MetadataLoader}; @@ -857,46 +857,6 @@ fn get_metadata_section<'p>( } } -/// Look for a plugin registrar. Returns its library path and crate disambiguator. -pub fn find_plugin_registrar( - sess: &Session, - metadata_loader: &dyn MetadataLoader, - span: Span, - name: Symbol, -) -> PathBuf { - find_plugin_registrar_impl(sess, metadata_loader, name).unwrap_or_else(|err| { - // `core` is always available if we got as far as loading plugins. - err.report(sess, span, false); - FatalError.raise() - }) -} - -fn find_plugin_registrar_impl<'a>( - sess: &'a Session, - metadata_loader: &dyn MetadataLoader, - name: Symbol, -) -> Result<PathBuf, CrateError> { - info!("find plugin registrar `{}`", name); - let mut locator = CrateLocator::new( - sess, - metadata_loader, - name, - false, // is_rlib - None, // hash - None, // extra_filename - true, // is_host - PathKind::Crate, - ); - - match locator.maybe_load_library_crate()? { - Some(library) => match library.source.dylib { - Some(dylib) => Ok(dylib.0), - None => Err(CrateError::NonDylibPlugin(name)), - }, - None => Err(locator.into_error(None)), - } -} - /// A diagnostic function for dumping crate metadata to an output stream. pub fn list_file_metadata( target: &Target, @@ -964,7 +924,6 @@ pub(crate) enum CrateError { DlOpen(String), DlSym(String), LocatorCombined(Box<CombinedLocatorError>), - NonDylibPlugin(Symbol), NotFound(Symbol), } @@ -1134,9 +1093,6 @@ impl CrateError { }); } } - CrateError::NonDylibPlugin(crate_name) => { - sess.emit_err(errors::NoDylibPlugin { span, crate_name }); - } CrateError::NotFound(crate_name) => { sess.emit_err(errors::CannotFindCrate { span, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 1d573a746b9..dd761b4e312 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -69,6 +69,7 @@ macro_rules! arena_types { [] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>, [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>, [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>, + [] canonical_goal_evaluation: rustc_middle::traits::solve::inspect::GoalEvaluationStep<'tcx>, [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>, [] type_op_subtype: rustc_middle::infer::canonical::Canonical<'tcx, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 0b5426c3bb1..64b63f4c5eb 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -222,7 +222,7 @@ pub enum CanonicalVarKind<'tcx> { Effect, /// A "placeholder" that represents "any const". - PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>), + PlaceholderConst(ty::PlaceholderConst, Ty<'tcx>), } impl<'tcx> CanonicalVarKind<'tcx> { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 59849e8eb40..eada116f896 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -9,17 +9,15 @@ use rustc_session::lint::{ FutureIncompatibilityReason, Level, Lint, LintId, }; use rustc_session::Session; -use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::{DesugaringKind, ExpnKind}; -use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; +use rustc_span::hygiene::{ExpnKind, MacroKind}; +use rustc_span::{symbol, DesugaringKind, Span, Symbol, DUMMY_SP}; use crate::ty::TyCtxt; /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)] pub enum LintLevelSource { - /// Lint is at the default level as declared - /// in rustc or a plugin. + /// Lint is at the default level as declared in rustc. Default, /// Lint level was set by an attribute. diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 403e80bd34c..91fdf0b3129 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -10,8 +10,8 @@ use rustc_hir::ItemId; use rustc_index::Idx; use rustc_query_system::ich::StableHashingContext; use rustc_session::config::OptLevel; -use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; +use rustc_span::Span; use std::fmt; use std::hash::Hash; diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 975e3e3ac62..3cceb8b2c59 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -10,7 +10,7 @@ use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; -use rustc_span::source_map::Span; +use rustc_span::Span; pub mod type_op { use crate::ty::fold::TypeFoldable; diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs index 9898b0019bb..e9e9cc418a6 100644 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ b/compiler/rustc_middle/src/traits/solve/cache.rs @@ -1,4 +1,4 @@ -use super::{CanonicalInput, QueryResult}; +use super::{inspect, CanonicalInput, QueryResult}; use crate::ty::TyCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lock; @@ -14,8 +14,10 @@ pub struct EvaluationCache<'tcx> { map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>, } +#[derive(PartialEq, Eq)] pub struct CacheData<'tcx> { pub result: QueryResult<'tcx>, + pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>, pub reached_depth: usize, pub encountered_overflow: bool, } @@ -24,22 +26,33 @@ impl<'tcx> EvaluationCache<'tcx> { /// Insert a final result into the global cache. pub fn insert( &self, + tcx: TyCtxt<'tcx>, key: CanonicalInput<'tcx>, + proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>, reached_depth: usize, - did_overflow: bool, + encountered_overflow: bool, cycle_participants: FxHashSet<CanonicalInput<'tcx>>, dep_node: DepNodeIndex, result: QueryResult<'tcx>, ) { let mut map = self.map.borrow_mut(); let entry = map.entry(key).or_default(); - let data = WithDepNode::new(dep_node, result); + let data = WithDepNode::new(dep_node, QueryData { result, proof_tree }); entry.cycle_participants.extend(cycle_participants); - if did_overflow { + if encountered_overflow { entry.with_overflow.insert(reached_depth, data); } else { entry.success = Some(Success { data, reached_depth }); } + + if cfg!(debug_assertions) { + drop(map); + if Some(CacheData { result, proof_tree, reached_depth, encountered_overflow }) + != self.get(tcx, key, |_| false, Limit(reached_depth)) + { + bug!("unable to retrieve inserted element from cache: {key:?}"); + } + } } /// Try to fetch a cached result, checking the recursion limit @@ -62,27 +75,39 @@ impl<'tcx> EvaluationCache<'tcx> { if let Some(ref success) = entry.success { if available_depth.value_within_limit(success.reached_depth) { + let QueryData { result, proof_tree } = success.data.get(tcx); return Some(CacheData { - result: success.data.get(tcx), + result, + proof_tree, reached_depth: success.reached_depth, encountered_overflow: false, }); } } - entry.with_overflow.get(&available_depth.0).map(|e| CacheData { - result: e.get(tcx), - reached_depth: available_depth.0, - encountered_overflow: true, + entry.with_overflow.get(&available_depth.0).map(|e| { + let QueryData { result, proof_tree } = e.get(tcx); + CacheData { + result, + proof_tree, + reached_depth: available_depth.0, + encountered_overflow: true, + } }) } } struct Success<'tcx> { - data: WithDepNode<QueryResult<'tcx>>, + data: WithDepNode<QueryData<'tcx>>, reached_depth: usize, } +#[derive(Clone, Copy)] +pub struct QueryData<'tcx> { + pub result: QueryResult<'tcx>, + pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>, +} + /// The cache entry for a goal `CanonicalInput`. /// /// This contains results whose computation never hit the @@ -96,5 +121,5 @@ struct CacheEntry<'tcx> { /// See the doc comment of `StackEntry::cycle_participants` for more /// details. cycle_participants: FxHashSet<CanonicalInput<'tcx>>, - with_overflow: FxHashMap<usize, WithDepNode<QueryResult<'tcx>>>, + with_overflow: FxHashMap<usize, WithDepNode<QueryData<'tcx>>>, } diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index e7e40bee6b9..a5916c4ab85 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -42,12 +42,6 @@ pub struct State<'tcx, T> { pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>; -#[derive(Debug, Eq, PartialEq)] -pub enum CacheHit { - Provisional, - Global, -} - /// When evaluating the root goals we also store the /// original values for the `CanonicalVarValues` of the /// canonicalized goal. We use this to map any [CanonicalState] @@ -78,8 +72,8 @@ pub struct CanonicalGoalEvaluation<'tcx> { #[derive(Eq, PartialEq)] pub enum CanonicalGoalEvaluationKind<'tcx> { Overflow, - CacheHit(CacheHit), - Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> }, + CycleInStack, + Evaluation { revisions: &'tcx [GoalEvaluationStep<'tcx>] }, } impl Debug for GoalEvaluation<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 5733be00adf..4b73d8e41a1 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -74,13 +74,10 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { CanonicalGoalEvaluationKind::Overflow => { writeln!(self.f, "OVERFLOW: {:?}", eval.result) } - CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => { - writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result) + CanonicalGoalEvaluationKind::CycleInStack => { + writeln!(self.f, "CYCLE IN STACK: {:?}", eval.result) } - CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => { - writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result) - } - CanonicalGoalEvaluationKind::Uncached { revisions } => { + CanonicalGoalEvaluationKind::Evaluation { revisions } => { for (n, step) in revisions.iter().enumerate() { writeln!(self.f, "REVISION {n}")?; self.nested(|this| this.format_evaluation_step(step))?; diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index cfacccd2679..af5ffc20d48 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -84,7 +84,7 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn new_placeholder( tcx: TyCtxt<'tcx>, - placeholder: ty::PlaceholderConst<'tcx>, + placeholder: ty::PlaceholderConst, ty: Ty<'tcx>, ) -> Const<'tcx> { Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 68812bba42f..551c4a15dd0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -106,7 +106,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Const = ty::Const<'tcx>; type InferConst = ty::InferConst; type AliasConst = ty::UnevaluatedConst<'tcx>; - type PlaceholderConst = ty::PlaceholderConst<'tcx>; + type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 7a782b2c249..77a50fa9276 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -274,6 +274,8 @@ pub fn suggest_constraining_type_params<'a>( span, if span_to_replace.is_some() { constraint.clone() + } else if constraint.starts_with("<") { + constraint.to_string() } else if bound_list_non_empty { format!(" + {constraint}") } else { diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 7895993ccff..3371ea3bec8 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -20,8 +20,8 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - // If there's nothing to erase avoid performing the query at all - if !value.has_type_flags(TypeFlags::HAS_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { + // If there's nothing to erase or anonymize, avoid performing the query at all + if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { return value; } debug!("erase_regions({:?})", value); diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index a348e9f608a..ec36bdc5a51 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -34,26 +34,6 @@ impl FlagComputation { result.flags } - pub fn bound_var_flags(vars: &ty::List<ty::BoundVariableKind>) -> FlagComputation { - let mut computation = FlagComputation::new(); - - for bv in vars { - match bv { - ty::BoundVariableKind::Ty(_) => { - computation.flags |= TypeFlags::HAS_TY_LATE_BOUND; - } - ty::BoundVariableKind::Region(_) => { - computation.flags |= TypeFlags::HAS_RE_LATE_BOUND; - } - ty::BoundVariableKind::Const => { - computation.flags |= TypeFlags::HAS_CT_LATE_BOUND; - } - } - } - - computation - } - fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -77,7 +57,11 @@ impl FlagComputation { where F: FnOnce(&mut Self, T), { - let mut computation = FlagComputation::bound_var_flags(value.bound_vars()); + let mut computation = FlagComputation::new(); + + if !value.bound_vars().is_empty() { + computation.add_flags(TypeFlags::HAS_BINDER_VARS); + } f(&mut computation, value.skip_binder()); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 739d4fa886e..f6ef1783aa4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1527,7 +1527,7 @@ pub struct BoundConst<'tcx> { pub ty: Ty<'tcx>, } -pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>; +pub type PlaceholderConst = Placeholder<BoundVar>; /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9430b3ee544..a251518d145 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1107,8 +1107,10 @@ impl<'tcx> Ty<'tcx> { // This doesn't depend on regions, so try to minimize distinct // query keys used. // If normalization fails, we just use `query_ty`. - let query_ty = - tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty); + debug_assert!(!param_env.has_infer()); + let query_ty = tcx + .try_normalize_erasing_regions(param_env, query_ty) + .unwrap_or_else(|_| tcx.erase_regions(query_ty)); tcx.needs_drop_raw(param_env.and(query_ty)) } @@ -1297,7 +1299,6 @@ pub fn needs_drop_components<'tcx>( | ty::FnDef(..) | ty::FnPtr(_) | ty::Char - | ty::CoroutineWitness(..) | ty::RawPtr(_) | ty::Ref(..) | ty::Str => Ok(SmallVec::new()), @@ -1337,7 +1338,8 @@ pub fn needs_drop_components<'tcx>( | ty::Placeholder(..) | ty::Infer(_) | ty::Closure(..) - | ty::Coroutine(..) => Ok(smallvec![ty]), + | ty::Coroutine(..) + | ty::CoroutineWitness(..) => Ok(smallvec![ty]), } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index ab0999b3f19..8fc5c030277 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -494,15 +494,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor { &mut self, t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { - // If we're looking for any of the HAS_*_LATE_BOUND flags, we need to - // additionally consider the bound vars on the binder itself, even if - // the contents of a the binder (e.g. a `TraitRef`) doesn't reference - // the bound vars. - if self.flags.intersects(TypeFlags::HAS_LATE_BOUND) { - let bound_var_flags = FlagComputation::bound_var_flags(t.bound_vars()); - if bound_var_flags.flags.intersects(self.flags) { - return ControlFlow::Break(FoundFlags); - } + // If we're looking for the HAS_BINDER_VARS flag, check if the + // binder has vars. This won't be present in the binder's bound + // value, so we need to check here too. + if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() { + return ControlFlow::Break(FoundFlags); } t.super_visit_with(self) diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 32711c23dc4..563851f712c 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -221,6 +221,11 @@ mir_build_non_exhaustive_omitted_pattern = some variants are not matched explici .help = ensure that all variants are matched explicitly by adding the suggested match arms .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found +mir_build_non_exhaustive_omitted_pattern_lint_on_arm = the lint level must be set on the whole match + .help = it no longer has any effect to set the lint level on an individual match arm + .label = remove this attribute + .suggestion = set the lint level on the whole match + mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty .def_note = `{$peeled_ty}` defined here .type_note = the matched value is of type `{$ty}` diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index c3e1b55e463..a43aae6f449 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -856,7 +856,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::InlineConstant { ref subpattern, .. } => { - self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f) + self.visit_primary_bindings(subpattern, pattern_user_ty, f) } PatKind::Leaf { ref subpatterns } => { diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 5bfce3ab510..c4eed5532ee 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -789,6 +789,18 @@ pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { pub uncovered: Uncovered<'tcx>, } +#[derive(LintDiagnostic)] +#[diag(mir_build_non_exhaustive_omitted_pattern_lint_on_arm)] +#[help] +pub(crate) struct NonExhaustiveOmittedPatternLintOnArm { + #[label] + pub lint_span: Span, + #[suggestion(code = "#[{lint_level}({lint_name})]\n", applicability = "maybe-incorrect")] + pub suggest_lint_on_match: Option<Span>, + pub lint_level: &'static str, + pub lint_name: &'static str, +} + #[derive(Subdiagnostic)] #[label(mir_build_uncovered)] pub(crate) struct Uncovered<'tcx> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 933653e708e..8c3d09c19a1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -9,9 +9,7 @@ use rustc_arena::TypedArena; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; @@ -44,7 +42,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err for param in thir.params.iter() { if let Some(box ref pattern) = param.pat { - visitor.check_irrefutable(pattern, "function argument", None); + visitor.check_binding_is_irrefutable(pattern, "function argument", None); } } visitor.error @@ -58,7 +56,7 @@ fn create_e0004( struct_span_err!(sess, sp, E0004, "{}", &error_message) } -#[derive(PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] enum RefutableFlag { Irrefutable, Refutable, @@ -68,24 +66,30 @@ use RefutableFlag::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum LetSource { None, + PlainLet, IfLet, IfLetGuard, LetElse, WhileLet, } -struct MatchVisitor<'a, 'p, 'tcx> { +struct MatchVisitor<'thir, 'p, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - thir: &'a Thir<'tcx>, + thir: &'thir Thir<'tcx>, lint_level: HirId, let_source: LetSource, pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>, + /// Tracks if we encountered an error while checking this body. That the first function to + /// report it stores it here. Some functions return `Result` to allow callers to short-circuit + /// on error, but callers don't need to store it here again. error: Result<(), ErrorGuaranteed>, } -impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { - fn thir(&self) -> &'a Thir<'tcx> { +// Visitor for a thir body. This calls `check_match`, `check_let` and `check_let_chain` as +// appropriate. +impl<'thir, 'tcx> Visitor<'thir, 'tcx> for MatchVisitor<'thir, '_, 'tcx> { + fn thir(&self) -> &'thir Thir<'tcx> { self.thir } @@ -100,7 +104,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { } Some(Guard::IfLet(ref pat, expr)) => { this.with_let_source(LetSource::IfLetGuard, |this| { - this.check_let(pat, expr, LetSource::IfLetGuard, pat.span); + this.check_let(pat, Some(expr), pat.span); this.visit_pat(pat); this.visit_expr(&this.thir[expr]); }); @@ -148,10 +152,18 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { self.check_match(scrutinee, arms, source, ex.span); } ExprKind::Let { box ref pat, expr } => { - self.check_let(pat, expr, self.let_source, ex.span); + self.check_let(pat, Some(expr), ex.span); } - ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { - self.check_let_chain(self.let_source, ex.span, lhs, rhs); + ExprKind::LogicalOp { op: LogicalOp::And, .. } + if !matches!(self.let_source, LetSource::None) => + { + let mut chain_refutabilities = Vec::new(); + let Ok(()) = self.visit_land(ex, &mut chain_refutabilities) else { return }; + // If at least one of the operands is a `let ... = ...`. + if chain_refutabilities.iter().any(|x| x.is_some()) { + self.check_let_chain(chain_refutabilities, ex.span); + } + return; } _ => {} }; @@ -159,33 +171,27 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { } fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - let old_lint_level = self.lint_level; match stmt.kind { StmtKind::Let { box ref pattern, initializer, else_block, lint_level, span, .. } => { - if let LintLevel::Explicit(lint_level) = lint_level { - self.lint_level = lint_level; - } - - if let Some(initializer) = initializer - && else_block.is_some() - { - self.check_let(pattern, initializer, LetSource::LetElse, span); - } - - if else_block.is_none() { - self.check_irrefutable(pattern, "local binding", Some(span)); - } + self.with_lint_level(lint_level, |this| { + let let_source = + if else_block.is_some() { LetSource::LetElse } else { LetSource::PlainLet }; + this.with_let_source(let_source, |this| { + this.check_let(pattern, initializer, span) + }); + visit::walk_stmt(this, stmt); + }); + } + StmtKind::Expr { .. } => { + visit::walk_stmt(self, stmt); } - _ => {} } - visit::walk_stmt(self, stmt); - self.lint_level = old_lint_level; } } -impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { +impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { #[instrument(level = "trace", skip(self, f))] fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { let old_let_source = self.let_source; @@ -194,53 +200,127 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { self.let_source = old_let_source; } - fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) { + fn with_lint_level<T>( + &mut self, + new_lint_level: LintLevel, + f: impl FnOnce(&mut Self) -> T, + ) -> T { if let LintLevel::Explicit(hir_id) = new_lint_level { let old_lint_level = self.lint_level; self.lint_level = hir_id; - f(self); + let ret = f(self); self.lint_level = old_lint_level; + ret } else { - f(self); + f(self) } } - fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) { - pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); - check_for_bindings_named_same_as_variants(self, pat, rf); + /// Visit a nested chain of `&&`. Used for if-let chains. This must call `visit_expr` on the + /// subexpressions we are not handling ourselves. + fn visit_land( + &mut self, + ex: &Expr<'tcx>, + accumulator: &mut Vec<Option<(Span, RefutableFlag)>>, + ) -> Result<(), ErrorGuaranteed> { + match ex.kind { + ExprKind::Scope { value, lint_level, .. } => self.with_lint_level(lint_level, |this| { + this.visit_land(&this.thir[value], accumulator) + }), + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + // We recurse into the lhs only, because `&&` chains associate to the left. + let res_lhs = self.visit_land(&self.thir[lhs], accumulator); + let res_rhs = self.visit_land_rhs(&self.thir[rhs])?; + accumulator.push(res_rhs); + res_lhs + } + _ => { + let res = self.visit_land_rhs(ex)?; + accumulator.push(res); + Ok(()) + } + } + } + + /// Visit the right-hand-side of a `&&`. Used for if-let chains. Returns `Some` if the + /// expression was ultimately a `let ... = ...`, and `None` if it was a normal boolean + /// expression. This must call `visit_expr` on the subexpressions we are not handling ourselves. + fn visit_land_rhs( + &mut self, + ex: &Expr<'tcx>, + ) -> Result<Option<(Span, RefutableFlag)>, ErrorGuaranteed> { + match ex.kind { + ExprKind::Scope { value, lint_level, .. } => { + self.with_lint_level(lint_level, |this| this.visit_land_rhs(&this.thir[value])) + } + ExprKind::Let { box ref pat, expr } => { + self.with_let_source(LetSource::None, |this| { + this.visit_expr(&this.thir()[expr]); + }); + Ok(Some((ex.span, self.is_let_irrefutable(pat)?))) + } + _ => { + self.with_let_source(LetSource::None, |this| { + this.visit_expr(ex); + }); + Ok(None) + } + } } fn lower_pattern( - &self, - cx: &mut MatchCheckCtxt<'p, 'tcx>, - pattern: &Pat<'tcx>, - ) -> &'p DeconstructedPat<'p, 'tcx> { - cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) + &mut self, + cx: &MatchCheckCtxt<'p, 'tcx>, + pat: &Pat<'tcx>, + ) -> Result<&'p DeconstructedPat<'p, 'tcx>, ErrorGuaranteed> { + if let Err(err) = pat.pat_error_reported() { + self.error = Err(err); + Err(err) + } else { + // Check the pattern for some things unrelated to exhaustiveness. + let refutable = if cx.refutable { Refutable } else { Irrefutable }; + pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); + pat.walk_always(|pat| check_for_bindings_named_same_as_variants(self, pat, refutable)); + Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pat))) + } } - fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> { + fn new_cx( + &self, + refutability: RefutableFlag, + match_span: Option<Span>, + ) -> MatchCheckCtxt<'p, 'tcx> { + let refutable = match refutability { + Irrefutable => false, + Refutable => true, + }; MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, - module: self.tcx.parent_module(hir_id).to_def_id(), + module: self.tcx.parent_module(self.lint_level).to_def_id(), pattern_arena: &self.pattern_arena, + match_span, refutable, } } #[instrument(level = "trace", skip(self))] - fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: ExprId, source: LetSource, span: Span) { - if let LetSource::None = source { - return; - } - if let Err(err) = pat.pat_error_reported() { - self.error = Err(err); - return; + fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: Option<ExprId>, span: Span) { + assert!(self.let_source != LetSource::None); + if let LetSource::PlainLet = self.let_source { + self.check_binding_is_irrefutable(pat, "local binding", Some(span)) + } else { + let Ok(refutability) = self.is_let_irrefutable(pat) else { return }; + if matches!(refutability, Irrefutable) { + report_irrefutable_let_patterns( + self.tcx, + self.lint_level, + self.let_source, + 1, + span, + ); + } } - self.check_patterns(pat, Refutable); - let mut cx = self.new_cx(self.lint_level, true); - let tpat = self.lower_pattern(&mut cx, pat); - self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); } fn check_match( @@ -250,33 +330,22 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { source: hir::MatchSource, expr_span: Span, ) { - let mut cx = self.new_cx(self.lint_level, true); + let cx = self.new_cx(Refutable, Some(expr_span)); + let mut tarms = Vec::with_capacity(arms.len()); for &arm in arms { - // Check the arm for some things unrelated to exhaustiveness. let arm = &self.thir.arms[arm]; - self.with_lint_level(arm.lint_level, |this| { - this.check_patterns(&arm.pattern, Refutable); + let got_error = self.with_lint_level(arm.lint_level, |this| { + let Ok(pat) = this.lower_pattern(&cx, &arm.pattern) else { return true }; + let arm = MatchArm { pat, hir_id: this.lint_level, has_guard: arm.guard.is_some() }; + tarms.push(arm); + false }); - if let Err(err) = arm.pattern.pat_error_reported() { - self.error = Err(err); + if got_error { return; } } - let tarms: Vec<_> = arms - .iter() - .map(|&arm| { - let arm = &self.thir.arms[arm]; - let hir_id = match arm.lint_level { - LintLevel::Explicit(hir_id) => hir_id, - LintLevel::Inherited => self.lint_level, - }; - let pat = self.lower_pattern(&mut cx, &arm.pattern); - MatchArm { pat, hir_id, has_guard: arm.guard.is_some() } - }) - .collect(); - let scrut = &self.thir[scrut]; let scrut_ty = scrut.ty; let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span); @@ -303,118 +372,37 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop)); let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() }; let [pat_field] = &subpatterns[..] else { bug!() }; - self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None); + self.check_binding_is_irrefutable(&pat_field.pattern, "`for` loop binding", None); } else { - self.error = Err(non_exhaustive_match( + self.error = Err(report_non_exhaustive_match( &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span, )); } } } - fn check_let_reachability( - &mut self, - cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat_id: HirId, - source: LetSource, - pat: &'p DeconstructedPat<'p, 'tcx>, - span: Span, - ) { - if is_let_irrefutable(cx, pat_id, pat) { - irrefutable_let_patterns(cx.tcx, pat_id, source, 1, span); - } - } - #[instrument(level = "trace", skip(self))] fn check_let_chain( &mut self, - let_source: LetSource, - top_expr_span: Span, - mut lhs: ExprId, - rhs: ExprId, + chain_refutabilities: Vec<Option<(Span, RefutableFlag)>>, + whole_chain_span: Span, ) { - if let LetSource::None = let_source { - return; - } - - // Lint level enclosing the next `lhs`. - let mut cur_lint_level = self.lint_level; - - // Obtain the refutabilities of all exprs in the chain, - // and record chain members that aren't let exprs. - let mut chain_refutabilities = Vec::new(); - - let mut error = Ok(()); - let mut add = |expr: ExprId, mut local_lint_level| { - // `local_lint_level` is the lint level enclosing the pattern inside `expr`. - let mut expr = &self.thir[expr]; - debug!(?expr, ?local_lint_level, "add"); - // Fast-forward through scopes. - while let ExprKind::Scope { value, lint_level, .. } = expr.kind { - if let LintLevel::Explicit(hir_id) = lint_level { - local_lint_level = hir_id - } - expr = &self.thir[value]; - } - debug!(?expr, ?local_lint_level, "after scopes"); - match expr.kind { - ExprKind::Let { box ref pat, expr: _ } => { - if let Err(err) = pat.pat_error_reported() { - error = Err(err); - return None; - } - let mut ncx = self.new_cx(local_lint_level, true); - let tpat = self.lower_pattern(&mut ncx, pat); - let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); - Some((expr.span, refutable)) - } - _ => None, - } - }; - - // Let chains recurse on the left, so we start by adding the rightmost. - chain_refutabilities.push(add(rhs, cur_lint_level)); + assert!(self.let_source != LetSource::None); - loop { - while let ExprKind::Scope { value, lint_level, .. } = self.thir[lhs].kind { - if let LintLevel::Explicit(hir_id) = lint_level { - cur_lint_level = hir_id - } - lhs = value; - } - if let ExprKind::LogicalOp { op: LogicalOp::And, lhs: new_lhs, rhs: expr } = - self.thir[lhs].kind - { - chain_refutabilities.push(add(expr, cur_lint_level)); - lhs = new_lhs; - } else { - chain_refutabilities.push(add(lhs, cur_lint_level)); - break; - } - } - debug!(?chain_refutabilities); - chain_refutabilities.reverse(); - - if error.is_err() { - self.error = error; - return; - } - - // Third, emit the actual warnings. - if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) { + if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, Irrefutable)))) { // The entire chain is made up of irrefutable `let` statements - irrefutable_let_patterns( + report_irrefutable_let_patterns( self.tcx, self.lint_level, - let_source, + self.let_source, chain_refutabilities.len(), - top_expr_span, + whole_chain_span, ); return; } if let Some(until) = - chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) + chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, Irrefutable)))) && until > 0 { // The chain has a non-zero prefix of irrefutable `let` statements. @@ -425,7 +413,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // so can't always be moved out. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) { + if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) { // Emit the lint let prefix = &chain_refutabilities[..until]; let span_start = prefix[0].unwrap().0; @@ -442,7 +430,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } if let Some(from) = - chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) + chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, Irrefutable)))) && from != (chain_refutabilities.len() - 1) { // The chain has a non-empty suffix of irrefutable `let` statements @@ -460,28 +448,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } } - #[instrument(level = "trace", skip(self))] - fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) { - // If we got errors while lowering, don't emit anything more. - if let Err(err) = pat.pat_error_reported() { - self.error = Err(err); - return; - } + fn analyze_binding( + &mut self, + pat: &Pat<'tcx>, + refutability: RefutableFlag, + ) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> { + let cx = self.new_cx(refutability, None); + let pat = self.lower_pattern(&cx, pat)?; + let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, self.lint_level, pat.ty(), pat.span()); + Ok((cx, report)) + } - let mut cx = self.new_cx(self.lint_level, false); + fn is_let_irrefutable(&mut self, pat: &Pat<'tcx>) -> Result<RefutableFlag, ErrorGuaranteed> { + let (cx, report) = self.analyze_binding(pat, Refutable)?; + // Report if the pattern is unreachable, which can only occur when the type is uninhabited. + // This also reports unreachable sub-patterns. + report_arm_reachability(&cx, &report); + // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is + // irrefutable. + Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable }) + } - let pattern = self.lower_pattern(&mut cx, pat); - let pattern_ty = pattern.ty(); - let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; - let report = - compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty, pattern.span()); + #[instrument(level = "trace", skip(self))] + fn check_binding_is_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) { + let pattern_ty = pat.ty; - // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We - // only care about exhaustiveness here. + let Ok((cx, report)) = self.analyze_binding(pat, Irrefutable) else { return }; let witnesses = report.non_exhaustiveness_witnesses; if witnesses.is_empty() { // The pattern is irrefutable. - self.check_patterns(pat, Irrefutable); return; } @@ -528,30 +524,20 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { }); }; - let adt_defined_here = try { - let ty = pattern_ty.peel_refs(); - let ty::Adt(def, _) = ty.kind() else { None? }; - let adt_def_span = cx.tcx.hir().get_if_local(def.did())?.ident()?.span; - let mut variants = vec![]; - - for span in maybe_point_at_variant(&cx, *def, witnesses.iter().take(5)) { - variants.push(Variant { span }); - } - AdtDefinedHere { adt_def_span, ty, variants } - }; + let adt_defined_here = report_adt_defined_here(self.tcx, pattern_ty, &witnesses, false); // Emit an extra note if the first uncovered witness would be uninhabited // if we disregard visibility. - let witness_1_is_privately_uninhabited = if cx.tcx.features().exhaustive_patterns + let witness_1_is_privately_uninhabited = if self.tcx.features().exhaustive_patterns && let Some(witness_1) = witnesses.get(0) && let ty::Adt(adt, args) = witness_1.ty().kind() && adt.is_enum() && let Constructor::Variant(variant_index) = witness_1.ctor() { let variant = adt.variant(*variant_index); - let inhabited = variant.inhabited_predicate(cx.tcx, *adt).instantiate(cx.tcx, args); - assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module)); - !inhabited.apply_ignore_module(cx.tcx, cx.param_env) + let inhabited = variant.inhabited_predicate(self.tcx, *adt).instantiate(self.tcx, args); + assert!(inhabited.apply(self.tcx, cx.param_env, cx.module)); + !inhabited.apply_ignore_module(self.tcx, cx.param_env) } else { false }; @@ -572,70 +558,154 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } } -fn check_for_bindings_named_same_as_variants( - cx: &MatchVisitor<'_, '_, '_>, - pat: &Pat<'_>, - rf: RefutableFlag, -) { - pat.walk_always(|p| { - if let PatKind::Binding { - name, - mode: BindingMode::ByValue, - mutability: Mutability::Not, - subpattern: None, - ty, - .. - } = p.kind - && let ty::Adt(edef, _) = ty.peel_refs().kind() - && edef.is_enum() - && edef - .variants() - .iter() - .any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const)) - { - let variant_count = edef.variants().len(); - let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); - cx.tcx.emit_spanned_lint( - BINDINGS_WITH_VARIANT_NAME, - cx.lint_level, - p.span, - BindingsWithVariantName { - // If this is an irrefutable pattern, and there's > 1 variant, - // then we can't actually match on this. Applying the below - // suggestion would produce code that breaks on `check_irrefutable`. - suggestion: if rf == Refutable || variant_count == 1 { - Some(p.span) - } else { - None - }, - ty_path, +/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. +/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. +/// +/// For example, this would reject: +/// - `ref x @ Some(ref mut y)`, +/// - `ref mut x @ Some(ref y)`, +/// - `ref mut x @ Some(ref mut y)`, +/// - `ref mut? x @ Some(y)`, and +/// - `x @ Some(ref mut? y)`. +/// +/// This analysis is *not* subsumed by NLL. +fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { + // Extract `sub` in `binding @ sub`. + let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { + return; + }; + + let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + + let sess = cx.tcx.sess; + + // Get the binding move, extract the mutability if by-ref. + let mut_outer = match mode { + BindingMode::ByValue if is_binding_by_move(ty) => { + // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. + let mut conflicts_ref = Vec::new(); + sub.each_binding(|_, mode, _, span| match mode { + BindingMode::ByValue => {} + BindingMode::ByRef(_) => conflicts_ref.push(span), + }); + if !conflicts_ref.is_empty() { + sess.emit_err(BorrowOfMovedValue { + binding_span: pat.span, + conflicts_ref, name, - }, - ) + ty, + suggest_borrowing: Some(pat.span.shrink_to_lo()), + }); + } + return; + } + BindingMode::ByValue => return, + BindingMode::ByRef(m) => m.mutability(), + }; + + // We now have `ref $mut_outer binding @ sub` (semantically). + // Recurse into each binding in `sub` and find mutability or move conflicts. + let mut conflicts_move = Vec::new(); + let mut conflicts_mut_mut = Vec::new(); + let mut conflicts_mut_ref = Vec::new(); + sub.each_binding(|name, mode, ty, span| { + match mode { + BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { + // Both sides are `ref`. + (Mutability::Not, Mutability::Not) => {} + // 2x `ref mut`. + (Mutability::Mut, Mutability::Mut) => { + conflicts_mut_mut.push(Conflict::Mut { span, name }) + } + (Mutability::Not, Mutability::Mut) => { + conflicts_mut_ref.push(Conflict::Mut { span, name }) + } + (Mutability::Mut, Mutability::Not) => { + conflicts_mut_ref.push(Conflict::Ref { span, name }) + } + }, + BindingMode::ByValue if is_binding_by_move(ty) => { + conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. + } + BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. } }); -} -/// Checks for common cases of "catchall" patterns that may not be intended as such. -fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { - use Constructor::*; - match pat.ctor() { - Wildcard => true, - Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)), - _ => false, + let report_mut_mut = !conflicts_mut_mut.is_empty(); + let report_mut_ref = !conflicts_mut_ref.is_empty(); + let report_move_conflict = !conflicts_move.is_empty(); + + let mut occurrences = match mut_outer { + Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], + Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], + }; + occurrences.extend(conflicts_mut_mut); + occurrences.extend(conflicts_mut_ref); + occurrences.extend(conflicts_move); + + // Report errors if any. + if report_mut_mut { + // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. + sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences }); + } else if report_mut_ref { + // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. + match mut_outer { + Mutability::Mut => { + sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences }); + } + Mutability::Not => { + sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences }); + } + }; + } else if report_move_conflict { + // Report by-ref and by-move conflicts, e.g. `ref x @ y`. + sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences }); } } -fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) { - tcx.emit_spanned_lint( - UNREACHABLE_PATTERNS, - id, - span, - UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall }, - ); +fn check_for_bindings_named_same_as_variants( + cx: &MatchVisitor<'_, '_, '_>, + pat: &Pat<'_>, + rf: RefutableFlag, +) { + if let PatKind::Binding { + name, + mode: BindingMode::ByValue, + mutability: Mutability::Not, + subpattern: None, + ty, + .. + } = pat.kind + && let ty::Adt(edef, _) = ty.peel_refs().kind() + && edef.is_enum() + && edef + .variants() + .iter() + .any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const)) + { + let variant_count = edef.variants().len(); + let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); + cx.tcx.emit_spanned_lint( + BINDINGS_WITH_VARIANT_NAME, + cx.lint_level, + pat.span, + BindingsWithVariantName { + // If this is an irrefutable pattern, and there's > 1 variant, + // then we can't actually match on this. Applying the below + // suggestion would produce code that breaks on `check_binding_is_irrefutable`. + suggestion: if rf == Refutable || variant_count == 1 { + Some(pat.span) + } else { + None + }, + ty_path, + name, + }, + ) + } } -fn irrefutable_let_patterns( +fn report_irrefutable_let_patterns( tcx: TyCtxt<'_>, id: HirId, source: LetSource, @@ -649,7 +719,7 @@ fn irrefutable_let_patterns( } match source { - LetSource::None => bug!(), + LetSource::None | LetSource::PlainLet => bug!(), LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), @@ -657,34 +727,28 @@ fn irrefutable_let_patterns( } } -fn is_let_irrefutable<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat_id: HirId, - pat: &'p DeconstructedPat<'p, 'tcx>, -) -> bool { - let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty(), pat.span()); - - // Report if the pattern is unreachable, which can only occur when the type is uninhabited. - // This also reports unreachable sub-patterns though, so we can't just replace it with an - // `is_uninhabited` check. - report_arm_reachability(&cx, &report); - - // If the list of witnesses is empty, the match is exhaustive, - // i.e. the `if let` pattern is irrefutable. - report.non_exhaustiveness_witnesses.is_empty() -} - /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>, ) { + let report_unreachable_pattern = |span, hir_id, catchall: Option<Span>| { + cx.tcx.emit_spanned_lint( + UNREACHABLE_PATTERNS, + hir_id, + span, + UnreachablePattern { + span: if catchall.is_some() { Some(span) } else { None }, + catchall, + }, + ); + }; + use Reachability::*; let mut catchall = None; for (arm, is_useful) in report.arm_usefulness.iter() { match is_useful { - Unreachable => unreachable_pattern(cx.tcx, arm.pat.span(), arm.hir_id, catchall), + Unreachable => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall), Reachable(unreachables) if unreachables.is_empty() => {} // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Reachable(unreachables) => { @@ -692,7 +756,7 @@ fn report_arm_reachability<'p, 'tcx>( // Emit lints in the order in which they occur in the file. unreachables.sort_unstable(); for span in unreachables { - unreachable_pattern(cx.tcx, span, arm.hir_id, None); + report_unreachable_pattern(span, arm.hir_id, None); } } } @@ -702,26 +766,18 @@ fn report_arm_reachability<'p, 'tcx>( } } -fn collect_non_exhaustive_tys<'tcx>( - tcx: TyCtxt<'tcx>, - pat: &WitnessPat<'tcx>, - non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>, -) { - if matches!(pat.ctor(), Constructor::NonExhaustive) { - non_exhaustive_tys.insert(pat.ty()); - } - if let Constructor::IntRange(range) = pat.ctor() { - if range.is_beyond_boundaries(pat.ty(), tcx) { - // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. - non_exhaustive_tys.insert(pat.ty()); - } +/// Checks for common cases of "catchall" patterns that may not be intended as such. +fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { + use Constructor::*; + match pat.ctor() { + Wildcard => true, + Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)), + _ => false, } - pat.iter_fields() - .for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys)) } /// Report that a match is not exhaustive. -fn non_exhaustive_match<'p, 'tcx>( +fn report_non_exhaustive_match<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, thir: &Thir<'tcx>, scrut_ty: Ty<'tcx>, @@ -755,7 +811,14 @@ fn non_exhaustive_match<'p, 'tcx>( sp, format!("non-exhaustive patterns: {joined_patterns} not covered"), ); - err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); + err.span_label( + sp, + format!( + "pattern{} {} not covered", + rustc_errors::pluralize!(witnesses.len()), + joined_patterns + ), + ); patterns_len = witnesses.len(); pattern = if witnesses.len() < 4 { witnesses @@ -768,7 +831,17 @@ fn non_exhaustive_match<'p, 'tcx>( }; }; - adt_defined_here(cx, &mut err, scrut_ty, &witnesses); + // Point at the definition of non-covered `enum` variants. + if let Some(AdtDefinedHere { adt_def_span, ty, variants }) = + report_adt_defined_here(cx.tcx, scrut_ty, &witnesses, true) + { + let mut multi_span = MultiSpan::from_span(adt_def_span); + multi_span.push_span_label(adt_def_span, ""); + for Variant { span } in variants { + multi_span.push_span_label(span, "not covered"); + } + err.span_note(multi_span, format!("`{ty}` defined here")); + } err.note(format!("the matched value is of type `{}`", scrut_ty)); if !is_empty_match { @@ -910,7 +983,7 @@ fn non_exhaustive_match<'p, 'tcx>( err.emit() } -pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( +fn joined_uncovered_patterns<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, witnesses: &[WitnessPat<'tcx>], ) -> String { @@ -931,48 +1004,51 @@ pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( } } -pub(crate) fn pattern_not_covered_label( - witnesses: &[WitnessPat<'_>], - joined_patterns: &str, -) -> String { - format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns) +fn collect_non_exhaustive_tys<'tcx>( + tcx: TyCtxt<'tcx>, + pat: &WitnessPat<'tcx>, + non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>, +) { + if matches!(pat.ctor(), Constructor::NonExhaustive) { + non_exhaustive_tys.insert(pat.ty()); + } + if let Constructor::IntRange(range) = pat.ctor() { + if range.is_beyond_boundaries(pat.ty(), tcx) { + // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. + non_exhaustive_tys.insert(pat.ty()); + } + } + pat.iter_fields() + .for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys)) } -/// Point at the definition of non-covered `enum` variants. -fn adt_defined_here<'p, 'tcx>( - cx: &MatchCheckCtxt<'p, 'tcx>, - err: &mut Diagnostic, +fn report_adt_defined_here<'tcx>( + tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, witnesses: &[WitnessPat<'tcx>], -) { + point_at_non_local_ty: bool, +) -> Option<AdtDefinedHere<'tcx>> { let ty = ty.peel_refs(); - if let ty::Adt(def, _) = ty.kind() { - let mut spans = vec![]; - if witnesses.len() < 5 { - for sp in maybe_point_at_variant(cx, *def, witnesses.iter()) { - spans.push(sp); - } - } - let def_span = cx - .tcx - .hir() - .get_if_local(def.did()) - .and_then(|node| node.ident()) - .map(|ident| ident.span) - .unwrap_or_else(|| cx.tcx.def_span(def.did())); - let mut span: MultiSpan = - if spans.is_empty() { def_span.into() } else { spans.clone().into() }; - - span.push_span_label(def_span, ""); - for pat in spans { - span.push_span_label(pat, "not covered"); - } - err.span_note(span, format!("`{ty}` defined here")); + let ty::Adt(def, _) = ty.kind() else { + return None; + }; + let adt_def_span = + tcx.hir().get_if_local(def.did()).and_then(|node| node.ident()).map(|ident| ident.span); + let adt_def_span = if point_at_non_local_ty { + adt_def_span.unwrap_or_else(|| tcx.def_span(def.did())) + } else { + adt_def_span? + }; + + let mut variants = vec![]; + for span in maybe_point_at_variant(tcx, *def, witnesses.iter().take(5)) { + variants.push(Variant { span }); } + Some(AdtDefinedHere { adt_def_span, ty, variants }) } -fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( - cx: &MatchCheckCtxt<'p, 'tcx>, +fn maybe_point_at_variant<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, patterns: impl Iterator<Item = &'a WitnessPat<'tcx>>, ) -> Vec<Span> { @@ -985,7 +1061,7 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( { continue; } - let sp = def.variant(*variant_index).ident(cx.tcx).span; + let sp = def.variant(*variant_index).ident(tcx).span; if covered.contains(&sp) { // Don't point at variants that have already been covered due to other patterns to avoid // visual clutter. @@ -993,112 +1069,7 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( } covered.push(sp); } - covered.extend(maybe_point_at_variant(cx, def, pattern.iter_fields())); + covered.extend(maybe_point_at_variant(tcx, def, pattern.iter_fields())); } covered } - -/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. -/// -/// For example, this would reject: -/// - `ref x @ Some(ref mut y)`, -/// - `ref mut x @ Some(ref y)`, -/// - `ref mut x @ Some(ref mut y)`, -/// - `ref mut? x @ Some(y)`, and -/// - `x @ Some(ref mut? y)`. -/// -/// This analysis is *not* subsumed by NLL. -fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { - // Extract `sub` in `binding @ sub`. - let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { - return; - }; - - let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); - - let sess = cx.tcx.sess; - - // Get the binding move, extract the mutability if by-ref. - let mut_outer = match mode { - BindingMode::ByValue if is_binding_by_move(ty) => { - // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. - let mut conflicts_ref = Vec::new(); - sub.each_binding(|_, mode, _, span| match mode { - BindingMode::ByValue => {} - BindingMode::ByRef(_) => conflicts_ref.push(span), - }); - if !conflicts_ref.is_empty() { - sess.emit_err(BorrowOfMovedValue { - binding_span: pat.span, - conflicts_ref, - name, - ty, - suggest_borrowing: Some(pat.span.shrink_to_lo()), - }); - } - return; - } - BindingMode::ByValue => return, - BindingMode::ByRef(m) => m.mutability(), - }; - - // We now have `ref $mut_outer binding @ sub` (semantically). - // Recurse into each binding in `sub` and find mutability or move conflicts. - let mut conflicts_move = Vec::new(); - let mut conflicts_mut_mut = Vec::new(); - let mut conflicts_mut_ref = Vec::new(); - sub.each_binding(|name, mode, ty, span| { - match mode { - BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { - // Both sides are `ref`. - (Mutability::Not, Mutability::Not) => {} - // 2x `ref mut`. - (Mutability::Mut, Mutability::Mut) => { - conflicts_mut_mut.push(Conflict::Mut { span, name }) - } - (Mutability::Not, Mutability::Mut) => { - conflicts_mut_ref.push(Conflict::Mut { span, name }) - } - (Mutability::Mut, Mutability::Not) => { - conflicts_mut_ref.push(Conflict::Ref { span, name }) - } - }, - BindingMode::ByValue if is_binding_by_move(ty) => { - conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. - } - BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. - } - }); - - let report_mut_mut = !conflicts_mut_mut.is_empty(); - let report_mut_ref = !conflicts_mut_ref.is_empty(); - let report_move_conflict = !conflicts_move.is_empty(); - - let mut occurrences = match mut_outer { - Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], - Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], - }; - occurrences.extend(conflicts_mut_mut); - occurrences.extend(conflicts_mut_ref); - occurrences.extend(conflicts_move); - - // Report errors if any. - if report_mut_mut { - // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences }); - } else if report_mut_ref { - // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. - match mut_outer { - Mutability::Mut => { - sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences }); - } - Mutability::Not => { - sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences }); - } - }; - } else if report_move_conflict { - // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences }); - } -} diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 1eb1dd72a61..da7b6587a72 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -311,7 +311,10 @@ use super::deconstruct_pat::{ Constructor, ConstructorSet, DeconstructedPat, IntRange, MaybeInfiniteInt, SplitConstructorSet, WitnessPat, }; -use crate::errors::{NonExhaustiveOmittedPattern, Overlap, OverlappingRangeEndpoints, Uncovered}; +use crate::errors::{ + NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap, + OverlappingRangeEndpoints, Uncovered, +}; use rustc_data_structures::captures::Captures; @@ -337,6 +340,8 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> { pub(crate) module: DefId, pub(crate) param_env: ty::ParamEnv<'tcx>, pub(crate) pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>, + /// The span of the whole match, if applicable. + pub(crate) match_span: Option<Span>, /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns. pub(crate) refutable: bool, } @@ -1149,28 +1154,50 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. - if cx.refutable - && non_exhaustiveness_witnesses.is_empty() - && !matches!( + if cx.refutable && non_exhaustiveness_witnesses.is_empty() { + if !matches!( cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0, rustc_session::lint::Level::Allow - ) - { - let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); - if !witnesses.is_empty() { - // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` - // is not exhaustive enough. - // - // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. - cx.tcx.emit_spanned_lint( - NON_EXHAUSTIVE_OMITTED_PATTERNS, - lint_root, - scrut_span, - NonExhaustiveOmittedPattern { - scrut_ty, - uncovered: Uncovered::new(scrut_span, cx, witnesses), - }, - ); + ) { + let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); + + if !witnesses.is_empty() { + // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` + // is not exhaustive enough. + // + // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. + cx.tcx.emit_spanned_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + lint_root, + scrut_span, + NonExhaustiveOmittedPattern { + scrut_ty, + uncovered: Uncovered::new(scrut_span, cx, witnesses), + }, + ); + } + } else { + // We used to allow putting the `#[allow(non_exhaustive_omitted_patterns)]` on a match + // arm. This no longer makes sense so we warn users, to avoid silently breaking their + // usage of the lint. + for arm in arms { + let (lint_level, lint_level_source) = + cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.hir_id); + if !matches!(lint_level, rustc_session::lint::Level::Allow) { + let decorator = NonExhaustiveOmittedPatternLintOnArm { + lint_span: lint_level_source.span(), + suggest_lint_on_match: cx.match_span.map(|span| span.shrink_to_lo()), + lint_level: lint_level.as_str(), + lint_name: "non_exhaustive_omitted_patterns", + }; + + use rustc_errors::DecorateLint; + let mut err = cx.tcx.sess.struct_span_warn(arm.pat.span(), ""); + err.set_primary_message(decorator.msg()); + decorator.decorate_lint(&mut err); + err.emit(); + } + } } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 28765af20ad..42b2f18869c 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -1,13 +1,12 @@ use crate::MirPass; -use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_index::IndexVec; use rustc_middle::mir::*; use rustc_middle::mir::{ interpret::Scalar, - visit::{PlaceContext, Visitor}, + visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}, }; -use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeAndMut}; use rustc_session::Session; pub struct CheckAlignment; @@ -30,7 +29,12 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &mut body.local_decls; + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + // This pass inserts new blocks. Each insertion changes the Location for all + // statements/blocks after. Iterating or visiting the MIR in order would require updating + // our current location after every insertion. By iterating backwards, we dodge this issue: + // The only Locations that an insertion changes have already been handled. for block in (0..basic_blocks.len()).rev() { let block = block.into(); for statement_index in (0..basic_blocks[block].statements.len()).rev() { @@ -38,22 +42,19 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { let statement = &basic_blocks[block].statements[statement_index]; let source_info = statement.source_info; - let mut finder = PointerFinder { - local_decls, - tcx, - pointers: Vec::new(), - def_id: body.source.def_id(), - }; - for (pointer, pointee_ty) in finder.find_pointers(statement) { - debug!("Inserting alignment check for {:?}", pointer.ty(&*local_decls, tcx).ty); + let mut finder = + PointerFinder { tcx, local_decls, param_env, pointers: Vec::new() }; + finder.visit_statement(statement, location); + for (local, ty) in finder.pointers { + debug!("Inserting alignment check for {:?}", ty); let new_block = split_block(basic_blocks, location); insert_alignment_check( tcx, local_decls, &mut basic_blocks[block], - pointer, - pointee_ty, + local, + ty, source_info, new_block, ); @@ -63,69 +64,71 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { } } -impl<'tcx, 'a> PointerFinder<'tcx, 'a> { - fn find_pointers(&mut self, statement: &Statement<'tcx>) -> Vec<(Place<'tcx>, Ty<'tcx>)> { - self.pointers.clear(); - self.visit_statement(statement, Location::START); - core::mem::take(&mut self.pointers) - } -} - struct PointerFinder<'tcx, 'a> { - local_decls: &'a mut LocalDecls<'tcx>, tcx: TyCtxt<'tcx>, - def_id: DefId, + local_decls: &'a mut LocalDecls<'tcx>, + param_env: ParamEnv<'tcx>, pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, } impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::AddressOf(..) = rvalue { - // Ignore dereferences inside of an AddressOf - return; + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + // We want to only check reads and writes to Places, so we specifically exclude + // Borrows and AddressOf. + match context { + PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::AsmOutput + | MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::Drop, + ) => {} + PlaceContext::NonMutatingUse( + NonMutatingUseContext::Copy | NonMutatingUseContext::Move, + ) => {} + _ => { + return; + } } - self.super_rvalue(rvalue, location); - } - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - if let PlaceContext::NonUse(_) = context { - return; - } if !place.is_indirect() { return; } + // Since Deref projections must come first and only once, the pointer for an indirect place + // is the Local that the Place is based on. let pointer = Place::from(place.local); - let pointer_ty = pointer.ty(&*self.local_decls, self.tcx).ty; + let pointer_ty = self.local_decls[place.local].ty; - // We only want to check unsafe pointers + // We only want to check places based on unsafe pointers if !pointer_ty.is_unsafe_ptr() { - trace!("Indirect, but not an unsafe ptr, not checking {:?}", pointer_ty); + trace!("Indirect, but not based on an unsafe ptr, not checking {:?}", place); return; } - let Some(pointee) = pointer_ty.builtin_deref(true) else { - debug!("Indirect but no builtin deref: {:?}", pointer_ty); + let pointee_ty = + pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer").ty; + // Ideally we'd support this in the future, but for now we are limited to sized types. + if !pointee_ty.is_sized(self.tcx, self.param_env) { + debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); return; - }; - let mut pointee_ty = pointee.ty; - if pointee_ty.is_array() || pointee_ty.is_slice() || pointee_ty.is_str() { - pointee_ty = pointee_ty.sequence_element_type(self.tcx); } - if !pointee_ty.is_sized(self.tcx, self.tcx.param_env_reveal_all_normalized(self.def_id)) { - debug!("Unsafe pointer, but unsized: {:?}", pointer_ty); + // Try to detect types we are sure have an alignment of 1 and skip the check + // We don't need to look for str and slices, we already rejected unsized types above + let element_ty = match pointee_ty.kind() { + ty::Array(ty, _) => *ty, + _ => pointee_ty, + }; + if [self.tcx.types.bool, self.tcx.types.i8, self.tcx.types.u8].contains(&element_ty) { + debug!("Trivially aligned place type: {:?}", pointee_ty); return; } - if [self.tcx.types.bool, self.tcx.types.i8, self.tcx.types.u8, self.tcx.types.str_] - .contains(&pointee_ty) - { - debug!("Trivially aligned pointee type: {:?}", pointer_ty); - return; - } + // Ensure that this place is based on an aligned pointer. + self.pointers.push((pointer, pointee_ty)); - self.pointers.push((pointer, pointee_ty)) + self.super_place(place, context, location); } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 82fee7c8dfe..65bdcf10762 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -186,8 +186,9 @@ use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyC use rustc_session::config::EntryFnType; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; -use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; +use rustc_span::source_map::{dummy_spanned, respan, Spanned}; use rustc_span::symbol::{sym, Ident}; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::Size; use std::path::PathBuf; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0b5ec9b59ea..36125e138b2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -32,10 +32,10 @@ use rustc_macros::Subdiagnostic; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; -use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::source_map::{self, Spanned}; use rustc_span::symbol::kw::PathRoot; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, Span}; use thin_vec::{thin_vec, ThinVec}; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f0cf6bb58ca..253dd2a3b34 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -22,9 +22,9 @@ use rustc_errors::{ }; use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; -use rustc_span::source_map::{self, Span}; +use rustc_span::source_map; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use std::fmt::Write; use std::mem; use thin_vec::{thin_vec, ThinVec}; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 59b51954542..1a7ae406911 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -36,8 +36,8 @@ use rustc_errors::{ Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, }; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{Span, DUMMY_SP}; use std::ops::Range; use std::{mem, slice}; use thin_vec::ThinVec; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 3378e4d46b7..0a4c7c17d06 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -20,8 +20,9 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult}; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::{respan, Span, Spanned}; +use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4969e672a72..8626dbe40af 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -10,8 +10,8 @@ use rustc_ast::{ Path, PathSegment, QSelf, }; use rustc_errors::{Applicability, IntoDiagnostic, PResult}; -use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::{BytePos, Span}; use std::mem; use thin_vec::ThinVec; use tracing::debug; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 8e3c4568694..aa939a71d63 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -20,8 +20,8 @@ use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyl use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; -use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::{BytePos, Span}; use std::borrow::Cow; use std::mem; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index badea5d6133..be2cbaf3020 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -18,9 +18,8 @@ use rustc_ast::{ TraitObjectSyntax, Ty, TyKind, }; use rustc_errors::{Applicability, PResult}; -use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use thin_vec::{thin_vec, ThinVec}; /// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 38e1a7f372b..be50aad1303 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -589,9 +589,6 @@ passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias .label = is not a struct, enum or type alias -passes_plugin_registrar = - `#[plugin_registrar]` only has an effect on functions - passes_proc_macro_bad_sig = {$kind} has incorrect signature passes_repr_conflicting = diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a8a27e761cb..c5767fd902f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -211,7 +211,6 @@ impl CheckAttrVisitor<'_> { sym::deprecated => self.check_deprecated(hir_id, attr, span, target), sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target), sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod), - sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target), sym::macro_export => self.check_macro_export(hir_id, attr, target), sym::ignore | sym::should_panic => { self.check_generic_attr(hir_id, attr, target, Target::Fn) @@ -2237,17 +2236,6 @@ impl CheckAttrVisitor<'_> { } } - fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) { - if target != Target::Fn { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::PluginRegistrar, - ); - } - } - fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { // Warn on useless empty attributes. let note = if matches!( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b0862704003..411c9410195 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -717,10 +717,6 @@ pub enum MacroExport { TooManyItems, } -#[derive(LintDiagnostic)] -#[diag(passes_plugin_registrar)] -pub struct PluginRegistrar; - #[derive(Subdiagnostic)] pub enum UnusedNote { #[note(passes_unused_empty_lints_note)] diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml deleted file mode 100644 index a0762e815e3..00000000000 --- a/compiler/rustc_plugin_impl/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "rustc_plugin_impl" -version = "0.0.0" -build = false -edition = "2021" - -[dependencies] -# tidy-alphabetical-start -libloading = "0.7.1" -rustc_ast = { path = "../rustc_ast" } -rustc_errors = { path = "../rustc_errors" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_lint = { path = "../rustc_lint" } -rustc_macros = { path = "../rustc_macros" } -rustc_metadata = { path = "../rustc_metadata" } -rustc_session = { path = "../rustc_session" } -rustc_span = { path = "../rustc_span" } -# tidy-alphabetical-end diff --git a/compiler/rustc_plugin_impl/messages.ftl b/compiler/rustc_plugin_impl/messages.ftl deleted file mode 100644 index 8db32a42c1d..00000000000 --- a/compiler/rustc_plugin_impl/messages.ftl +++ /dev/null @@ -1,4 +0,0 @@ -plugin_impl_load_plugin_error = {$msg} - -plugin_impl_malformed_plugin_attribute = malformed `plugin` attribute - .label = malformed attribute diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs deleted file mode 100644 index e6a7fc86bee..00000000000 --- a/compiler/rustc_plugin_impl/src/errors.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Errors emitted by plugin_impl - -use rustc_macros::Diagnostic; -use rustc_span::Span; - -#[derive(Diagnostic)] -#[diag(plugin_impl_load_plugin_error)] -pub struct LoadPluginError { - #[primary_span] - pub span: Span, - pub msg: String, -} - -#[derive(Diagnostic)] -#[diag(plugin_impl_malformed_plugin_attribute, code = "E0498")] -pub struct MalformedPluginAttribute { - #[primary_span] - #[label] - pub span: Span, -} diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs deleted file mode 100644 index 0e1c80a1f64..00000000000 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Infrastructure for compiler plugins. -//! -//! Plugins are a deprecated way to extend the behavior of `rustc` in various ways. -//! -//! See the [`plugin` -//! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) -//! of the Unstable Book for some examples. - -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![cfg_attr(not(bootstrap), doc(rust_logo))] -#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] -#![cfg_attr(not(bootstrap), allow(internal_features))] -#![recursion_limit = "256"] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_fluent_macro::fluent_messages; -use rustc_lint::LintStore; - -mod errors; -pub mod load; - -fluent_messages! { "../messages.ftl" } - -/// Structure used to register plugins. -/// -/// A plugin registrar function takes an `&mut Registry` and should call -/// methods to register its plugins. -pub struct Registry<'a> { - /// The `LintStore` allows plugins to register new lints. - pub lint_store: &'a mut LintStore, -} diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs deleted file mode 100644 index 27e5cb9f0d0..00000000000 --- a/compiler/rustc_plugin_impl/src/load.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Used by `rustc` when loading a plugin. - -use crate::errors::{LoadPluginError, MalformedPluginAttribute}; -use crate::Registry; -use libloading::Library; -use rustc_ast::Attribute; -use rustc_metadata::locator; -use rustc_session::cstore::MetadataLoader; -use rustc_session::Session; -use rustc_span::symbol::{sym, Ident}; - -use std::env; -use std::mem; -use std::path::PathBuf; - -/// Pointer to a registrar function. -type PluginRegistrarFn = fn(&mut Registry<'_>); - -/// Read plugin metadata and dynamically load registrar functions. -pub fn load_plugins( - sess: &Session, - metadata_loader: &dyn MetadataLoader, - attrs: &[Attribute], -) -> Vec<PluginRegistrarFn> { - let mut plugins = Vec::new(); - - for attr in attrs { - if !attr.has_name(sym::plugin) { - continue; - } - - for plugin in attr.meta_item_list().unwrap_or_default() { - match plugin.ident() { - Some(ident) if plugin.is_word() => { - load_plugin(&mut plugins, sess, metadata_loader, ident) - } - _ => { - sess.emit_err(MalformedPluginAttribute { span: plugin.span() }); - } - } - } - } - - plugins -} - -fn load_plugin( - plugins: &mut Vec<PluginRegistrarFn>, - sess: &Session, - metadata_loader: &dyn MetadataLoader, - ident: Ident, -) { - let lib = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name); - let fun = dylink_registrar(lib).unwrap_or_else(|err| { - // This is fatal: there are almost certainly macros we need inside this crate, so - // continuing would spew "macro undefined" errors. - sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() }); - }); - plugins.push(fun); -} - -/// Dynamically link a registrar function into the compiler process. -fn dylink_registrar(lib_path: PathBuf) -> Result<PluginRegistrarFn, libloading::Error> { - // Make sure the path contains a / or the linker will search for it. - let lib_path = env::current_dir().unwrap().join(&lib_path); - - let lib = unsafe { Library::new(&lib_path) }?; - - let registrar_sym = unsafe { lib.get::<PluginRegistrarFn>(b"__rustc_plugin_registrar") }?; - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long - // (e.g., an Rc cycle or a thread). - let registrar_sym = unsafe { registrar_sym.into_raw() }; - mem::forget(lib); - - Ok(*registrar_sym) -} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a8ebab4ae33..c94e0d0ed39 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -18,10 +18,9 @@ use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; -use rustc_span::source_map::{FileName, FilePathMapping}; +use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::SourceFileHashAlgorithm; -use rustc_span::{FileNameDisplayPreference, RealFileName}; +use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg}; @@ -2674,28 +2673,19 @@ pub fn build_session_options( ); } - // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes - // precedence. - match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) { - (Some(smv_c), Some(smv_z)) if smv_c != smv_z => { - handler.early_error( - "incompatible values passed for `-C symbol-mangling-version` \ - and `-Z symbol-mangling-version`", - ); - } - (Some(SymbolManglingVersion::V0), _) => {} - (Some(_), _) if !unstable_opts.unstable_options => { - handler - .early_error("`-C symbol-mangling-version=legacy` requires `-Z unstable-options`"); - } - (None, None) => {} - (None, smv) => { - handler.early_warn( - "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`", - ); - cg.symbol_mangling_version = smv; + // Check for unstable values of `-C symbol-mangling-version`. + // This is what prevents them from being used on stable compilers. + match cg.symbol_mangling_version { + // Stable values: + None | Some(SymbolManglingVersion::V0) => {} + // Unstable values: + Some(SymbolManglingVersion::Legacy) => { + if !unstable_opts.unstable_options { + handler.early_error( + "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", + ); + } } - _ => {} } // Check for unstable values of `-C instrument-coverage`. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 30c8b9d6700..7510a41485a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1529,8 +1529,6 @@ options! { dump_solver_proof_tree: DumpSolverProofTree = (DumpSolverProofTree::Never, parse_dump_solver_proof_tree, [UNTRACKED], "dump a proof tree for every goal evaluated by the new trait solver. If the flag is specified without any options after it then it defaults to `always`. If the flag is not specified at all it defaults to `on-request`."), - dump_solver_proof_tree_use_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED], - "determines whether dumped proof trees use the global cache"), dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], @@ -1823,9 +1821,6 @@ written to standard error output)"), "control if mem::uninitialized and mem::zeroed panic on more UB"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), - symbol_mangling_version: Option<SymbolManglingVersion> = (None, - parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")] teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f823b556154..80a549b30f7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -31,8 +31,8 @@ use rustc_errors::{ use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; -use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span}; -use rustc_span::{SourceFileHashAlgorithm, Symbol}; +use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap}; +use rustc_span::{SourceFileHashAlgorithm, Span, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ diff --git a/compiler/rustc_span/src/fatal_error.rs b/compiler/rustc_span/src/fatal_error.rs index fa84c486df5..8b4f77a0566 100644 --- a/compiler/rustc_span/src/fatal_error.rs +++ b/compiler/rustc_span/src/fatal_error.rs @@ -1,13 +1,11 @@ -/// Used as a return value to signify a fatal error occurred. (It is also -/// used as the argument to panic at the moment, but that will eventually -/// not be true.) +/// Used as a return value to signify a fatal error occurred. #[derive(Copy, Clone, Debug)] #[must_use] pub struct FatalError; pub struct FatalErrorMarker; -// Don't implement Send on FatalError. This makes it impossible to panic!(FatalError). +// Don't implement Send on FatalError. This makes it impossible to `panic_any!(FatalError)`. // We don't want to invoke the panic handler and print a backtrace for fatal errors. impl !Send for FatalError {} diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 88081700c3b..36731d0fe74 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -24,16 +24,13 @@ // because getting it wrong can lead to nested `HygieneData::with` calls that // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) +use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use crate::edition::Edition; use crate::symbol::{kw, sym, Symbol}; -use crate::with_session_globals; -use crate::{HashStableContext, Span, DUMMY_SP}; - -use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; +use crate::{with_session_globals, HashStableContext, Span, DUMMY_SP}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::HashingControls; -use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc, WorkerLocal}; use rustc_data_structures::unhash::UnhashMap; use rustc_index::IndexVec; @@ -130,7 +127,7 @@ impl ExpnHash { /// Returns the crate-local part of the [ExpnHash]. /// - /// Used for tests. + /// Used for assertions. #[inline] pub fn local_hash(self) -> Hash64 { self.0.split().1 @@ -173,7 +170,7 @@ impl LocalExpnId { pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0); #[inline] - pub fn from_raw(idx: ExpnIndex) -> LocalExpnId { + fn from_raw(idx: ExpnIndex) -> LocalExpnId { LocalExpnId::from_u32(idx.as_u32()) } @@ -205,11 +202,6 @@ impl LocalExpnId { } #[inline] - pub fn expn_hash(self) -> ExpnHash { - HygieneData::with(|data| data.local_expn_hash(self)) - } - - #[inline] pub fn expn_data(self) -> ExpnData { HygieneData::with(|data| data.local_expn_data(self).clone()) } @@ -239,13 +231,6 @@ impl LocalExpnId { self.to_expn_id().is_descendant_of(ancestor.to_expn_id()) } - /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than - /// `expn_id.is_descendant_of(ctxt.outer_expn())`. - #[inline] - pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { - self.to_expn_id().outer_expn_is_descendant_of(ctxt) - } - /// Returns span for the macro which originally caused this expansion to happen. /// /// Stops backtracing at include! boundary. @@ -253,12 +238,6 @@ impl LocalExpnId { pub fn expansion_cause(self) -> Option<Span> { self.to_expn_id().expansion_cause() } - - #[inline] - #[track_caller] - pub fn parent(self) -> LocalExpnId { - self.expn_data().parent.as_local().unwrap() - } } impl ExpnId { @@ -333,7 +312,7 @@ impl ExpnId { } #[derive(Debug)] -pub struct HygieneData { +pub(crate) struct HygieneData { /// Each expansion should have an associated expansion data, but sometimes there's a delay /// between creation of an expansion ID and obtaining its data (e.g. macros are collected /// first and then resolved later), so we use an `Option` here. @@ -384,16 +363,11 @@ impl HygieneData { } } - pub fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T { + fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T { with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut())) } #[inline] - fn local_expn_hash(&self, expn_id: LocalExpnId) -> ExpnHash { - self.local_expn_hashes[expn_id] - } - - #[inline] fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash { match expn_id.as_local() { Some(expn_id) => self.local_expn_hashes[expn_id], @@ -746,7 +720,7 @@ impl SyntaxContext { } /// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0. - pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> { + pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> { HygieneData::with(|data| { *self = data.normalize_to_macros_2_0(*self); data.adjust(self, expn_id) @@ -779,7 +753,11 @@ impl SyntaxContext { /// ``` /// This returns `None` if the context cannot be glob-adjusted. /// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details). - pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> { + pub(crate) fn glob_adjust( + &mut self, + expn_id: ExpnId, + glob_span: Span, + ) -> Option<Option<ExpnId>> { HygieneData::with(|data| { let mut scope = None; let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt()); @@ -803,7 +781,7 @@ impl SyntaxContext { /// assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope)); /// } /// ``` - pub fn reverse_glob_adjust( + pub(crate) fn reverse_glob_adjust( &mut self, expn_id: ExpnId, glob_span: Span, @@ -858,11 +836,11 @@ impl SyntaxContext { } #[inline] - pub fn outer_mark(self) -> (ExpnId, Transparency) { + fn outer_mark(self) -> (ExpnId, Transparency) { HygieneData::with(|data| data.outer_mark(self)) } - pub fn dollar_crate_name(self) -> Symbol { + pub(crate) fn dollar_crate_name(self) -> Symbol { HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) } @@ -961,12 +939,12 @@ pub struct ExpnData { /// The normal module (`mod`) in which the expanded macro was defined. pub parent_module: Option<DefId>, /// Suppresses the `unsafe_code` lint for code produced by this macro. - pub allow_internal_unsafe: bool, + pub(crate) allow_internal_unsafe: bool, /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. pub local_inner_macros: bool, /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? - pub collapse_debuginfo: bool, + pub(crate) collapse_debuginfo: bool, } impl !PartialEq for ExpnData {} diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 1a94b7e98fd..fc13bdff36f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,10 +4,12 @@ //! //! - the *span*, represented by [`SpanData`] and related types; //! - source code as represented by a [`SourceMap`]; and -//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module. +//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically +//! in the [`sym`] module. //! -//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata, -//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`]. +//! Unlike most compilers, the span contains not only the position in the source code, but also +//! various other metadata, such as the edition and macro hygiene. This metadata is stored in +//! [`SyntaxContext`] and [`ExpnData`]. //! //! ## Note //! @@ -117,7 +119,6 @@ impl SessionGlobals { } } -#[inline] pub fn create_session_globals_then<R>(edition: Edition, f: impl FnOnce() -> R) -> R { assert!( !SESSION_GLOBALS.is_set(), @@ -128,7 +129,6 @@ pub fn create_session_globals_then<R>(edition: Edition, f: impl FnOnce() -> R) - SESSION_GLOBALS.set(&session_globals, f) } -#[inline] pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnOnce() -> R) -> R { assert!( !SESSION_GLOBALS.is_set(), @@ -138,7 +138,6 @@ pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnO SESSION_GLOBALS.set(session_globals, f) } -#[inline] pub fn create_default_session_if_not_set_then<R, F>(f: F) -> R where F: FnOnce(&SessionGlobals) -> R, @@ -146,7 +145,6 @@ where create_session_if_not_set_then(edition::DEFAULT_EDITION, f) } -#[inline] pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R where F: FnOnce(&SessionGlobals) -> R, @@ -159,7 +157,6 @@ where } } -#[inline] pub fn with_session_globals<R, F>(f: F) -> R where F: FnOnce(&SessionGlobals) -> R, @@ -167,7 +164,6 @@ where SESSION_GLOBALS.with(f) } -#[inline] pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R { create_session_globals_then(edition::DEFAULT_EDITION, f) } @@ -179,8 +175,7 @@ scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals); // FIXME: We should use this enum or something like it to get rid of the // use of magic `/rust/1.x/...` paths across the board. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)] -#[derive(Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)] pub enum RealFileName { LocalPath(PathBuf), /// For remapped paths (namely paths into libstd that have been mapped @@ -217,8 +212,8 @@ impl<S: Encoder> Encodable<S> for RealFileName { RealFileName::Remapped { ref local_path, ref virtual_name } => encoder .emit_enum_variant(1, |encoder| { - // For privacy and build reproducibility, we must not embed host-dependant path in artifacts - // if they have been remapped by --remap-path-prefix + // For privacy and build reproducibility, we must not embed host-dependant path + // in artifacts if they have been remapped by --remap-path-prefix assert!(local_path.is_none()); local_path.encode(encoder); virtual_name.encode(encoder); @@ -954,7 +949,7 @@ impl Span { /// Produces a span with the same location as `self` and context produced by a macro with the /// given ID and transparency, assuming that macro was defined directly and not produced by /// some other macro (which is the case for built-in and procedural macros). - pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency)) } @@ -1529,7 +1524,8 @@ impl SourceFile { }) } - /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it. + /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes + /// it. fn convert_diffs_to_lines_frozen(&self) { let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return }; @@ -2247,6 +2243,9 @@ where /// Useful type to use with `Result<>` indicate that an error has already /// been reported to the user, so no need to continue checking. +/// +/// The `()` field is necessary: it is non-`pub`, which means values of this +/// type cannot be constructed outside of this crate. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable_Generic)] pub struct ErrorGuaranteed(()); @@ -2264,7 +2263,8 @@ impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed { #[inline] fn encode(&self, _e: &mut E) { panic!( - "should never serialize an `ErrorGuaranteed`, as we do not write metadata or incremental caches in case errors occurred" + "should never serialize an `ErrorGuaranteed`, as we do not write metadata or \ + incremental caches in case errors occurred" ) } } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 612d396b099..dcf346acb33 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -9,21 +9,16 @@ //! within the `SourceMap`, which upon request can be converted to line and column //! information, source code snippets, etc. -pub use crate::hygiene::{ExpnData, ExpnKind}; -pub use crate::*; - +use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock}; use std::cmp; +use std::fs; use std::hash::Hash; +use std::io::{self, BorrowedBuf, Read}; use std::path::{self, Path, PathBuf}; -use std::fs; -use std::io; -use std::io::BorrowedBuf; -use std::io::Read; - #[cfg(test)] mod tests; @@ -41,7 +36,7 @@ pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { } } -pub mod monotonic { +mod monotonic { use std::ops::{Deref, DerefMut}; /// A `MonotonicVec` is a `Vec` which can only be grown. @@ -51,18 +46,14 @@ pub mod monotonic { // field is inaccessible pub struct MonotonicVec<T>(Vec<T>); impl<T> MonotonicVec<T> { - pub fn new(val: Vec<T>) -> MonotonicVec<T> { - MonotonicVec(val) - } - - pub fn push(&mut self, val: T) { + pub(super) fn push(&mut self, val: T) { self.0.push(val); } } impl<T> Default for MonotonicVec<T> { fn default() -> Self { - MonotonicVec::new(vec![]) + MonotonicVec(vec![]) } } @@ -207,7 +198,7 @@ impl StableSourceFileId { // #[derive(Default)] -pub(super) struct SourceMapFiles { +struct SourceMapFiles { source_files: monotonic::MonotonicVec<Lrc<SourceFile>>, stable_id_to_source_file: FxHashMap<StableSourceFileId, Lrc<SourceFile>>, } @@ -466,33 +457,6 @@ impl SourceMap { self.span_to_string(sp, FileNameDisplayPreference::Remapped) } - /// Format the span location suitable for pretty printing annotations with relative line numbers - pub fn span_to_relative_line_string(&self, sp: Span, relative_to: Span) -> String { - if self.files.borrow().source_files.is_empty() || sp.is_dummy() || relative_to.is_dummy() { - return "no-location".to_string(); - } - - let lo = self.lookup_char_pos(sp.lo()); - let hi = self.lookup_char_pos(sp.hi()); - let offset = self.lookup_char_pos(relative_to.lo()); - - if lo.file.name != offset.file.name || !relative_to.contains(sp) { - return self.span_to_embeddable_string(sp); - } - - let lo_line = lo.line.saturating_sub(offset.line); - let hi_line = hi.line.saturating_sub(offset.line); - - format!( - "{}:+{}:{}: +{}:{}", - lo.file.name.display(FileNameDisplayPreference::Remapped), - lo_line, - lo.col.to_usize() + 1, - hi_line, - hi.col.to_usize() + 1, - ) - } - /// Format the span location to be printed in diagnostics. Must not be emitted /// to build artifacts as this may leak local file paths. Use span_to_embeddable_string /// for string suitable for embedding. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3f99d2a4b1f..ff470ce1fa0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -3,7 +3,7 @@ //! type, and vice versa. use rustc_arena::DroplessArena; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_data_structures::sync::Lock; use rustc_macros::HashStable_Generic; @@ -20,8 +20,8 @@ mod tests; // The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`. symbols! { - // After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`, - // this should be rarely necessary though if the keywords are kept in alphabetic order. + // If you modify this list, adjust `is_special` and `is_used_keyword`/`is_unused_keyword`. + // But this should rarely be necessary if the keywords are kept in alphabetic order. Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. @@ -316,6 +316,7 @@ symbols! { ToOwned, ToString, TokenStream, + Trait, Try, TryCaptureGeneric, TryCapturePrintable, @@ -893,7 +894,7 @@ symbols! { inline_const_pat, inout, instruction_set, - integer_: "integer", + integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below integral, into_future, into_iter, @@ -2076,43 +2077,33 @@ impl<CTX> ToStableHashKey<CTX> for Symbol { } } -#[derive(Default)] pub(crate) struct Interner(Lock<InternerInner>); // The `&'static str`s in this type actually point into the arena. // -// The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278 -// found that to regress performance up to 2% in some cases. This might be -// revisited after further improvements to `indexmap`. -// // This type is private to prevent accidentally constructing more than one // `Interner` on the same thread, which makes it easy to mix up `Symbol`s // between `Interner`s. -#[derive(Default)] struct InternerInner { arena: DroplessArena, - names: FxHashMap<&'static str, Symbol>, - strings: Vec<&'static str>, + strings: FxIndexSet<&'static str>, } impl Interner { fn prefill(init: &[&'static str]) -> Self { Interner(Lock::new(InternerInner { - strings: init.into(), - names: init.iter().copied().zip((0..).map(Symbol::new)).collect(), - ..Default::default() + arena: Default::default(), + strings: init.iter().copied().collect(), })) } #[inline] fn intern(&self, string: &str) -> Symbol { let mut inner = self.0.lock(); - if let Some(&name) = inner.names.get(string) { - return name; + if let Some(idx) = inner.strings.get_index_of(string) { + return Symbol::new(idx as u32); } - let name = Symbol::new(inner.strings.len() as u32); - // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, // and immediately convert the clone back to `&[u8]`, all because there // is no `inner.arena.alloc_str()` method. This is clearly safe. @@ -2122,20 +2113,21 @@ impl Interner { // SAFETY: we can extend the arena allocation to `'static` because we // only access these while the arena is still alive. let string: &'static str = unsafe { &*(string as *const str) }; - inner.strings.push(string); // This second hash table lookup can be avoided by using `RawEntryMut`, // but this code path isn't hot enough for it to be worth it. See // #91445 for details. - inner.names.insert(string, name); - name + let (idx, is_new) = inner.strings.insert_full(string); + debug_assert!(is_new); // due to the get_index_of check above + + Symbol::new(idx as u32) } /// Get the symbol as a string. /// /// [`Symbol::as_str()`] should be used in preference to this function. fn get(&self, symbol: Symbol) -> &str { - self.0.lock().strings[symbol.0.as_usize()] + self.0.lock().strings.get_index(symbol.0.as_usize()).unwrap() } } diff --git a/compiler/rustc_span/src/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs index 0958fce5fee..4366c5a2c26 100644 --- a/compiler/rustc_span/src/symbol/tests.rs +++ b/compiler/rustc_span/src/symbol/tests.rs @@ -4,7 +4,7 @@ use crate::create_default_session_globals_then; #[test] fn interner_tests() { - let i = Interner::default(); + let i = Interner::prefill(&[]); // first one is zero: assert_eq!(i.intern("dog"), Symbol::new(0)); // re-use gets the same entry: diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 066129d8e47..70235b710e2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -119,25 +119,11 @@ impl NestedGoals<'_> { #[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] pub enum GenerateProofTree { - Yes(UseGlobalCache), + Yes, IfEnabled, Never, } -#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] -pub enum UseGlobalCache { - Yes, - No, -} -impl UseGlobalCache { - pub fn from_bool(use_cache: bool) -> Self { - match use_cache { - true => UseGlobalCache::Yes, - false => UseGlobalCache::No, - } - } -} - pub trait InferCtxtEvalExt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 15c8d9e5bcb..69bfdd4688c 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -17,7 +17,7 @@ use rustc_middle::traits::solve::{Certainty, Goal}; use rustc_middle::ty; use crate::solve::inspect::ProofTreeBuilder; -use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache}; +use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; pub struct InspectGoal<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, @@ -82,8 +82,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { } for &goal in &instantiated_goals { - let (_, proof_tree) = - infcx.evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No)); + let (_, proof_tree) = infcx.evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); visitor.visit_goal(&InspectGoal::new( infcx, @@ -169,11 +168,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { let mut candidates = vec![]; let last_eval_step = match self.evaluation.evaluation.kind { inspect::CanonicalGoalEvaluationKind::Overflow - | inspect::CanonicalGoalEvaluationKind::CacheHit(_) => { + | inspect::CanonicalGoalEvaluationKind::CycleInStack => { warn!("unexpected root evaluation: {:?}", self.evaluation); return vec![]; } - inspect::CanonicalGoalEvaluationKind::Uncached { ref revisions } => { + inspect::CanonicalGoalEvaluationKind::Evaluation { ref revisions } => { if let Some(last) = revisions.last() { last } else { @@ -227,8 +226,7 @@ impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V, ) -> ControlFlow<V::BreakTy> { - let (_, proof_tree) = - self.evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No)); + let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree)) } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 2eba98b02e9..088455b38cb 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -3,6 +3,8 @@ //! This code is *a bit* of a mess and can hopefully be //! mostly ignored. For a general overview of how it works, //! see the comment on [ProofTreeBuilder]. +use std::mem; + use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult, @@ -10,7 +12,6 @@ use rustc_middle::traits::solve::{ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::DumpSolverProofTree; -use crate::solve::eval_ctxt::UseGlobalCache; use crate::solve::{self, inspect, EvalCtxt, GenerateProofTree}; /// The core data structure when building proof trees. @@ -34,12 +35,7 @@ use crate::solve::{self, inspect, EvalCtxt, GenerateProofTree}; /// is called to recursively convert the whole structure to a /// finished proof tree. pub(in crate::solve) struct ProofTreeBuilder<'tcx> { - state: Option<Box<BuilderData<'tcx>>>, -} - -struct BuilderData<'tcx> { - tree: DebugSolver<'tcx>, - use_global_cache: UseGlobalCache, + state: Option<Box<DebugSolver<'tcx>>>, } /// The current state of the proof tree builder, at most places @@ -118,36 +114,46 @@ pub(in crate::solve) enum WipGoalEvaluationKind<'tcx> { Nested { is_normalizes_to_hack: IsNormalizesToHack }, } -#[derive(Eq, PartialEq, Debug)] -pub(in crate::solve) enum WipCanonicalGoalEvaluationKind { +#[derive(Eq, PartialEq)] +pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<'tcx> { Overflow, - CacheHit(inspect::CacheHit), + CycleInStack, + Interned { revisions: &'tcx [inspect::GoalEvaluationStep<'tcx>] }, +} + +impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Overflow => write!(f, "Overflow"), + Self::CycleInStack => write!(f, "CycleInStack"), + Self::Interned { revisions: _ } => f.debug_struct("Interned").finish_non_exhaustive(), + } + } } #[derive(Eq, PartialEq, Debug)] struct WipCanonicalGoalEvaluation<'tcx> { goal: CanonicalInput<'tcx>, - kind: Option<WipCanonicalGoalEvaluationKind>, + kind: Option<WipCanonicalGoalEvaluationKind<'tcx>>, + /// Only used for uncached goals. After we finished evaluating + /// the goal, this is interned and moved into `kind`. revisions: Vec<WipGoalEvaluationStep<'tcx>>, result: Option<QueryResult<'tcx>>, } impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> { - let kind = match self.kind { - Some(WipCanonicalGoalEvaluationKind::Overflow) => { + assert!(self.revisions.is_empty()); + let kind = match self.kind.unwrap() { + WipCanonicalGoalEvaluationKind::Overflow => { inspect::CanonicalGoalEvaluationKind::Overflow } - Some(WipCanonicalGoalEvaluationKind::CacheHit(hit)) => { - inspect::CanonicalGoalEvaluationKind::CacheHit(hit) + WipCanonicalGoalEvaluationKind::CycleInStack => { + inspect::CanonicalGoalEvaluationKind::CycleInStack + } + WipCanonicalGoalEvaluationKind::Interned { revisions } => { + inspect::CanonicalGoalEvaluationKind::Evaluation { revisions } } - None => inspect::CanonicalGoalEvaluationKind::Uncached { - revisions: self - .revisions - .into_iter() - .map(WipGoalEvaluationStep::finalize) - .collect(), - }, }; inspect::CanonicalGoalEvaluation { goal: self.goal, kind, result: self.result.unwrap() } @@ -226,33 +232,20 @@ impl<'tcx> WipProbeStep<'tcx> { } impl<'tcx> ProofTreeBuilder<'tcx> { - fn new( - state: impl Into<DebugSolver<'tcx>>, - use_global_cache: UseGlobalCache, - ) -> ProofTreeBuilder<'tcx> { - ProofTreeBuilder { - state: Some(Box::new(BuilderData { tree: state.into(), use_global_cache })), - } + fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder { state: Some(Box::new(state.into())) } } fn nested<T: Into<DebugSolver<'tcx>>>(&self, state: impl FnOnce() -> T) -> Self { - match &self.state { - Some(prev_state) => Self { - state: Some(Box::new(BuilderData { - tree: state().into(), - use_global_cache: prev_state.use_global_cache, - })), - }, - None => Self { state: None }, - } + ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) } } fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> { - self.state.as_mut().map(|boxed| &mut boxed.tree) + self.state.as_deref_mut() } pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { - match self.state?.tree { + match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) } @@ -260,13 +253,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn use_global_cache(&self) -> bool { - self.state - .as_ref() - .map(|state| matches!(state.use_global_cache, UseGlobalCache::Yes)) - .unwrap_or(true) - } - pub fn new_maybe_root( tcx: TyCtxt<'tcx>, generate_proof_tree: GenerateProofTree, @@ -276,10 +262,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { GenerateProofTree::IfEnabled => { let opts = &tcx.sess.opts.unstable_opts; match opts.dump_solver_proof_tree { - DumpSolverProofTree::Always => { - let use_cache = opts.dump_solver_proof_tree_use_cache.unwrap_or(true); - ProofTreeBuilder::new_root(UseGlobalCache::from_bool(use_cache)) - } + DumpSolverProofTree::Always => ProofTreeBuilder::new_root(), // `OnError` is handled by reevaluating goals in error // reporting with `GenerateProofTree::Yes`. DumpSolverProofTree::OnError | DumpSolverProofTree::Never => { @@ -287,12 +270,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } } - GenerateProofTree::Yes(use_cache) => ProofTreeBuilder::new_root(use_cache), + GenerateProofTree::Yes => ProofTreeBuilder::new_root(), } } - pub fn new_root(use_global_cache: UseGlobalCache) -> ProofTreeBuilder<'tcx> { - ProofTreeBuilder::new(DebugSolver::Root, use_global_cache) + pub fn new_root() -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder::new(DebugSolver::Root) } pub fn new_noop() -> ProofTreeBuilder<'tcx> { @@ -336,9 +319,27 @@ impl<'tcx> ProofTreeBuilder<'tcx> { }) } + pub fn finalize_evaluation( + &mut self, + tcx: TyCtxt<'tcx>, + ) -> Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]> { + self.as_mut().map(|this| match this { + DebugSolver::CanonicalGoalEvaluation(evaluation) => { + let revisions = mem::take(&mut evaluation.revisions) + .into_iter() + .map(WipGoalEvaluationStep::finalize); + let revisions = &*tcx.arena.alloc_from_iter(revisions); + let kind = WipCanonicalGoalEvaluationKind::Interned { revisions }; + assert_eq!(evaluation.kind.replace(kind), None); + revisions + } + _ => unreachable!(), + }) + } + pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, canonical_goal_evaluation.state.unwrap().tree) { + match (this, *canonical_goal_evaluation.state.unwrap()) { ( DebugSolver::GoalEvaluation(goal_evaluation), DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation), @@ -348,7 +349,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) { + pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<'tcx>) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -372,7 +373,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, goal_evaluation.state.unwrap().tree) { + match (this, *goal_evaluation.state.unwrap()) { ( DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { evaluations, .. @@ -396,7 +397,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, goal_evaluation_step.state.unwrap().tree) { + match (this, *goal_evaluation_step.state.unwrap()) { ( DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluations), DebugSolver::GoalEvaluationStep(goal_evaluation_step), @@ -444,7 +445,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, probe.state.unwrap().tree) { + match (this, *probe.state.unwrap()) { ( DebugSolver::Probe(WipProbe { steps, .. }) | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { @@ -486,7 +487,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn added_goals_evaluation(&mut self, added_goals_evaluation: ProofTreeBuilder<'tcx>) { if let Some(this) = self.as_mut() { - match (this, added_goals_evaluation.state.unwrap().tree) { + match (this, *added_goals_evaluation.state.unwrap()) { ( DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { evaluation: WipProbe { steps, .. }, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index d45fe102805..dba5369fa0f 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -38,9 +38,7 @@ mod project_goals; mod search_graph; mod trait_goals; -pub use eval_ctxt::{ - EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache, -}; +pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; pub use fulfill::FulfillmentCtxt; pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index 33513f6bd43..7ffa1d7d319 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -6,7 +6,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_index::Idx; use rustc_index::IndexVec; use rustc_middle::dep_graph::dep_kinds; -use rustc_middle::traits::solve::inspect::CacheHit; use rustc_middle::traits::solve::CacheData; use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult}; use rustc_middle::ty::TyCtxt; @@ -191,8 +190,8 @@ impl<'tcx> SearchGraph<'tcx> { }; // Try to fetch the goal from the global cache. - if inspect.use_global_cache() { - if let Some(CacheData { result, reached_depth, encountered_overflow }) = + 'global: { + let Some(CacheData { result, proof_tree, reached_depth, encountered_overflow }) = self.global_cache(tcx).get( tcx, input, @@ -201,13 +200,26 @@ impl<'tcx> SearchGraph<'tcx> { }, available_depth, ) - { - inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit( - CacheHit::Global, - )); - self.on_cache_hit(reached_depth, encountered_overflow); - return result; + else { + break 'global; + }; + + // If we're building a proof tree and the current cache entry does not + // contain a proof tree, we do not use the entry but instead recompute + // the goal. We simply overwrite the existing entry once we're done, + // caching the proof tree. + if !inspect.is_noop() { + if let Some(revisions) = proof_tree { + inspect.goal_evaluation_kind( + inspect::WipCanonicalGoalEvaluationKind::Interned { revisions }, + ); + } else { + break 'global; + } } + + self.on_cache_hit(reached_depth, encountered_overflow); + return result; } // Check whether we're in a cycle. @@ -238,9 +250,7 @@ impl<'tcx> SearchGraph<'tcx> { // Finally we can return either the provisional response for that goal if we have a // coinductive cycle or an ambiguous result if the cycle is inductive. Entry::Occupied(entry) => { - inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit( - CacheHit::Provisional, - )); + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CycleInStack); let stack_depth = *entry.get(); debug!("encountered cycle with depth {stack_depth:?}"); @@ -329,6 +339,8 @@ impl<'tcx> SearchGraph<'tcx> { (current_entry, result) }); + let proof_tree = inspect.finalize_evaluation(tcx); + // We're now done with this goal. In case this goal is involved in a larger cycle // do not remove it from the provisional cache and update its provisional result. // We only add the root of cycles to the global cache. @@ -346,7 +358,9 @@ impl<'tcx> SearchGraph<'tcx> { // more details. let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len(); self.global_cache(tcx).insert( + tcx, input, + proof_tree, reached_depth, final_entry.encountered_overflow, final_entry.cycle_participants, 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 79b09db2268..0796cb57d97 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -8,7 +8,7 @@ mod type_err_ctxt_ext; use super::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation}; use crate::infer::InferCtxt; -use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache}; +use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -173,7 +173,7 @@ pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: & infcx.probe(|_| { let goal = Goal { predicate: o.predicate, param_env: o.param_env }; let tree = infcx - .evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No)) + .evaluate_root_goal(goal, GenerateProofTree::Yes) .1 .expect("proof tree should have been generated"); let mut lock = std::io::stdout().lock(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index a5508c74134..5fbfedd3e83 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -53,6 +53,7 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ sym::float, sym::_Self, sym::crate_local, + sym::Trait, ]; impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { @@ -183,6 +184,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } + if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id) + && let ty::Tuple(args) = trait_ref.args.type_at(1).kind() + { + let args = args + .iter() + .map(|ty| ty.to_string()) + .collect::<Vec<_>>() + .join(", "); + flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str())))); + } else { + flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string()))); + } + // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({ diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index e4f7592c409..471d10dbdbd 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -783,7 +783,7 @@ pub struct BoundVarReplacer<'me, 'tcx> { // the `var` (but we *could* bring that into scope if we were to track them as we pass them). mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>, + mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, // The current depth relative to *this* folding, *not* the entire normalization. In other words, // the depth of binders we've passed here. current_index: ty::DebruijnIndex, @@ -843,11 +843,11 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { T, BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, BTreeMap<ty::PlaceholderType, ty::BoundTy>, - BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>, + BTreeMap<ty::PlaceholderConst, ty::BoundVar>, ) { let mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion> = BTreeMap::new(); let mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy> = BTreeMap::new(); - let mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar> = BTreeMap::new(); + let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new(); let mut replacer = BoundVarReplacer { infcx, @@ -966,7 +966,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> { infcx: &'me InferCtxt<'tcx>, mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>, + mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, universe_indices: &'me [Option<ty::UniverseIndex>], current_index: ty::DebruijnIndex, } @@ -976,7 +976,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { infcx: &'me InferCtxt<'tcx>, mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>, + mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, universe_indices: &'me [Option<ty::UniverseIndex>], value: T, ) -> T { diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 0783eec6fe8..f8efa6a1f6c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -5,7 +5,7 @@ use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -133,7 +133,7 @@ pub fn compute_dropck_outlives_inner<'tcx>( result.overflows.len(), ty_stack.len() ); - dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; + dtorck_constraint_for_ty_inner(tcx, param_env, DUMMY_SP, depth, ty, &mut constraints)?; // "outlives" represent types/regions that may be touched // by a destructor. @@ -185,16 +185,15 @@ pub fn compute_dropck_outlives_inner<'tcx>( /// Returns a set of constraints that needs to be satisfied in /// order for `ty` to be valid for destruction. +#[instrument(level = "debug", skip(tcx, param_env, span, constraints))] pub fn dtorck_constraint_for_ty_inner<'tcx>( tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, span: Span, - for_ty: Ty<'tcx>, depth: usize, ty: Ty<'tcx>, constraints: &mut DropckConstraint<'tcx>, ) -> Result<(), NoSolution> { - debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - if !tcx.recursion_limit().value_within_limit(depth) { constraints.overflows.push(ty); return Ok(()); @@ -224,13 +223,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints) + dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints) })?; } ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in tys.iter() { - dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?; } Ok::<_, NoSolution>(()) })?, @@ -249,7 +248,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in args.as_closure().upvar_tys() { - dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner( + tcx, + param_env, + span, + depth + 1, + ty, + constraints, + )?; } Ok::<_, NoSolution>(()) })? @@ -278,8 +284,8 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // only take place through references with lifetimes // derived from lifetimes attached to the upvars and resume // argument, and we *do* incorporate those here. - - if !args.as_coroutine().is_valid() { + let args = args.as_coroutine(); + if !args.is_valid() { // By the time this code runs, all type variables ought to // be fully resolved. tcx.sess.delay_span_bug( @@ -289,10 +295,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( return Err(NoSolution); } - constraints - .outlives - .extend(args.as_coroutine().upvar_tys().iter().map(ty::GenericArg::from)); - constraints.outlives.push(args.as_coroutine().resume_ty().into()); + // While we conservatively assume that all coroutines require drop + // to avoid query cycles during MIR building, we can check the actual + // witness during borrowck to avoid unnecessary liveness constraints. + if args.witness().needs_drop(tcx, tcx.erase_regions(param_env)) { + constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from)); + constraints.outlives.push(args.resume_ty().into()); + } } ty::Adt(def, args) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index c99e018e9ae..c81bc579003 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -6,8 +6,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{TyCtxt, TypeFoldable}; -use rustc_span::source_map::DUMMY_SP; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::fmt; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e415d70479e..e345fc39ead 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -10,7 +10,7 @@ use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use smallvec::{smallvec, SmallVec}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 074764f0c4e..f40c3614e1c 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -34,6 +34,7 @@ pub(crate) fn adt_dtorck_constraint( ) -> Result<&DropckConstraint<'_>, NoSolution> { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); + let param_env = tcx.param_env(def_id); debug!("dtorck_constraint: {:?}", def); if def.is_manually_drop() { @@ -55,7 +56,7 @@ pub(crate) fn adt_dtorck_constraint( let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).instantiate_identity(); - dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?; + dtorck_constraint_for_ty_inner(tcx, param_env, span, 0, fty, &mut result)?; } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index e8917d72483..9fd550495aa 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,7 +1,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 08127304741..67ccfe7e78a 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -66,6 +66,9 @@ fn has_significant_drop_raw<'tcx>( struct NeedsDropTypes<'tcx, F> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, + // Whether to reveal coroutine witnesses, this is set + // to `false` unless we compute `needs_drop` for a coroutine witness. + reveal_coroutine_witnesses: bool, query_ty: Ty<'tcx>, seen_tys: FxHashSet<Ty<'tcx>>, /// A stack of types left to process, and the recursion depth when we @@ -89,6 +92,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { Self { tcx, param_env, + reveal_coroutine_witnesses: false, seen_tys, query_ty: ty, unchecked_tys: vec![(ty, 0)], @@ -133,8 +137,31 @@ where // The information required to determine whether a coroutine has drop is // computed on MIR, while this very method is used to build MIR. // To avoid cycles, we consider that coroutines always require drop. - ty::Coroutine(..) => { - return Some(Err(AlwaysRequiresDrop)); + // + // HACK: Because we erase regions contained in the coroutine witness, we + // have to conservatively assume that every region captured by the + // coroutine has to be live when dropped. This results in a lot of + // undesirable borrowck errors. During borrowck, we call `needs_drop` + // for the coroutine witness and check whether any of the contained types + // need to be dropped, and only require the captured types to be live + // if they do. + ty::Coroutine(_, args, _) => { + if self.reveal_coroutine_witnesses { + queue_type(self, args.as_coroutine().witness()); + } else { + return Some(Err(AlwaysRequiresDrop)); + } + } + ty::CoroutineWitness(def_id, args) => { + if let Some(witness) = tcx.mir_coroutine_witnesses(def_id) { + self.reveal_coroutine_witnesses = true; + for field_ty in &witness.field_tys { + queue_type( + self, + EarlyBinder::bind(field_ty.ty).instantiate(tcx, args), + ); + } + } } _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), @@ -191,7 +218,6 @@ where | ty::FnPtr(..) | ty::Tuple(_) | ty::Bound(..) - | ty::CoroutineWitness(..) | ty::Never | ty::Infer(_) | ty::Error(_) => { diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index d5cadd4e83a..8472a084505 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -115,5 +115,8 @@ bitflags! { /// Does this have `Coroutine` or `CoroutineWitness`? const HAS_TY_COROUTINE = 1 << 23; + + /// Does this have any binders with bound vars (e.g. that need to be anonymized)? + const HAS_BINDER_VARS = 1 << 24; } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index dceb5ba0560..2138c273341 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -218,7 +218,6 @@ pub enum TyKind<I: Interner> { /// the type of the coroutine, we convert them to higher ranked /// lifetimes bound by the witness itself. /// - /// This variant is only using when `drop_tracking_mir` is set. /// This contains the `DefId` and the `GenericArgsRef` of the coroutine. /// The actual witness types are computed on MIR by the `mir_coroutine_witnesses` query. /// diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 4a62013c685..25c63b425ce 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2444,4 +2444,8 @@ impl<T: core::error::Error> core::error::Error for Box<T> { fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { core::error::Error::source(&**self) } + + fn provide<'b>(&'b self, request: &mut core::error::Request<'b>) { + core::error::Error::provide(&**self, request); + } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4f0a02da440..d33c4418e1b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,6 @@ #![feature(const_eval_select)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_write)] -#![feature(const_maybe_uninit_zeroed)] #![feature(const_pin)] #![feature(const_refs_to_cell)] #![feature(const_size_of_val)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index bd66ad61219..817b93720ce 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -305,10 +305,13 @@ impl<T, A: Allocator> RawVec<T, A> { /// The same as `reserve`, but returns on errors instead of panicking or aborting. pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { if self.needs_to_grow(len, additional) { - self.grow_amortized(len, additional) - } else { - Ok(()) + self.grow_amortized(len, additional)?; + } + unsafe { + // Inform the optimizer that the reservation has succeeded or wasn't needed + core::intrinsics::assume(!self.needs_to_grow(len, additional)); } + Ok(()) } /// Ensures that the buffer contains at least enough space to hold `len + @@ -339,7 +342,14 @@ impl<T, A: Allocator> RawVec<T, A> { len: usize, additional: usize, ) -> Result<(), TryReserveError> { - if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) } + if self.needs_to_grow(len, additional) { + self.grow_exact(len, additional)?; + } + unsafe { + // Inform the optimizer that the reservation has succeeded or wasn't needed + core::intrinsics::assume(!self.needs_to_grow(len, additional)); + } + Ok(()) } /// Shrinks the buffer down to the specified capacity. If the given amount diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 89125b7955e..8c01b0973d6 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -138,7 +138,7 @@ pub const fn identity<T>(x: T) -> T { /// /// [dereferenceable types]: core::ops::Deref /// [pointed-to value]: core::ops::Deref::Target -/// ['`Deref` coercion']: core::ops::Deref#more-on-deref-coercion +/// ['`Deref` coercion']: core::ops::Deref#deref-coercion /// /// ``` /// let x = Box::new(5i32); @@ -244,7 +244,7 @@ pub trait AsRef<T: ?Sized> { /// /// [mutably dereferenceable types]: core::ops::DerefMut /// [pointed-to value]: core::ops::Deref::Target -/// ['`Deref` coercion']: core::ops::DerefMut#more-on-deref-coercion +/// ['`Deref` coercion']: core::ops::DerefMut#mutable-deref-coercion /// /// ``` /// let mut x = Box::new(5i32); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 964aa3906f1..f855b2ad483 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1072,7 +1072,7 @@ extern "rust-intrinsic" { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")] + #[rustc_const_stable(feature = "const_assert_type2", since = "CURRENT_RUSTC_VERSION")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_zero_valid<T>(); @@ -1080,7 +1080,7 @@ extern "rust-intrinsic" { /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")] + #[rustc_const_stable(feature = "const_assert_type2", since = "CURRENT_RUSTC_VERSION")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_mem_uninitialized_valid<T>(); diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index d396a707b55..13437d8f961 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -155,12 +155,18 @@ pub trait Sized { /// Those implementations are: /// /// - Arrays `[T; N]` implement `Unsize<[T]>`. -/// - Types implementing a trait `Trait` also implement `Unsize<dyn Trait>`. -/// - Structs `Foo<..., T, ...>` implement `Unsize<Foo<..., U, ...>>` if all of these conditions -/// are met: -/// - `T: Unsize<U>`. -/// - Only the last field of `Foo` has a type involving `T`. -/// - `Bar<T>: Unsize<Bar<U>>`, where `Bar<T>` stands for the actual type of that last field. +/// - A type implements `Unsize<dyn Trait + 'a>` if all of these conditions are met: +/// - The type implements `Trait`. +/// - `Trait` is object safe. +/// - The type is sized. +/// - The type outlives `'a`. +/// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize<Foo<..., U1, ..., Un, ...>>` +/// where any number of (type and const) parameters may be changed if all of these conditions +/// are met: +/// - Only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`. +/// - All other parameters of the struct are equal. +/// - `Field<T1, ..., Tn>: Unsize<Field<U1, ..., Un>>`, where `Field<...>` stands for the actual +/// type of the struct's last field. /// /// `Unsize` is used along with [`ops::CoerceUnsized`] to allow /// "user-defined" containers such as [`Rc`] to contain dynamically-sized diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 855bb1675c5..8a4070ebd96 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -374,6 +374,9 @@ impl<T> MaybeUninit<T> { /// assert_eq!(x, (0, false)); /// ``` /// + /// This can be used in const contexts, such as to indicate the end of static arrays for + /// plugin registration. + /// /// *Incorrect* usage of this function: calling `x.zeroed().assume_init()` /// when `0` is not a valid bit-pattern for the type: /// @@ -387,17 +390,19 @@ impl<T> MaybeUninit<T> { /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. /// // This is undefined behavior. ⚠️ /// ``` - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_maybe_uninit_zeroed", issue = "91850")] - #[must_use] #[inline] + #[must_use] #[rustc_diagnostic_item = "maybe_uninit_zeroed"] + #[stable(feature = "maybe_uninit", since = "1.36.0")] + // These are OK to allow since we do not leak &mut to user-visible API + #[rustc_allow_const_fn_unstable(const_mut_refs)] + #[rustc_allow_const_fn_unstable(const_ptr_write)] + #[rustc_allow_const_fn_unstable(const_maybe_uninit_as_mut_ptr)] + #[rustc_const_stable(feature = "const_maybe_uninit_zeroed", since = "CURRENT_RUSTC_VERSION")] pub const fn zeroed() -> MaybeUninit<T> { let mut u = MaybeUninit::<T>::uninit(); // SAFETY: `u.as_mut_ptr()` points to allocated memory. - unsafe { - u.as_mut_ptr().write_bytes(0u8, 1); - } + unsafe { u.as_mut_ptr().write_bytes(0u8, 1) }; u } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 8792134cdc8..caf16827ad0 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -647,7 +647,8 @@ pub const fn needs_drop<T: ?Sized>() -> bool { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] #[track_caller] -pub unsafe fn zeroed<T>() -> T { +#[rustc_const_stable(feature = "const_mem_zeroed", since = "CURRENT_RUSTC_VERSION")] +pub const unsafe fn zeroed<T>() -> T { // SAFETY: the caller must guarantee that an all-zero value is valid for `T`. unsafe { intrinsics::assert_zero_valid::<T>(); @@ -1054,6 +1055,7 @@ pub const fn copy<T: Copy>(x: &T) -> T { /// ``` #[inline] #[must_use] +#[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_transmute_copy", since = "1.74.0")] pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst { @@ -1294,13 +1296,63 @@ impl<T> SizedTypeProperties for T {} /// /// Structs, enums, unions and tuples are supported. /// -/// Nested field accesses may be used, but not array indexes like in `C`'s `offsetof`. +/// Nested field accesses may be used, but not array indexes. /// /// Enum variants may be traversed as if they were fields. Variants themselves do /// not have an offset. /// +/// Visibility is respected - all types and fields must be visible to the call site: +/// +/// ``` +/// #![feature(offset_of)] +/// +/// mod nested { +/// #[repr(C)] +/// pub struct Struct { +/// private: u8, +/// } +/// } +/// +/// // assert_eq!(mem::offset_of!(nested::Struct, private), 0); +/// // ^^^ error[E0616]: field `private` of struct `Struct` is private +/// ``` +/// /// Note that type layout is, in general, [subject to change and -/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). +/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If +/// layout stability is required, consider using an [explicit `repr` attribute]. +/// +/// Rust guarantees that the offset of a given field within a given type will not +/// change over the lifetime of the program. However, two different compilations of +/// the same program may result in different layouts. Also, even within a single +/// program execution, no guarantees are made about types which are *similar* but +/// not *identical*, e.g.: +/// +/// ``` +/// #![feature(offset_of)] +/// +/// struct Wrapper<T, U>(T, U); +/// +/// type A = Wrapper<u8, u8>; +/// type B = Wrapper<u8, i8>; +/// +/// // Not necessarily identical even though `u8` and `i8` have the same layout! +/// // assert!(mem::offset_of!(A, 1), mem::offset_of!(B, 1)); +/// +/// #[repr(transparent)] +/// struct U8(u8); +/// +/// type C = Wrapper<u8, U8>; +/// +/// // Not necessarily identical even though `u8` and `U8` have the same layout! +/// // assert!(mem::offset_of!(A, 1), mem::offset_of!(C, 1)); +/// +/// struct Empty<T>(core::marker::PhantomData<T>); +/// +/// // Not necessarily identical even though `PhantomData` always has the same layout! +/// // assert!(mem::offset_of!(Empty<u8>, 0), mem::offset_of!(Empty<i8>, 0)); +/// ``` +/// +/// [explicit `repr` attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations /// /// # Examples /// @@ -1329,6 +1381,17 @@ impl<T> SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// +/// #[repr(u8)] +/// enum Enum { +/// A(u8, u16), +/// B { one: u8, two: u16 }, +/// } +/// +/// # #[cfg(not(bootstrap))] +/// assert_eq!(mem::offset_of!(Enum, A.0), 1); +/// # #[cfg(not(bootstrap))] +/// assert_eq!(mem::offset_of!(Enum, B.two), 2); +/// /// # #[cfg(not(bootstrap))] /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index d6f2f5ca366..99adbb91599 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -3,40 +3,107 @@ /// In addition to being used for explicit dereferencing operations with the /// (unary) `*` operator in immutable contexts, `Deref` is also used implicitly /// by the compiler in many circumstances. This mechanism is called -/// ['`Deref` coercion'][more]. In mutable contexts, [`DerefMut`] is used. +/// ["`Deref` coercion"][coercion]. In mutable contexts, [`DerefMut`] is used and +/// mutable deref coercion similarly occurs. /// -/// Implementing `Deref` for smart pointers makes accessing the data behind them -/// convenient, which is why they implement `Deref`. On the other hand, the -/// rules regarding `Deref` and [`DerefMut`] were designed specifically to -/// accommodate smart pointers. Because of this, **`Deref` should only be -/// implemented for smart pointers** to avoid confusion. +/// **Warning:** Deref coercion is a powerful language feature which has +/// far-reaching implications for every type that implements `Deref`. The +/// compiler will silently insert calls to `Deref::deref`. For this reason, one +/// should be careful about implementing `Deref` and only do so when deref +/// coercion is desirable. See [below][implementing] for advice on when this is +/// typically desirable or undesirable. /// -/// For similar reasons, **this trait should never fail**. Failure during -/// dereferencing can be extremely confusing when `Deref` is invoked implicitly. +/// Types that implement `Deref` or `DerefMut` are often called "smart +/// pointers" and the mechanism of deref coercion has been specifically designed +/// to facilitate the pointer-like behaviour that name suggests. Often, the +/// purpose of a "smart pointer" type is to change the ownership semantics +/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the +/// storage semantics of a contained value (for example, [`Box`][box]). /// -/// Violating these requirements is a logic error. The behavior resulting from a logic error is not -/// specified, but users of the trait must ensure that such logic errors do *not* result in -/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this -/// method. +/// # Deref coercion /// -/// # More on `Deref` coercion +/// If `T` implements `Deref<Target = U>`, and `v` is a value of type `T`, then: /// -/// If `T` implements `Deref<Target = U>`, and `x` is a value of type `T`, then: -/// -/// * In immutable contexts, `*x` (where `T` is neither a reference nor a raw pointer) -/// is equivalent to `*Deref::deref(&x)`. +/// * In immutable contexts, `*v` (where `T` is neither a reference nor a raw +/// pointer) is equivalent to `*Deref::deref(&v)`. /// * Values of type `&T` are coerced to values of type `&U` -/// * `T` implicitly implements all the (immutable) methods of the type `U`. +/// * `T` implicitly implements all the methods of the type `U` which take the +/// `&self` receiver. /// /// For more details, visit [the chapter in *The Rust Programming Language*][book] /// as well as the reference sections on [the dereference operator][ref-deref-op], -/// [method resolution] and [type coercions]. +/// [method resolution], and [type coercions]. +/// +/// # When to implement `Deref` or `DerefMut` +/// +/// The same advice applies to both deref traits. In general, deref traits +/// **should** be implemented if: +/// +/// 1. a value of the type transparently behaves like a value of the target +/// type; +/// 1. the implementation of the deref function is cheap; and +/// 1. users of the type will not be surprised by any deref coercion behaviour. +/// +/// In general, deref traits **should not** be implemented if: +/// +/// 1. the deref implementations could fail unexpectedly; or +/// 1. the type has methods that are likely to collide with methods on the +/// target type; or +/// 1. committing to deref coercion as part of the public API is not desirable. +/// +/// Note that there's a large difference between implementing deref traits +/// generically over many target types, and doing so only for specific target +/// types. +/// +/// Generic implementations, such as for [`Box<T>`][box] (which is generic over +/// every type and dereferences to `T`) should be careful to provide few or no +/// methods, since the target type is unknown and therefore every method could +/// collide with one on the target type, causing confusion for users. +/// `impl<T> Box<T>` has no methods (though several associated functions), +/// partly for this reason. +/// +/// Specific implementations, such as for [`String`][string] (whose `Deref` +/// implementation has `Target = str`) can have many methods, since avoiding +/// collision is much easier. `String` and `str` both have many methods, and +/// `String` additionally behaves as if it has every method of `str` because of +/// deref coercion. The implementing type may also be generic while the +/// implementation is still specific in this sense; for example, [`Vec<T>`][vec] +/// dereferences to `[T]`, so methods of `T` are not applicable. +/// +/// Consider also that deref coericion means that deref traits are a much larger +/// part of a type's public API than any other trait as it is implicitly called +/// by the compiler. Therefore, it is advisable to consider whether this is +/// something you are comfortable supporting as a public API. +/// +/// The [`AsRef`] and [`Borrow`][core::borrow::Borrow] traits have very similar +/// signatures to `Deref`. It may be desirable to implement either or both of +/// these, whether in addition to or rather than deref traits. See their +/// documentation for details. +/// +/// # Fallibility +/// +/// **This trait's method should never unexpectedly fail**. Deref coercion means +/// the compiler will often insert calls to `Deref::deref` implicitly. Failure +/// during dereferencing can be extremely confusing when `Deref` is invoked +/// implicitly. In the majority of uses it should be infallible, though it may +/// be acceptable to panic if the type is misused through programmer error, for +/// example. +/// +/// However, infallibility is not enforced and therefore not guaranteed. +/// As such, `unsafe` code should not rely on infallibility in general for +/// soundness. /// /// [book]: ../../book/ch15-02-deref.html -/// [more]: #more-on-deref-coercion +/// [coercion]: #deref-coercion +/// [implementing]: #when-to-implement-deref-or-derefmut /// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator /// [method resolution]: ../../reference/expressions/method-call-expr.html /// [type coercions]: ../../reference/type-coercions.html +/// [box]: ../../alloc/boxed/struct.Box.html +/// [string]: ../../alloc/string/struct.String.html +/// [vec]: ../../alloc/vec/struct.Vec.html +/// [rc]: ../../alloc/rc/struct.Rc.html +/// [cow]: ../../alloc/borrow/enum.Cow.html /// /// # Examples /// @@ -107,30 +174,29 @@ impl<T: ?Sized> Deref for &mut T { /// In addition to being used for explicit dereferencing operations with the /// (unary) `*` operator in mutable contexts, `DerefMut` is also used implicitly /// by the compiler in many circumstances. This mechanism is called -/// ['`Deref` coercion'][more]. In immutable contexts, [`Deref`] is used. -/// -/// Implementing `DerefMut` for smart pointers makes mutating the data behind -/// them convenient, which is why they implement `DerefMut`. On the other hand, -/// the rules regarding [`Deref`] and `DerefMut` were designed specifically to -/// accommodate smart pointers. Because of this, **`DerefMut` should only be -/// implemented for smart pointers** to avoid confusion. +/// ["mutable deref coercion"][coercion]. In immutable contexts, [`Deref`] is used. /// -/// For similar reasons, **this trait should never fail**. Failure during -/// dereferencing can be extremely confusing when `DerefMut` is invoked -/// implicitly. +/// **Warning:** Deref coercion is a powerful language feature which has +/// far-reaching implications for every type that implements `DerefMut`. The +/// compiler will silently insert calls to `DerefMut::deref_mut`. For this +/// reason, one should be careful about implementing `DerefMut` and only do so +/// when mutable deref coercion is desirable. See [the `Deref` docs][implementing] +/// for advice on when this is typically desirable or undesirable. /// -/// Violating these requirements is a logic error. The behavior resulting from a logic error is not -/// specified, but users of the trait must ensure that such logic errors do *not* result in -/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this -/// method. +/// Types that implement `DerefMut` or `Deref` are often called "smart +/// pointers" and the mechanism of deref coercion has been specifically designed +/// to facilitate the pointer-like behaviour that name suggests. Often, the +/// purpose of a "smart pointer" type is to change the ownership semantics +/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the +/// storage semantics of a contained value (for example, [`Box`][box]). /// -/// # More on `Deref` coercion +/// # Mutable deref coercion /// -/// If `T` implements `DerefMut<Target = U>`, and `x` is a value of type `T`, +/// If `T` implements `DerefMut<Target = U>`, and `v` is a value of type `T`, /// then: /// -/// * In mutable contexts, `*x` (where `T` is neither a reference nor a raw pointer) -/// is equivalent to `*DerefMut::deref_mut(&mut x)`. +/// * In mutable contexts, `*v` (where `T` is neither a reference nor a raw pointer) +/// is equivalent to `*DerefMut::deref_mut(&mut v)`. /// * Values of type `&mut T` are coerced to values of type `&mut U` /// * `T` implicitly implements all the (mutable) methods of the type `U`. /// @@ -138,11 +204,29 @@ impl<T: ?Sized> Deref for &mut T { /// as well as the reference sections on [the dereference operator][ref-deref-op], /// [method resolution] and [type coercions]. /// +/// # Fallibility +/// +/// **This trait's method should never unexpectedly fail**. Deref coercion means +/// the compiler will often insert calls to `DerefMut::deref_mut` implicitly. +/// Failure during dereferencing can be extremely confusing when `DerefMut` is +/// invoked implicitly. In the majority of uses it should be infallible, though +/// it may be acceptable to panic if the type is misused through programmer +/// error, for example. +/// +/// However, infallibility is not enforced and therefore not guaranteed. +/// As such, `unsafe` code should not rely on infallibility in general for +/// soundness. +/// /// [book]: ../../book/ch15-02-deref.html -/// [more]: #more-on-deref-coercion +/// [coercion]: #mutable-deref-coercion +/// [implementing]: Deref#when-to-implement-deref-or-derefmut /// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator /// [method resolution]: ../../reference/expressions/method-call-expr.html /// [type coercions]: ../../reference/type-coercions.html +/// [box]: ../../alloc/boxed/struct.Box.html +/// [string]: ../../alloc/string/struct.String.html +/// [rc]: ../../alloc/rc/struct.Rc.html +/// [cow]: ../../alloc/borrow/enum.Cow.html /// /// # Examples /// diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 20f0bba4c13..51e304dd7c2 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -56,7 +56,7 @@ use crate::marker::Tuple; #[lang = "fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( on( Args = "()", note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" @@ -67,9 +67,9 @@ use crate::marker::Tuple; // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), - message = "expected a `{Fn}<{Args}>` closure, found `{Self}`", - label = "expected an `Fn<{Args}>` closure, found `{Self}`" -)] + message = "expected a `{Trait}` closure, found `{Self}`", + label = "expected an `{Trait}` closure, found `{Self}`" +))] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] // FIXME(effects) #[const_trait] @@ -143,7 +143,7 @@ pub trait Fn<Args: Tuple>: FnMut<Args> { #[lang = "fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( on( Args = "()", note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" @@ -154,9 +154,9 @@ pub trait Fn<Args: Tuple>: FnMut<Args> { // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), - message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`", - label = "expected an `FnMut<{Args}>` closure, found `{Self}`" -)] + message = "expected a `{Trait}` closure, found `{Self}`", + label = "expected an `{Trait}` closure, found `{Self}`" +))] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] // FIXME(effects) #[const_trait] @@ -222,7 +222,7 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> { #[lang = "fn_once"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( on( Args = "()", note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" @@ -233,9 +233,9 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> { // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), - message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`", - label = "expected an `FnOnce<{Args}>` closure, found `{Self}`" -)] + message = "expected a `{Trait}` closure, found `{Self}`", + label = "expected an `{Trait}` closure, found `{Self}`" +))] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] // FIXME(effects) #[const_trait] diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index fd8271b1344..35654d0b853 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -8,8 +8,8 @@ //! trait, but since the assignment operator (`=`) has no backing trait, there //! is no way of overloading its semantics. Additionally, this module does not //! provide any mechanism to create new operators. If traitless overloading or -//! custom operators are required, you should look toward macros or compiler -//! plugins to extend Rust's syntax. +//! custom operators are required, you should look toward macros to extend +//! Rust's syntax. //! //! Implementations of operator traits should be unsurprising in their //! respective contexts, keeping in mind their usual meanings and diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 12de349d22b..acf3dfbdf4c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -119,15 +119,21 @@ //! # Representation //! //! Rust guarantees to optimize the following types `T` such that -//! [`Option<T>`] has the same size and alignment as `T`: -//! -//! * [`Box<U>`] -//! * `&U` -//! * `&mut U` -//! * `fn`, `extern "C" fn`[^extern_fn] -//! * [`num::NonZero*`] -//! * [`ptr::NonNull<U>`] -//! * `#[repr(transparent)]` struct around one of the types in this list. +//! [`Option<T>`] has the same size and alignment as `T`. In some +//! of these cases, Rust further guarantees that +//! `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and +//! produces `Option::<T>::None`. These cases are identified by the +//! second column: +//! +//! | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? | +//! |---------------------------------------------------------------------|----------------------------------------------------------------------| +//! | [`Box<U>`] | when `U: Sized` | +//! | `&U` | when `U: Sized` | +//! | `&mut U` | when `U: Sized` | +//! | `fn`, `extern "C" fn`[^extern_fn] | always | +//! | [`num::NonZero*`] | always | +//! | [`ptr::NonNull<U>`] | when `U: Sized` | +//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type | //! //! [^extern_fn]: this remains true for any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) //! diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index f3695d16d7a..87e49210874 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -283,7 +283,7 @@ mod prim_never {} /// `char` type. For technical reasons, there is additional, separate /// documentation in [the `std::char` module](char/index.html) as well. /// -/// # Validity +/// # Validity and Layout /// /// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]' /// other than a [surrogate code point]. This has a fixed numerical definition: @@ -291,7 +291,7 @@ mod prim_never {} /// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF. /// /// No `char` may be constructed, whether as a literal or at runtime, that is not a -/// Unicode scalar value: +/// Unicode scalar value. Violating this rule causes undefined behavior. /// /// ```compile_fail /// // Each of these is a compiler error @@ -308,9 +308,10 @@ mod prim_never {} /// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// -/// USVs are also the exact set of values that may be encoded in UTF-8. Because -/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store -/// any `char` in a `str` or read any character from a `str` as a `char`. +/// Unicode scalar values are also the exact set of values that may be encoded in UTF-8. Because +/// `char` values are Unicode scalar values and functions may assume [incoming `str` values are +/// valid UTF-8](primitive.str.html#invariant), it is safe to store any `char` in a `str` or read +/// any character from a `str` as a `char`. /// /// The gap in valid `char` values is understood by the compiler, so in the /// below example the two ranges are understood to cover the whole range of @@ -324,11 +325,17 @@ mod prim_never {} /// }; /// ``` /// -/// All USVs are valid `char` values, but not all of them represent a real -/// character. Many USVs are not currently assigned to a character, but may be -/// in the future ("reserved"); some will never be a character -/// ("noncharacters"); and some may be given different meanings by different -/// users ("private use"). +/// All Unicode scalar values are valid `char` values, but not all of them represent a real +/// character. Many Unicode scalar values are not currently assigned to a character, but may be in +/// the future ("reserved"); some will never be a character ("noncharacters"); and some may be given +/// different meanings by different users ("private use"). +/// +/// `char` is guaranteed to have the same size and alignment as `u32` on all +/// platforms. +/// ``` +/// use std::alloc::Layout; +/// assert_eq!(Layout::new::<char>(), Layout::new::<u32>()); +/// ``` /// /// [Unicode code point]: https://www.unicode.org/glossary/#code_point /// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value @@ -887,8 +894,6 @@ mod prim_slice {} /// type. It is usually seen in its borrowed form, `&str`. It is also the type /// of string literals, `&'static str`. /// -/// String slices are always valid UTF-8. -/// /// # Basic Usage /// /// String literals are string slices: @@ -942,6 +947,14 @@ mod prim_slice {} /// Note: This example shows the internals of `&str`. `unsafe` should not be /// used to get a string slice under normal circumstances. Use `as_str` /// instead. +/// +/// # Invariant +/// +/// Rust libraries may assume that string slices are always valid UTF-8. +/// +/// Constructing a non-UTF-8 string slice is not immediate undefined behavior, but any function +/// called on a string slice may assume that it is valid UTF-8, which means that a non-UTF-8 string +/// slice can lead to undefined behavior down the road. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str {} diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 5c2e18745ea..20498b16cb2 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -565,3 +565,24 @@ fn offset_of_addr() { assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr()); assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr()); } + +#[test] +fn const_maybe_uninit_zeroed() { + // Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term) + #[repr(C)] + struct Foo { + a: Option<&'static str>, + b: Bar, + c: f32, + d: *const u8, + } + #[repr(C)] + struct Bar(usize); + struct FooPtr(*const Foo); + unsafe impl Sync for FooPtr {} + + static UNINIT: FooPtr = FooPtr([unsafe { MaybeUninit::zeroed().assume_init() }].as_ptr()); + const SIZE: usize = size_of::<Foo>(); + + assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]); +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 2eb7608c7ae..f3e79b28faf 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.149", default-features = false, features = ['rustc-dep-of-std'], public = true } -compiler_builtins = { version = "0.1.100" } +compiler_builtins = { version = "0.1.103" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index bfef3e67240..626ca6cf2e7 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -59,6 +59,7 @@ o("missing-tools", "dist.missing-tools", "allow failures when building tools") o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++") o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard") o("patch-binaries-for-nix", "build.patch-binaries-for-nix", "whether patch binaries for usage with Nix toolchains") +o("new-symbol-mangling", "rust.new-symbol-mangling", "use symbol-mangling-version v0") v("llvm-cflags", "llvm.cflags", "build LLVM with these extra compiler flags") v("llvm-cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 441931e415c..1eed534150b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -45,15 +45,42 @@ pub struct Std { /// When using download-rustc, we need to use a new build of `std` for running unit tests of Std itself, /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overriden by `builder.ensure` from other steps. force_recompile: bool, + extra_rust_args: &'static [&'static str], } impl Std { pub fn new(compiler: Compiler, target: TargetSelection) -> Self { - Self { target, compiler, crates: Default::default(), force_recompile: false } + Self { + target, + compiler, + crates: Default::default(), + force_recompile: false, + extra_rust_args: &[], + } } pub fn force_recompile(compiler: Compiler, target: TargetSelection) -> Self { - Self { target, compiler, crates: Default::default(), force_recompile: true } + Self { + target, + compiler, + crates: Default::default(), + force_recompile: true, + extra_rust_args: &[], + } + } + + pub fn new_with_extra_rust_args( + compiler: Compiler, + target: TargetSelection, + extra_rust_args: &'static [&'static str], + ) -> Self { + Self { + target, + compiler, + crates: Default::default(), + force_recompile: false, + extra_rust_args, + } } } @@ -81,6 +108,7 @@ impl Step for Std { target: run.target, crates, force_recompile: false, + extra_rust_args: &[], }); } @@ -188,6 +216,9 @@ impl Step for Std { if target.is_synthetic() { cargo.env("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET", "1"); } + for rustflag in self.extra_rust_args.into_iter() { + cargo.rustflag(rustflag); + } let _guard = builder.msg( Kind::Build, diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 6e80c55c8ce..b578c5ec295 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1298,10 +1298,6 @@ impl Step for CodegenBackend { } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - if builder.config.dry_run() { - return None; - } - // This prevents rustc_codegen_cranelift from being built for "dist" // or "install" on the stable/beta channels. It is not yet stable and // should not be included. @@ -1309,10 +1305,6 @@ impl Step for CodegenBackend { return None; } - if !builder.config.rust_codegen_backends.contains(&self.backend) { - return None; - } - if self.backend == "cranelift" { if !target_supports_cranelift_backend(self.compiler.host) { builder.info("target not supported by rustc_codegen_cranelift. skipping"); @@ -1351,15 +1343,12 @@ impl Step for CodegenBackend { let backends_dst = PathBuf::from("lib").join(&backends_rel); let backend_name = format!("rustc_codegen_{}", backend); - let mut found_backend = false; for backend in fs::read_dir(&backends_src).unwrap() { let file_name = backend.unwrap().file_name(); if file_name.to_str().unwrap().contains(&backend_name) { tarball.add_file(backends_src.join(file_name), &backends_dst, 0o644); - found_backend = true; } } - assert!(found_backend); Some(tarball.generate()) } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8c6878f61ba..e2b515a3086 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3063,6 +3063,7 @@ impl Step for CodegenCranelift { // FIXME handle vendoring for source tarballs before removing the --skip-test below let download_dir = builder.out.join("cg_clif_download"); + // FIXME: Uncomment the `prepare` command below once vendoring is implemented. /* let mut prepare_cargo = build_cargo(); prepare_cargo.arg("--").arg("prepare").arg("--download-dir").arg(&download_dir); @@ -3094,3 +3095,123 @@ impl Step for CodegenCranelift { builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast()); } } + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CodegenGCC { + compiler: Compiler, + target: TargetSelection, +} + +impl Step for CodegenGCC { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.paths(&["compiler/rustc_codegen_gcc"]) + } + + fn make_run(run: RunConfig<'_>) { + let builder = run.builder; + let host = run.build_triple(); + let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + + if builder.doc_tests == DocTests::Only { + return; + } + + let triple = run.target.triple; + let target_supported = + if triple.contains("linux") { triple.contains("x86_64") } else { false }; + if !target_supported { + builder.info("target not supported by rustc_codegen_gcc. skipping"); + return; + } + + if builder.remote_tested(run.target) { + builder.info("remote testing is not supported by rustc_codegen_gcc. skipping"); + return; + } + + if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("gcc")) { + builder.info("gcc not in rust.codegen-backends. skipping"); + return; + } + + builder.ensure(CodegenGCC { compiler, target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let compiler = self.compiler; + let target = self.target; + + builder.ensure(compile::Std::new_with_extra_rust_args( + compiler, + target, + &["-Csymbol-mangling-version=v0", "-Cpanic=abort"], + )); + + // If we're not doing a full bootstrap but we're testing a stage2 + // version of libstd, then what we're actually testing is the libstd + // produced in stage1. Reflect that here by updating the compiler that + // we're working with automatically. + let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + + let build_cargo = || { + let mut cargo = builder.cargo( + compiler, + Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works + SourceType::InTree, + target, + "run", + ); + cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc")); + cargo + .arg("--manifest-path") + .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml")); + compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + + // Avoid incremental cache issues when changing rustc + cargo.env("CARGO_BUILD_INCREMENTAL", "false"); + cargo.rustflag("-Cpanic=abort"); + + cargo + }; + + builder.info(&format!( + "{} GCC stage{} ({} -> {})", + Kind::Test.description(), + compiler.stage, + &compiler.host, + target + )); + let _time = helpers::timeit(&builder); + + // FIXME: Uncomment the `prepare` command below once vendoring is implemented. + /* + let mut prepare_cargo = build_cargo(); + prepare_cargo.arg("--").arg("prepare"); + #[allow(deprecated)] + builder.config.try_run(&mut prepare_cargo.into()).unwrap(); + */ + + let mut cargo = build_cargo(); + + cargo + .arg("--") + .arg("test") + .arg("--use-system-gcc") + .arg("--use-backend") + .arg("gcc") + .arg("--out-dir") + .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc")) + .arg("--release") + .arg("--no-default-features") + .arg("--mini-tests") + .arg("--std-tests"); + cargo.args(builder.config.test_args()); + + let mut cmd: Command = cargo.into(); + builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast()); + } +} diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 90e09d12a9d..44cdbe38de3 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -737,6 +737,7 @@ impl<'a> Builder<'a> { test::Debuginfo, test::UiFullDeps, test::CodegenCranelift, + test::CodegenGCC, test::Rustdoc, test::RunCoverageRustdoc, test::Pretty, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d7f49a6d11b..303c910d49f 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1197,11 +1197,10 @@ impl Build { .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) .collect::<Vec<String>>(); - // If we're compiling on macOS then we add a few unconditional flags - // indicating that we want libc++ (more filled out than libstdc++) and - // we want to compile for 10.7. This way we can ensure that + // If we're compiling C++ on macOS then we add a flag indicating that + // we want libc++ (more filled out than libstdc++), ensuring that // LLVM/etc are all properly compiled. - if target.contains("apple-darwin") { + if matches!(c, CLang::Cxx) && target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); } diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock new file mode 100644 index 00000000000..e983edf205c --- /dev/null +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "r-efi" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575fc2d9b3da54adbdfaddf6eca48fec256d977c8630a1750b8991347d1ac911" + +[[package]] +name = "uefi_qemu_test" +version = "0.0.0" +dependencies = [ + "r-efi", +] diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile index 444e0275d48..cefdcad7643 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile @@ -24,6 +24,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ nodejs \ mingw-w64 \ + libgccjit-12-dev \ && rm -rf /var/lib/apt/lists/* # Install powershell (universal package) so we can test x.ps1 on Linux @@ -34,6 +35,9 @@ RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# Make `libgccjit.so` accessible to the linker. +RUN ln -s /usr/lib/gcc/x86_64-linux-gnu/12/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so + # We are disabling CI LLVM since this builder is intentionally using a host # LLVM, rather than the typical src/llvm-project LLVM. ENV NO_DOWNLOAD_CI_LLVM 1 @@ -47,6 +51,7 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --llvm-root=/usr/lib/llvm-15 \ --enable-llvm-link-shared \ + $USE_NEW_MANGLING \ --set rust.thin-lto-import-instr-limit=10 COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh index 7d40db2ee23..2eb751ca376 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh @@ -4,7 +4,13 @@ set -ex # Only run the stage 1 tests on merges, not on PR CI jobs. if [[ -z "${PR_CI_JOB}" ]]; then - ../x.py --stage 1 test --skip src/tools/tidy + # When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen + # tests as it will fail them. + if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then + ../x.py --stage 1 test --skip src/tools/tidy --skip tests/codegen + else + ../x.py --stage 1 test --skip src/tools/tidy + fi # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have @@ -19,8 +25,14 @@ if [[ -z "${PR_CI_JOB}" ]]; then ../x.py --stage 1 test tests/ui-fulldeps fi +# When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen +# tests as it will fail them. # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. -../x.py --stage 2 test --skip src/tools/tidy +if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then + ../x.py --stage 2 test --skip src/tools/tidy --skip tests/codegen +else + ../x.py --stage 2 test --skip src/tools/tidy +fi # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index b0eeff0c576..82385ea15b7 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ sudo \ xz-utils \ tidy \ + libgccjit-12-dev \ \ # Install dependencies for chromium browser gconf-service \ @@ -61,6 +62,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# Make `libgccjit.so` accessible. +RUN ln -s /usr/lib/gcc/x86_64-linux-gnu/12/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so +# Fix rustc_codegen_gcc lto issues. +ENV GCC_EXEC_PREFIX="/usr/lib/gcc/" + COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/ RUN curl -sL https://nodejs.org/dist/v14.20.0/node-v14.20.0-linux-x64.tar.xz | tar -xJ @@ -81,7 +87,8 @@ RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --u ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ - --save-toolstates=/tmp/toolstate/toolstates.json + --save-toolstates=/tmp/toolstate/toolstates.json \ + --enable-new-symbol-mangling ENV HOST_TARGET x86_64-unknown-linux-gnu diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 0b535532f69..a2891ef9563 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -267,10 +267,24 @@ fi SUMMARY_FILE=github-summary.md touch $objdir/${SUMMARY_FILE} +extra_env="" +if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then + extra_env="$EXTRA_ENV --env ENABLE_GCC_CODEGEN=1" + # If `ENABLE_GCC_CODEGEN` is set and not empty, we add the `--enable-new-symbol-mangling` + # argument to `RUST_CONFIGURE_ARGS` and set the `GCC_EXEC_PREFIX` environment variable. + # `cg_gcc` doesn't support the legacy mangling so we need to enforce the new one + # if we run `cg_gcc` tests. + extra_env="$EXTRA_ENV --env USE_NEW_MANGLING=--enable-new-symbol-mangling" + # Fix rustc_codegen_gcc lto issues. + extra_env="$EXTRA_ENV --env GCC_EXEC_PREFIX=/usr/lib/gcc/" + echo "Setting extra environment values for docker: $extra_env" +fi + docker \ run \ --workdir /checkout/obj \ --env SRC=/checkout \ + $extra_env \ $args \ --env CARGO_HOME=/cargo \ --env DEPLOY \ @@ -288,7 +302,6 @@ docker \ --env DIST_TRY_BUILD \ --env PR_CI_JOB \ --env OBJDIR_ON_HOST="$objdir" \ - --env CODEGEN_BACKENDS \ --init \ --rm \ rust-ci \ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 2feb51920df..b415eb5961b 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -331,6 +331,8 @@ jobs: <<: *job-linux-4c - name: x86_64-gnu-llvm-15 + env: + ENABLE_GCC_CODEGEN: "1" <<: *job-linux-16c - name: x86_64-gnu-tools diff --git a/src/ci/run.sh b/src/ci/run.sh index 9a63bb5c91c..31ef55216b9 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -126,8 +126,15 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir" - # Test the Cranelift backend in CI. Bootstrap knows which targets to run tests on. - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift" + # When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen + # tests as it will fail them. + if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then + # Test the Cranelift and GCC backends in CI. Bootstrap knows which targets to run tests on. + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift,gcc" + else + # Test the Cranelift backend in CI. Bootstrap knows which targets to run tests on. + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift" + fi # We enable this for non-dist builders, since those aren't trying to produce # fresh binaries. We currently don't entirely support distributing a fresh diff --git a/src/doc/book b/src/doc/book -Subproject 3dca2fc50b922a8efb94903b9fee8bb42ab48f3 +Subproject 5b6c1ceaa62ecbd6caef08df39b33b3938e99de diff --git a/src/doc/guide-plugins.md b/src/doc/guide-plugins.md index 6c511548789..ccb9bb2ee83 100644 --- a/src/doc/guide-plugins.md +++ b/src/doc/guide-plugins.md @@ -1,4 +1,3 @@ % The (old) Rust Compiler Plugins Guide -This content has moved into -[the Unstable Book](unstable-book/language-features/plugin.html). +Support for plugins has been removed. diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md deleted file mode 100644 index d9421a428f1..00000000000 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ /dev/null @@ -1,114 +0,0 @@ -# `plugin` - -The tracking issue for this feature is: [#29597] - -[#29597]: https://github.com/rust-lang/rust/issues/29597 - - -This feature is part of "compiler plugins." It will often be used with the -`rustc_private` feature. - ------------------------- - -`rustc` can load compiler plugins, which are user-provided libraries that -extend the compiler's behavior with new lint checks, etc. - -A plugin is a dynamic library crate with a designated *registrar* function that -registers extensions with `rustc`. Other crates can load these extensions using -the crate attribute `#![plugin(...)]`. See the -`rustc_driver::plugin` documentation for more about the -mechanics of defining and loading a plugin. - -In the vast majority of cases, a plugin should *only* be used through -`#![plugin]` and not through an `extern crate` item. Linking a plugin would -pull in all of librustc_ast and librustc as dependencies of your crate. This is -generally unwanted unless you are building another plugin. - -The usual practice is to put compiler plugins in their own crate, separate from -any `macro_rules!` macros or ordinary Rust code meant to be used by consumers -of a library. - -# Lint plugins - -Plugins can extend [Rust's lint -infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with -additional checks for code style, safety, etc. Now let's write a plugin -[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs) -that warns about any item named `lintme`. - -```rust,ignore (requires-stage-2) -#![feature(rustc_private)] - -extern crate rustc_ast; - -// Load rustc as a plugin to get macros -extern crate rustc_driver; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_ast::ast; -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; - -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint_pass!(Pass => [TEST_LINT]); - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| Box::new(Pass)); -} -``` - -Then code like - -```rust,ignore (requires-plugin) -#![feature(plugin)] -#![plugin(lint_plugin_test)] - -fn lintme() { } -``` - -will produce a compiler warning: - -```txt -foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default -foo.rs:4 fn lintme() { } - ^~~~~~~~~~~~~~~ -``` - -The components of a lint plugin are: - -* one or more `declare_lint!` invocations, which define static `Lint` structs; - -* a struct holding any state needed by the lint pass (here, none); - -* a `LintPass` - implementation defining how to check each syntax element. A single - `LintPass` may call `span_lint` for several different `Lint`s, but should - register them all through the `get_lints` method. - -Lint passes are syntax traversals, but they run at a late stage of compilation -where type information is available. `rustc`'s [built-in -lints](https://github.com/rust-lang/rust/blob/master/compiler/rustc_lint_defs/src/builtin.rs) -mostly use the same infrastructure as lint plugins, and provide examples of how -to access type information. - -Lints defined by plugins are controlled by the usual [attributes and compiler -flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g. -`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the -first argument to `declare_lint!`, with appropriate case and punctuation -conversion. - -You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, -including those provided by plugins loaded by `foo.rs`. diff --git a/src/etc/test-float-parse/Cargo.lock b/src/etc/test-float-parse/Cargo.lock new file mode 100644 index 00000000000..3f60423fed3 --- /dev/null +++ b/src/etc/test-float-parse/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "test-float-parse" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 6d7b227d0ad..a045be956ac 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -8,7 +8,7 @@ publish = false resolver = "1" [dependencies] -rand = "0.4" +rand = "0.8" [lib] name = "test_float_parse" diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 4907a55270b..ee7c0068eb4 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -1,9 +1,8 @@ use super::*; use rustc_resolve::rustdoc::{unindent_doc_fragments, DocFragment, DocFragmentKind}; -use rustc_span::create_default_session_globals_then; -use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::Symbol; +use rustc_span::{create_default_session_globals_then, DUMMY_SP}; fn create_doc_fragment(s: &str) -> Vec<DocFragment> { vec![DocFragment { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index aa728c26afc..2807dfed072 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1750,7 +1750,7 @@ pub(crate) fn markdown_links<'md, R>( } // do not actually include braces in the span let range = (open_brace + 1)..close_brace; - MarkdownLinkRange::Destination(range.clone()) + MarkdownLinkRange::Destination(range) }; let span_for_offset_forward = |span: Range<usize>, open: u8, close: u8| { @@ -1786,7 +1786,7 @@ pub(crate) fn markdown_links<'md, R>( } // do not actually include braces in the span let range = (open_brace + 1)..close_brace; - MarkdownLinkRange::Destination(range.clone()) + MarkdownLinkRange::Destination(range) }; let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 6da9e45a1da..50777134d70 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -10,8 +10,7 @@ use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::source_map::FileName; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, FileName, Symbol}; use super::print_item::{full_path, item_path, print_item}; use super::search_index::build_index; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 65e7c08d521..d226701ba4a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -991,7 +991,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } } - let (local, foreign) = + let (local, mut foreign) = implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cx)); let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = @@ -999,6 +999,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: synthetic.sort_by_cached_key(|i| ImplString::new(i, cx)); concrete.sort_by_cached_key(|i| ImplString::new(i, cx)); + foreign.sort_by_cached_key(|i| ImplString::new(i, cx)); if !foreign.is_empty() { write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index d01553b8e71..ce620c226de 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -13,8 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::source_map::FileName; -use rustc_span::sym; +use rustc_span::{sym, FileName}; use std::cell::RefCell; use std::ffi::OsStr; diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index b74a9392f27..b661ced0169 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -4,7 +4,7 @@ use std::io::prelude::*; use std::path::Path; use rustc_span::edition::Edition; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use crate::config::{Options, RenderOptions}; use crate::doctest::{Collector, GlobalTestOptions}; diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 79fc599e176..00d15a3ca8d 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -25,91 +25,85 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { Some(sp) => sp, None => item.attr_span(tcx), }; - tcx.struct_span_lint_hir( - crate::lint::INVALID_HTML_TAGS, - hir_id, - sp, - msg.to_string(), - |lint| { - use rustc_lint_defs::Applicability; - // If a tag looks like `<this>`, it might actually be a generic. - // We don't try to detect stuff `<like, this>` because that's not valid HTML, - // and we don't try to detect stuff `<like this>` because that's not valid Rust. - let mut generics_end = range.end; - if let Some(Some(mut generics_start)) = (is_open_tag - && dox[..generics_end].ends_with('>')) - .then(|| extract_path_backwards(&dox, range.start)) + tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| { + use rustc_lint_defs::Applicability; + // If a tag looks like `<this>`, it might actually be a generic. + // We don't try to detect stuff `<like, this>` because that's not valid HTML, + // and we don't try to detect stuff `<like this>` because that's not valid Rust. + let mut generics_end = range.end; + if let Some(Some(mut generics_start)) = (is_open_tag + && dox[..generics_end].ends_with('>')) + .then(|| extract_path_backwards(&dox, range.start)) + { + while generics_start != 0 + && generics_end < dox.len() + && dox.as_bytes()[generics_start - 1] == b'<' + && dox.as_bytes()[generics_end] == b'>' { - while generics_start != 0 - && generics_end < dox.len() - && dox.as_bytes()[generics_start - 1] == b'<' - && dox.as_bytes()[generics_end] == b'>' - { - generics_end += 1; - generics_start -= 1; - if let Some(new_start) = extract_path_backwards(&dox, generics_start) { - generics_start = new_start; - } - if let Some(new_end) = extract_path_forward(&dox, generics_end) { - generics_end = new_end; - } + generics_end += 1; + generics_start -= 1; + if let Some(new_start) = extract_path_backwards(&dox, generics_start) { + generics_start = new_start; } if let Some(new_end) = extract_path_forward(&dox, generics_end) { generics_end = new_end; } - let generics_sp = match source_span_for_markdown_range( - tcx, - &dox, - &(generics_start..generics_end), - &item.attrs.doc_strings, - ) { - Some(sp) => sp, - None => item.attr_span(tcx), - }; - // Sometimes, we only extract part of a path. For example, consider this: - // - // <[u32] as IntoIter<u32>>::Item - // ^^^^^ unclosed HTML tag `u32` - // - // We don't have any code for parsing fully-qualified trait paths. - // In theory, we could add it, but doing it correctly would require - // parsing the entire path grammar, which is problematic because of - // overlap between the path grammar and Markdown. - // - // The example above shows that ambiguity. Is `[u32]` intended to be an - // intra-doc link to the u32 primitive, or is it intended to be a slice? - // - // If the below conditional were removed, we would suggest this, which is - // not what the user probably wants. - // - // <[u32] as `IntoIter<u32>`>::Item - // - // We know that the user actually wants to wrap the whole thing in a code - // block, but the only reason we know that is because `u32` does not, in - // fact, implement IntoIter. If the example looks like this: - // - // <[Vec<i32>] as IntoIter<i32>::Item - // - // The ideal fix would be significantly different. - if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') - || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') - { - return lint; - } - // multipart form is chosen here because ``Vec<i32>`` would be confusing. - lint.multipart_suggestion( - "try marking as source code", - vec![ - (generics_sp.shrink_to_lo(), String::from("`")), - (generics_sp.shrink_to_hi(), String::from("`")), - ], - Applicability::MaybeIncorrect, - ); } + if let Some(new_end) = extract_path_forward(&dox, generics_end) { + generics_end = new_end; + } + let generics_sp = match source_span_for_markdown_range( + tcx, + &dox, + &(generics_start..generics_end), + &item.attrs.doc_strings, + ) { + Some(sp) => sp, + None => item.attr_span(tcx), + }; + // Sometimes, we only extract part of a path. For example, consider this: + // + // <[u32] as IntoIter<u32>>::Item + // ^^^^^ unclosed HTML tag `u32` + // + // We don't have any code for parsing fully-qualified trait paths. + // In theory, we could add it, but doing it correctly would require + // parsing the entire path grammar, which is problematic because of + // overlap between the path grammar and Markdown. + // + // The example above shows that ambiguity. Is `[u32]` intended to be an + // intra-doc link to the u32 primitive, or is it intended to be a slice? + // + // If the below conditional were removed, we would suggest this, which is + // not what the user probably wants. + // + // <[u32] as `IntoIter<u32>`>::Item + // + // We know that the user actually wants to wrap the whole thing in a code + // block, but the only reason we know that is because `u32` does not, in + // fact, implement IntoIter. If the example looks like this: + // + // <[Vec<i32>] as IntoIter<i32>::Item + // + // The ideal fix would be significantly different. + if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') + || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') + { + return lint; + } + // multipart form is chosen here because ``Vec<i32>`` would be confusing. + lint.multipart_suggestion( + "try marking as source code", + vec![ + (generics_sp.shrink_to_lo(), String::from("`")), + (generics_sp.shrink_to_hi(), String::from("`")), + ], + Applicability::MaybeIncorrect, + ); + } - lint - }, - ); + lint + }); }; let mut tags = Vec::new(); diff --git a/src/tools/cargo b/src/tools/cargo -Subproject b4d18d4bd3db6d872892f6c87c51a02999b8080 +Subproject 65e297d1ec0dee1a74800efe600b8dc163bcf5d diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml index 410ff53a251..99d80bec025 100644 --- a/src/tools/clippy/.github/workflows/clippy.yml +++ b/src/tools/clippy/.github/workflows/clippy.yml @@ -60,7 +60,7 @@ jobs: working-directory: clippy_lints - name: Test clippy_utils - run: cargo test --features deny-warnings,internal + run: cargo test --features deny-warnings working-directory: clippy_utils - name: Test rustc_tools_util diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 9b96f8dc253..f67233dec62 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -120,9 +120,13 @@ jobs: working-directory: clippy_lints - name: Test clippy_utils - run: cargo test --features deny-warnings,internal + run: cargo test --features deny-warnings working-directory: clippy_utils + - name: Test clippy_config + run: cargo test --features deny-warnings + working-directory: clippy_config + - name: Test rustc_tools_util run: cargo test --features deny-warnings working-directory: rustc_tools_util diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 26c9877dbff..87a96bdeba6 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5528,6 +5528,7 @@ Released 2018-09-13 [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints [`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast +[`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold @@ -5560,6 +5561,7 @@ Released 2018-09-13 [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice [`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect +[`unused_enumerate_index`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_enumerate_index [`unused_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label @@ -5589,6 +5591,7 @@ Released 2018-09-13 [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons +[`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 2c50addfd7d..4b6688a76b4 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -21,11 +21,12 @@ name = "clippy-driver" path = "src/driver.rs" [dependencies] +clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" -color-print = "0.3.4" # Sync version with Cargo +color-print = "0.3.4" anstream = "0.5.0" [dev-dependencies] diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index c7eeed17954..841a5b6d007 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -26,7 +26,7 @@ arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`) +**Default Value:** `[]` --- **Affected lints:** @@ -49,7 +49,7 @@ Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] ``` -**Default Value:** `[]` (`Vec<[String; 2]>`) +**Default Value:** `[]` --- **Affected lints:** @@ -65,7 +65,7 @@ Suppress checking of the passed type names in unary operations like "negation" ( arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] ``` -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`) +**Default Value:** `[]` --- **Affected lints:** @@ -75,7 +75,7 @@ arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] ## `avoid-breaking-exported-api` Suppress lints whenever the suggested change would cause breakage for other crates. -**Default Value:** `true` (`bool`) +**Default Value:** `true` --- **Affected lints:** @@ -98,9 +98,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat ## `msrv` -The minimum rust version that the project supports - -**Default Value:** `Msrv { stack: [] }` (`crate::Msrv`) +The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` --- **Affected lints:** @@ -157,7 +155,7 @@ The minimum rust version that the project supports ## `cognitive-complexity-threshold` The maximum cognitive complexity a function can have -**Default Value:** `25` (`u64`) +**Default Value:** `25` --- **Affected lints:** @@ -167,7 +165,7 @@ The maximum cognitive complexity a function can have ## `excessive-nesting-threshold` The maximum amount of nesting a block can reside in -**Default Value:** `0` (`u64`) +**Default Value:** `0` --- **Affected lints:** @@ -179,7 +177,7 @@ The list of disallowed names to lint about. NB: `bar` is not here since it has l `".."` can be used as part of the list to indicate that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`) +**Default Value:** `["foo", "baz", "quux"]` --- **Affected lints:** @@ -189,7 +187,7 @@ default configuration of Clippy. By default, any configuration will replace the ## `semicolon-inside-block-ignore-singleline` Whether to lint only if it's multiline. -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -199,7 +197,7 @@ Whether to lint only if it's multiline. ## `semicolon-outside-block-ignore-multiline` Whether to lint only if it's singleline. -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -213,9 +211,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -Default list: - -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`) +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -225,7 +221,7 @@ Default list: ## `too-many-arguments-threshold` The maximum number of argument a function or method can have -**Default Value:** `7` (`u64`) +**Default Value:** `7` --- **Affected lints:** @@ -235,7 +231,7 @@ The maximum number of argument a function or method can have ## `type-complexity-threshold` The maximum complexity a type can have -**Default Value:** `250` (`u64`) +**Default Value:** `250` --- **Affected lints:** @@ -245,7 +241,7 @@ The maximum complexity a type can have ## `single-char-binding-names-threshold` The maximum number of single char bindings a scope may have -**Default Value:** `4` (`u64`) +**Default Value:** `4` --- **Affected lints:** @@ -255,7 +251,7 @@ The maximum number of single char bindings a scope may have ## `too-large-for-stack` The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap -**Default Value:** `200` (`u64`) +**Default Value:** `200` --- **Affected lints:** @@ -266,7 +262,7 @@ The maximum size of objects (in bytes) that will be linted. Larger objects are o ## `enum-variant-name-threshold` The minimum number of enum variants for the lints about variant names to trigger -**Default Value:** `3` (`u64`) +**Default Value:** `3` --- **Affected lints:** @@ -276,7 +272,7 @@ The minimum number of enum variants for the lints about variant names to trigger ## `struct-field-name-threshold` The minimum number of struct fields for the lints about field names to trigger -**Default Value:** `3` (`u64`) +**Default Value:** `3` --- **Affected lints:** @@ -286,7 +282,7 @@ The minimum number of struct fields for the lints about field names to trigger ## `enum-variant-size-threshold` The maximum size of an enum's variant to avoid box suggestion -**Default Value:** `200` (`u64`) +**Default Value:** `200` --- **Affected lints:** @@ -296,7 +292,7 @@ The maximum size of an enum's variant to avoid box suggestion ## `verbose-bit-mask-threshold` The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' -**Default Value:** `1` (`u64`) +**Default Value:** `1` --- **Affected lints:** @@ -306,7 +302,7 @@ The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' ## `literal-representation-threshold` The lower bound for linting decimal literals -**Default Value:** `16384` (`u64`) +**Default Value:** `16384` --- **Affected lints:** @@ -314,9 +310,8 @@ The lower bound for linting decimal literals ## `trivial-copy-size-limit` -The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. - -**Default Value:** `None` (`Option<u64>`) +The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by +reference. By default there is no limit --- **Affected lints:** @@ -326,7 +321,7 @@ The maximum size (in bytes) to consider a `Copy` type for passing by value inste ## `pass-by-value-size-limit` The minimum size (in bytes) to consider a type for passing by reference instead of by value. -**Default Value:** `256` (`u64`) +**Default Value:** `256` --- **Affected lints:** @@ -336,7 +331,7 @@ The minimum size (in bytes) to consider a type for passing by reference instead ## `too-many-lines-threshold` The maximum number of lines a function or method can have -**Default Value:** `100` (`u64`) +**Default Value:** `100` --- **Affected lints:** @@ -346,7 +341,7 @@ The maximum number of lines a function or method can have ## `array-size-threshold` The maximum allowed size for arrays on the stack -**Default Value:** `512000` (`u64`) +**Default Value:** `512000` --- **Affected lints:** @@ -357,7 +352,7 @@ The maximum allowed size for arrays on the stack ## `stack-size-threshold` The maximum allowed stack size for functions in bytes -**Default Value:** `512000` (`u64`) +**Default Value:** `512000` --- **Affected lints:** @@ -367,7 +362,7 @@ The maximum allowed stack size for functions in bytes ## `vec-box-size-threshold` The size of the boxed type in bytes, where boxing in a `Vec` is allowed -**Default Value:** `4096` (`u64`) +**Default Value:** `4096` --- **Affected lints:** @@ -377,7 +372,7 @@ The size of the boxed type in bytes, where boxing in a `Vec` is allowed ## `max-trait-bounds` The maximum number of bounds a trait can have to be linted -**Default Value:** `3` (`u64`) +**Default Value:** `3` --- **Affected lints:** @@ -387,7 +382,7 @@ The maximum number of bounds a trait can have to be linted ## `max-struct-bools` The maximum number of bool fields a struct can have -**Default Value:** `3` (`u64`) +**Default Value:** `3` --- **Affected lints:** @@ -397,7 +392,7 @@ The maximum number of bool fields a struct can have ## `max-fn-params-bools` The maximum number of bool parameters a function can have -**Default Value:** `3` (`u64`) +**Default Value:** `3` --- **Affected lints:** @@ -407,7 +402,7 @@ The maximum number of bool parameters a function can have ## `warn-on-all-wildcard-imports` Whether to allow certain wildcard imports (prelude, super in tests). -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -417,7 +412,7 @@ Whether to allow certain wildcard imports (prelude, super in tests). ## `disallowed-macros` The list of disallowed macros, written as fully qualified paths. -**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) +**Default Value:** `[]` --- **Affected lints:** @@ -427,7 +422,7 @@ The list of disallowed macros, written as fully qualified paths. ## `disallowed-methods` The list of disallowed methods, written as fully qualified paths. -**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) +**Default Value:** `[]` --- **Affected lints:** @@ -437,7 +432,7 @@ The list of disallowed methods, written as fully qualified paths. ## `disallowed-types` The list of disallowed types, written as fully qualified paths. -**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) +**Default Value:** `[]` --- **Affected lints:** @@ -447,7 +442,7 @@ The list of disallowed types, written as fully qualified paths. ## `unreadable-literal-lint-fractions` Should the fraction of a decimal be linted to include separators. -**Default Value:** `true` (`bool`) +**Default Value:** `true` --- **Affected lints:** @@ -457,7 +452,7 @@ Should the fraction of a decimal be linted to include separators. ## `upper-case-acronyms-aggressive` Enables verbose mode. Triggers if there is more than one uppercase char next to each other -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -468,7 +463,7 @@ Enables verbose mode. Triggers if there is more than one uppercase char next to Whether the matches should be considered by the lint, and whether there should be filtering for common types. -**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`) +**Default Value:** `"WellKnownTypes"` --- **Affected lints:** @@ -478,11 +473,11 @@ be filtering for common types. ## `cargo-ignore-publish` For internal testing only, ignores the current `publish` settings in the Cargo manifest. -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** -* [`_cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata) +* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) ## `standard-macro-braces` @@ -492,7 +487,7 @@ A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If could be used with a full path two `MacroMatcher`s have to be added one with the full path `crate_name::macro_name` and one with just the macro name. -**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`) +**Default Value:** `[]` --- **Affected lints:** @@ -502,7 +497,7 @@ could be used with a full path two `MacroMatcher`s have to be added one with the ## `enforced-import-renames` The list of imports to always rename, a fully qualified path followed by the rename. -**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`) +**Default Value:** `[]` --- **Affected lints:** @@ -512,7 +507,7 @@ The list of imports to always rename, a fully qualified path followed by the ren ## `allowed-scripts` The list of unicode scripts allowed to be used in the scope. -**Default Value:** `["Latin"]` (`Vec<String>`) +**Default Value:** `["Latin"]` --- **Affected lints:** @@ -522,7 +517,7 @@ The list of unicode scripts allowed to be used in the scope. ## `enable-raw-pointer-heuristic-for-send` Whether to apply the raw pointer heuristic to determine if a type is `Send`. -**Default Value:** `true` (`bool`) +**Default Value:** `true` --- **Affected lints:** @@ -534,7 +529,7 @@ When Clippy suggests using a slice pattern, this is the maximum number of elemen the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. -**Default Value:** `3` (`u64`) +**Default Value:** `3` --- **Affected lints:** @@ -544,7 +539,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. ## `await-holding-invalid-types` -**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) +**Default Value:** `[]` --- **Affected lints:** @@ -554,7 +549,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. ## `max-include-file-size` The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes -**Default Value:** `1000000` (`u64`) +**Default Value:** `1000000` --- **Affected lints:** @@ -564,7 +559,7 @@ The maximum size of a file included via `include_bytes!()` or `include_str!()`, ## `allow-expect-in-tests` Whether `expect` should be allowed in test functions or `#[cfg(test)]` -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -574,7 +569,7 @@ Whether `expect` should be allowed in test functions or `#[cfg(test)]` ## `allow-unwrap-in-tests` Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -584,7 +579,7 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` ## `allow-dbg-in-tests` Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -594,7 +589,7 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` ## `allow-print-in-tests` Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -605,7 +600,7 @@ Whether print macros (ex. `println!`) should be allowed in test functions or `#[ ## `large-error-threshold` The maximum size of the `Err`-variant in a `Result` returned from a function -**Default Value:** `128` (`u64`) +**Default Value:** `128` --- **Affected lints:** @@ -616,7 +611,7 @@ The maximum size of the `Err`-variant in a `Result` returned from a function A list of paths to types that should be treated like `Arc`, i.e. ignored but for the generic parameters for determining interior mutability -**Default Value:** `["bytes::Bytes"]` (`Vec<String>`) +**Default Value:** `["bytes::Bytes"]` --- **Affected lints:** @@ -627,7 +622,7 @@ for the generic parameters for determining interior mutability ## `allow-mixed-uninlined-format-args` Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` -**Default Value:** `true` (`bool`) +**Default Value:** `true` --- **Affected lints:** @@ -641,7 +636,7 @@ suggested counterparts are unavailable in constant code. This configuration will cause restriction lints to trigger even if no suggestion can be made. -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -652,7 +647,7 @@ if no suggestion can be made. Whether to **only** check for missing documentation in items visible within the current crate. For example, `pub(crate)` items. -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -662,7 +657,7 @@ crate. For example, `pub(crate)` items. ## `future-size-threshold` The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint -**Default Value:** `16384` (`u64`) +**Default Value:** `16384` --- **Affected lints:** @@ -672,7 +667,7 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large ## `unnecessary-box-size` The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint -**Default Value:** `128` (`u64`) +**Default Value:** `128` --- **Affected lints:** @@ -682,7 +677,7 @@ The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::u ## `allow-private-module-inception` Whether to allow module inception if it's not public. -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -694,7 +689,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used the list to indicate, that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `{"j", "z", "i", "y", "n", "x", "w"}` (`rustc_data_structures::fx::FxHashSet<String>`) +**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]` --- **Affected lints:** @@ -704,7 +699,7 @@ configuration of Clippy. By default, any configuration will replace the default ## `min-ident-chars-threshold` Minimum chars an ident can have, anything below or equal to this will be linted. -**Default Value:** `1` (`u64`) +**Default Value:** `1` --- **Affected lints:** @@ -714,7 +709,7 @@ Minimum chars an ident can have, anything below or equal to this will be linted. ## `accept-comment-above-statement` Whether to accept a safety comment to be placed above the statement containing the `unsafe` block -**Default Value:** `true` (`bool`) +**Default Value:** `true` --- **Affected lints:** @@ -724,7 +719,7 @@ Whether to accept a safety comment to be placed above the statement containing t ## `accept-comment-above-attributes` Whether to accept a safety comment to be placed above the attributes for the `unsafe` block -**Default Value:** `true` (`bool`) +**Default Value:** `true` --- **Affected lints:** @@ -734,7 +729,7 @@ Whether to accept a safety comment to be placed above the attributes for the `un ## `allow-one-hash-in-raw-strings` Whether to allow `r#""#` when `r""` can be used -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** @@ -745,7 +740,7 @@ Whether to allow `r#""#` when `r""` can be used The maximum number of segments a path can have before being linted, anything above this will be linted. -**Default Value:** `2` (`u64`) +**Default Value:** `2` --- **Affected lints:** @@ -755,7 +750,7 @@ be linted. ## `absolute-paths-allowed-crates` Which crates to allow absolute paths from -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`) +**Default Value:** `[]` --- **Affected lints:** @@ -765,7 +760,7 @@ Which crates to allow absolute paths from ## `allowed-dotfiles` Additional dotfiles (files or directories starting with a dot) to allow -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`) +**Default Value:** `[]` --- **Affected lints:** @@ -774,7 +769,7 @@ Additional dotfiles (files or directories starting with a dot) to allow ## `enforce-iter-loop-reborrow` #### Example -``` +```no_run let mut vec = vec![1, 2, 3]; let rmvec = &mut vec; for _ in rmvec.iter() {} @@ -782,14 +777,14 @@ for _ in rmvec.iter_mut() {} ``` Use instead: -``` +```no_run let mut vec = vec![1, 2, 3]; let rmvec = &mut vec; for _ in &*rmvec {} for _ in &mut *rmvec {} ``` -**Default Value:** `false` (`bool`) +**Default Value:** `false` --- **Affected lints:** diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml new file mode 100644 index 00000000000..2d41087b51d --- /dev/null +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "clippy_config" +version = "0.1.75" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustc-semver = "1.1" +serde = { version = "1.0", features = ["derive"] } +toml = "0.7.3" + +[dev-dependencies] +walkdir = "2.3" + +[features] +deny-warnings = [] + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)] +rustc_private = true diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 8829f188fe7..47259776921 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -1,11 +1,11 @@ -//! Read configurations files. - -#![allow(clippy::module_name_repetitions)] - +use crate::msrvs::Msrv; +use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename}; +use crate::ClippyConfiguration; +use rustc_data_structures::fx::FxHashSet; use rustc_session::Session; use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; -use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor}; -use serde::Deserialize; +use serde::de::{IgnoredAny, IntoDeserializer, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; use std::fmt::{Debug, Display, Formatter}; use std::ops::Range; use std::path::PathBuf; @@ -38,43 +38,12 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; -/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. -#[derive(Clone, Debug, Deserialize)] -pub struct Rename { - pub path: String, - pub rename: String, -} - -#[derive(Clone, Debug, Deserialize)] -#[serde(untagged)] -pub enum DisallowedPath { - Simple(String), - WithReason { path: String, reason: Option<String> }, -} - -impl DisallowedPath { - pub fn path(&self) -> &str { - let (Self::Simple(path) | Self::WithReason { path, .. }) = self; - - path - } - - pub fn reason(&self) -> Option<String> { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, - } - } -} - /// Conf with parse errors #[derive(Default)] -pub struct TryConf { - pub conf: Conf, - pub errors: Vec<ConfError>, - pub warnings: Vec<ConfError>, +struct TryConf { + conf: Conf, + errors: Vec<ConfError>, + warnings: Vec<ConfError>, } impl TryConf { @@ -88,9 +57,9 @@ impl TryConf { } #[derive(Debug)] -pub struct ConfError { - pub message: String, - pub span: Span, +struct ConfError { + message: String, + span: Span, } impl ConfError { @@ -112,10 +81,31 @@ impl ConfError { } } +macro_rules! wrap_option { + () => { + None + }; + ($x:literal) => { + Some($x) + }; +} + +macro_rules! default_text { + ($value:expr) => {{ + let mut text = String::new(); + $value.serialize(toml::ser::ValueSerializer::new(&mut text)).unwrap(); + text + }}; + ($value:expr, $override:expr) => { + $override.to_string() + }; +} + macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? + $(#[default_text = $default_text:expr])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration @@ -124,6 +114,7 @@ macro_rules! define_Conf { } mod defaults { + use super::*; $(pub fn $name() -> $ty { $default })* } @@ -190,31 +181,21 @@ macro_rules! define_Conf { } } - pub mod metadata { - use crate::utils::ClippyConfiguration; - - macro_rules! wrap_option { - () => (None); - ($x:literal) => (Some($x)); - } - - pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> { - vec![ - $( - { - let deprecation_reason = wrap_option!($($dep)?); - - ClippyConfiguration::new( - stringify!($name), - stringify!($ty), - format!("{:?}", super::defaults::$name()), - concat!($($doc, '\n',)*), - deprecation_reason, - ) - }, - )+ - ] - } + pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> { + vec![ + $( + { + let deprecation_reason = wrap_option!($($dep)?); + + ClippyConfiguration::new( + stringify!($name), + default_text!(defaults::$name() $(, $default_text)?), + concat!($($doc, '\n',)*), + deprecation_reason, + ) + }, + )+ + ] } }; } @@ -236,7 +217,7 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), + (arithmetic_side_effects_allowed: FxHashSet<String> = <_>::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type pair names in binary operations like addition or @@ -263,15 +244,16 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` - (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), + (arithmetic_side_effects_allowed_unary: FxHashSet<String> = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. /// - /// The minimum rust version that the project supports - (msrv: crate::Msrv = crate::Msrv::empty()), + /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` + #[default_text = ""] + (msrv: Msrv = Msrv::empty()), /// DEPRECATED LINT: BLACKLISTED_NAME. /// /// Use the Disallowed Names lint instead @@ -295,7 +277,7 @@ define_Conf! { /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. - (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), + (disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: SEMICOLON_INSIDE_BLOCK. /// /// Whether to lint only if it's multiline. @@ -311,9 +293,7 @@ define_Conf! { /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - /// - /// Default list: - (doc_valid_idents: Vec<String> = super::DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + (doc_valid_idents: Vec<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), /// Lint: TOO_MANY_ARGUMENTS. /// /// The maximum number of argument a function or method can have @@ -352,7 +332,9 @@ define_Conf! { (literal_representation_threshold: u64 = 16384), /// Lint: TRIVIALLY_COPY_PASS_BY_REF. /// - /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. + /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by + /// reference. By default there is no limit + #[default_text = ""] (trivial_copy_size_limit: Option<u64> = None), /// Lint: LARGE_TYPES_PASSED_BY_VALUE. /// @@ -393,15 +375,15 @@ define_Conf! { /// Lint: DISALLOWED_MACROS. /// /// The list of disallowed macros, written as fully qualified paths. - (disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), + (disallowed_macros: Vec<DisallowedPath> = Vec::new()), /// Lint: DISALLOWED_METHODS. /// /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), + (disallowed_methods: Vec<DisallowedPath> = Vec::new()), /// Lint: DISALLOWED_TYPES. /// /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), + (disallowed_types: Vec<DisallowedPath> = Vec::new()), /// Lint: UNREADABLE_LITERAL. /// /// Should the fraction of a decimal be linted to include separators. @@ -414,9 +396,8 @@ define_Conf! { /// /// Whether the matches should be considered by the lint, and whether there should /// be filtering for common types. - (matches_for_let_else: crate::manual_let_else::MatchLintBehaviour = - crate::manual_let_else::MatchLintBehaviour::WellKnownTypes), - /// Lint: _CARGO_COMMON_METADATA. + (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes), + /// Lint: CARGO_COMMON_METADATA. /// /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. (cargo_ignore_publish: bool = false), @@ -427,11 +408,11 @@ define_Conf! { /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro /// could be used with a full path two `MacroMatcher`s have to be added one with the full path /// `crate_name::macro_name` and one with just the macro name. - (standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()), + (standard_macro_braces: Vec<MacroMatcher> = Vec::new()), /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. /// /// 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()), + (enforced_import_renames: Vec<Rename> = Vec::new()), /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. @@ -447,7 +428,7 @@ define_Conf! { /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. (max_suggested_slice_pattern_length: u64 = 3), /// Lint: AWAIT_HOLDING_INVALID_TYPE. - (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()), + (await_holding_invalid_types: Vec<DisallowedPath> = Vec::new()), /// Lint: LARGE_INCLUDE_FILE. /// /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes @@ -511,8 +492,8 @@ define_Conf! { /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of /// the list to indicate, that the configured values should be appended to the default /// configuration of Clippy. By default, any configuration will replace the default value. - (allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet<String> = - super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), + (allowed_idents_below_min_chars: FxHashSet<String> = + DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), /// Lint: MIN_IDENT_CHARS. /// /// Minimum chars an ident can have, anything below or equal to this will be linted. @@ -537,19 +518,17 @@ define_Conf! { /// Lint: ABSOLUTE_PATHS. /// /// Which crates to allow absolute paths from - (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> = - rustc_data_structures::fx::FxHashSet::default()), + (absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default()), /// Lint: PATH_ENDS_WITH_EXT. /// /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: rustc_data_structures::fx::FxHashSet<String> = - rustc_data_structures::fx::FxHashSet::default()), + (allowed_dotfiles: FxHashSet<String> = FxHashSet::default()), /// Lint: EXPLICIT_ITER_LOOP /// /// Whether to recommend using implicit into iter for reborrowed values. /// /// #### Example - /// ``` + /// ```no_run /// let mut vec = vec![1, 2, 3]; /// let rmvec = &mut vec; /// for _ in rmvec.iter() {} @@ -557,7 +536,7 @@ define_Conf! { /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// let mut vec = vec![1, 2, 3]; /// let rmvec = &mut vec; /// for _ in &*rmvec {} @@ -779,7 +758,7 @@ mod tests { #[test] fn configs_are_tested() { - let mut names: FxHashSet<String> = super::metadata::get_configuration_metadata() + let mut names: FxHashSet<String> = crate::get_configuration_metadata() .into_iter() .map(|meta| meta.name.replace('_', "-")) .collect(); diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs new file mode 100644 index 00000000000..f5dcb16d670 --- /dev/null +++ b/src/tools/clippy/clippy_config/src/lib.rs @@ -0,0 +1,23 @@ +#![feature(rustc_private, let_chains)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] +#![allow( + clippy::must_use_candidate, + clippy::missing_panics_doc, + rustc::untranslatable_diagnostic_trivial +)] + +extern crate rustc_ast; +extern crate rustc_data_structures; +#[allow(unused_extern_crates)] +extern crate rustc_driver; +extern crate rustc_session; +extern crate rustc_span; + +mod conf; +mod metadata; +pub mod msrvs; +pub mod types; + +pub use conf::{get_configuration_metadata, lookup_conf_file, Conf}; +pub use metadata::ClippyConfiguration; diff --git a/src/tools/clippy/clippy_config/src/metadata.rs b/src/tools/clippy/clippy_config/src/metadata.rs new file mode 100644 index 00000000000..2451fbc91e8 --- /dev/null +++ b/src/tools/clippy/clippy_config/src/metadata.rs @@ -0,0 +1,116 @@ +use std::fmt::{self, Write}; + +#[derive(Debug, Clone, Default)] +pub struct ClippyConfiguration { + pub name: String, + pub default: String, + pub lints: Vec<String>, + pub doc: String, + pub deprecation_reason: Option<&'static str>, +} + +impl fmt::Display for ClippyConfiguration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "- `{}`: {}", self.name, self.doc)?; + if !self.default.is_empty() { + write!(f, " (default: `{}`)", self.default)?; + } + Ok(()) + } +} + +impl ClippyConfiguration { + pub fn new( + name: &'static str, + default: String, + doc_comment: &'static str, + deprecation_reason: Option<&'static str>, + ) -> Self { + let (lints, doc) = parse_config_field_doc(doc_comment) + .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + + Self { + name: to_kebab(name), + lints, + doc, + default, + deprecation_reason, + } + } + + pub fn to_markdown_paragraph(&self) -> String { + let mut out = format!( + "## `{}`\n{}\n\n", + self.name, + self.doc + .lines() + .map(|line| line.strip_prefix(" ").unwrap_or(line)) + .collect::<Vec<_>>() + .join("\n"), + ); + + if !self.default.is_empty() { + write!(out, "**Default Value:** `{}`\n\n", self.default).unwrap(); + } + + write!( + out, + "---\n**Affected lints:**\n{}\n\n", + self.lints + .iter() + .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) + .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) + .collect::<Vec<_>>() + .join("\n"), + ) + .unwrap(); + + out + } + + pub fn to_markdown_link(&self) -> String { + const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html"; + format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) + } +} + +/// This parses the field documentation of the config struct. +/// +/// ```rust, ignore +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") +/// ``` +/// +/// Would yield: +/// ```rust, ignore +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") +/// ``` +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { + const DOC_START: &str = " Lint: "; + if doc_comment.starts_with(DOC_START) + && let Some(split_pos) = doc_comment.find('.') + { + let mut doc_comment = doc_comment.to_string(); + let mut documentation = doc_comment.split_off(split_pos); + + // Extract lints + doc_comment.make_ascii_lowercase(); + let lints: Vec<String> = doc_comment + .split_off(DOC_START.len()) + .split(", ") + .map(str::to_string) + .collect(); + + // Format documentation correctly + // split off leading `.` from lint name list and indent for correct formatting + documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); + + Some((lints, documentation)) + } else { + None + } +} + +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` +fn to_kebab(config_name: &str) -> String { + config_name.replace('_', "-") +} diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index c6a48874e09..011d54629d4 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -1,10 +1,9 @@ use rustc_ast::Attribute; use rustc_semver::RustcVersion; use rustc_session::Session; +use rustc_span::{sym, Symbol}; use serde::Deserialize; -use crate::attrs::get_unique_attr; - macro_rules! msrv_aliases { ($($major:literal,$minor:literal,$patch:literal { $($name:ident),* $(,)? @@ -101,7 +100,16 @@ impl Msrv { } fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> { - if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") { + let sym_msrv = Symbol::intern("msrv"); + let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); + + if let Some(msrv_attr) = msrv_attrs.next() { + if let Some(duplicate) = msrv_attrs.last() { + sess.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times") + .span_note(msrv_attr.span, "first definition found here") + .emit(); + } + if let Some(msrv) = msrv_attr.value_str() { if let Ok(version) = RustcVersion::parse(msrv.as_str()) { return Some(version); diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs new file mode 100644 index 00000000000..e898221ffa7 --- /dev/null +++ b/src/tools/clippy/clippy_config/src/types.rs @@ -0,0 +1,142 @@ +use serde::de::{self, Deserializer, Visitor}; +use serde::{ser, Deserialize, Serialize}; +use std::fmt; +use std::hash::{Hash, Hasher}; + +#[derive(Clone, Debug, Deserialize)] +pub struct Rename { + pub path: String, + pub rename: String, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub enum DisallowedPath { + Simple(String), + WithReason { path: String, reason: Option<String> }, +} + +impl DisallowedPath { + pub fn path(&self) -> &str { + let (Self::Simple(path) | Self::WithReason { path, .. }) = self; + + path + } + + pub fn reason(&self) -> Option<String> { + match self { + Self::WithReason { + reason: Some(reason), .. + } => Some(format!("{reason} (from clippy.toml)")), + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] +pub enum MatchLintBehaviour { + AllTypes, + WellKnownTypes, + Never, +} + +#[derive(Clone, Debug)] +pub struct MacroMatcher { + pub name: String, + pub braces: (String, String), +} + +impl Hash for MacroMatcher { + fn hash<H: Hasher>(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl PartialEq for MacroMatcher { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} +impl Eq for MacroMatcher {} + +impl<'de> Deserialize<'de> for MacroMatcher { + fn deserialize<D>(deser: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Name, + Brace, + } + struct MacVisitor; + impl<'de> Visitor<'de> for MacVisitor { + type Value = MacroMatcher; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("struct MacroMatcher") + } + + fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> + where + V: de::MapAccess<'de>, + { + let mut name = None; + let mut brace: Option<String> = None; + while let Some(key) = map.next_key()? { + match key { + Field::Name => { + if name.is_some() { + return Err(de::Error::duplicate_field("name")); + } + name = Some(map.next_value()?); + }, + Field::Brace => { + if brace.is_some() { + return Err(de::Error::duplicate_field("brace")); + } + brace = Some(map.next_value()?); + }, + } + } + let name = name.ok_or_else(|| de::Error::missing_field("name"))?; + let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?; + Ok(MacroMatcher { + name, + braces: [("(", ")"), ("{", "}"), ("[", "]")] + .into_iter() + .find(|b| b.0 == brace) + .map(|(o, c)| (o.to_owned(), c.to_owned())) + .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, + }) + } + } + + const FIELDS: &[&str] = &["name", "brace"]; + deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor) + } +} + +// these impls are never actually called but are used by the various config options that default to +// empty lists +macro_rules! unimplemented_serialize { + ($($t:ty,)*) => { + $( + impl Serialize for $t { + fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + Err(ser::Error::custom("unimplemented")) + } + } + )* + } +} + +unimplemented_serialize! { + DisallowedPath, + Rename, + MacroMatcher, +} diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index fca750fafc7..5bd9994e18d 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -199,7 +199,6 @@ fn get_clap_config() -> ArgMatches { "cargo", "nursery", "internal", - "internal_warn", ]), Arg::new("type").long("type").help("What directory the lint belongs in"), Arg::new("msrv") diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index be2386bb1d2..eeea53ce46f 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -346,11 +346,11 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String { /// ### Why is this bad? /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// ``` #[clippy::version = "{}"] diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 842aeed2aa4..6b76a44debf 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -588,7 +588,7 @@ impl Lint { .collect() } - /// Returns all internal lints (not `internal_warn` lints) + /// Returns all internal lints #[must_use] fn internal_lints(lints: &[Self]) -> Vec<Self> { lints.iter().filter(|l| l.group == "internal").cloned().collect() diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 4d5b3bf8a94..4bc27fd48e2 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" [dependencies] arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.15.3" +clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } if_chain = "1.0" @@ -32,9 +33,9 @@ url = "2.2" walkdir = "2.3" [features] -deny-warnings = ["clippy_utils/deny-warnings"] +deny-warnings = ["clippy_config/deny-warnings", "clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default -internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"] +internal = ["serde_json", "tempfile", "regex"] [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs index 04417c4c460..582423603eb 100644 --- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// using absolute paths is the proper way of referencing items in one. /// /// ### Example - /// ```rust + /// ```no_run /// let x = std::f64::consts::PI; /// ``` /// Use any of the below instead, or anything else: - /// ```rust + /// ```no_run /// use std::f64; /// use std::f64::consts; /// use std::f64::consts::PI; diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 32d80f42e7e..e85878eb570 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; @@ -17,11 +17,11 @@ declare_clippy_lint! { /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = 'a'..'z'; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = 'a'..='z'; /// ``` #[clippy::version = "1.68.0"] @@ -82,33 +82,20 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg ( Ok(LitKind::Byte(b'a') | LitKind::Char('a')), Ok(LitKind::Byte(b'z') | LitKind::Char('z')) - ) - | ( + ) | ( Ok(LitKind::Byte(b'A') | LitKind::Char('A')), Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), - ) - | ( + ) | ( Ok(LitKind::Byte(b'0') | LitKind::Char('0')), Ok(LitKind::Byte(b'9') | LitKind::Char('9')), ) ) && !in_external_macro(cx.sess(), span) { - span_lint_and_then( - cx, - ALMOST_COMPLETE_RANGE, - span, - "almost complete ascii range", - |diag| { - if let Some((span, sugg)) = sugg { - diag.span_suggestion( - span, - "use an inclusive range", - sugg, - Applicability::MaybeIncorrect, - ); - } + span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| { + if let Some((span, sugg)) = sugg { + diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect); } - ); + }); } } diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index ccf82f132f4..b4f778f12b9 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -24,12 +24,12 @@ declare_clippy_lint! { /// issue](https://github.com/rust-lang/rust/issues). /// /// ### Example - /// ```rust + /// ```no_run /// let x = 3.14; /// let y = 1_f64 / x; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = std::f32::consts::PI; /// let y = std::f64::consts::FRAC_1_PI; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 35a04b5e44a..192bc7d9ddc 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # use std::sync::Arc; /// @@ -62,19 +62,21 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { ARC_WITH_NON_SEND_SYNC, expr.span, "usage of an `Arc` that is not `Send` or `Sync`", - |diag| with_forced_trimmed_paths!({ - if !is_send { - diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); - } - if !is_sync { - diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); - } + |diag| { + with_forced_trimmed_paths!({ + if !is_send { + diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); + } + if !is_sync { + diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); + } - diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); + diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); - diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); - } - )); + diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); + }); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index 2980c9d6db3..71ec87a8874 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { return; } } - let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""}; + let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" }; let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => { @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { ), app, ); - } + }, "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => { span_lint_and_sugg( cx, @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { ), app, ); - } + }, _ => (), }; } diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 050df68a0fa..ec2447dae96 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath}; +use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -15,7 +15,7 @@ declare_clippy_lint! { /// An await is likely missing. /// /// ### Example - /// ```rust + /// ```no_run /// async fn foo() {} /// /// fn bar() { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// async fn foo() {} /// /// fn bar() { diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index db01ddbde04..38364af27c7 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -1,9 +1,9 @@ //! checks for attributes +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_from_proc_macro; use clippy_utils::macros::{is_panic, macro_backtrace}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::token::{Token, TokenKind}; @@ -19,9 +19,8 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{sym, DUMMY_SP, Span}; use semver::Version; static UNIX_SYSTEMS: &[&str] = &[ @@ -129,7 +128,7 @@ declare_clippy_lint! { /// a valid semver. Failing that, the contained information is useless. /// /// ### Example - /// ```rust + /// ```no_run /// #[deprecated(since = "forever")] /// fn something_else() { /* ... */ } /// ``` @@ -156,14 +155,14 @@ declare_clippy_lint! { /// currently works for basic cases but is not perfect. /// /// ### Example - /// ```rust + /// ```no_run /// #[allow(dead_code)] /// /// fn not_quite_good_code() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Good (as inner attribute) /// #![allow(dead_code)] /// @@ -198,25 +197,25 @@ declare_clippy_lint! { /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). /// /// ### Example - /// ```rust + /// ```no_run /// /// Some doc comment with a blank line after it. /// /// fn not_quite_good_code() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// /// Good (no blank line) /// fn this_is_fine() { } /// ``` /// - /// ```rust + /// ```no_run /// // Good (convert to a regular comment) /// /// fn this_is_fine_too() { } /// ``` /// - /// ```rust + /// ```no_run /// //! Good (convert to a comment on an inner attribute) /// /// fn this_is_fine_as_well() { } @@ -236,12 +235,12 @@ declare_clippy_lint! { /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. /// /// ### Example - /// ```rust + /// ```no_run /// #![deny(clippy::restriction)] /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![deny(clippy::as_conversions)] /// ``` #[clippy::version = "1.47.0"] @@ -265,13 +264,13 @@ declare_clippy_lint! { /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg_attr(rustfmt, rustfmt_skip)] /// fn main() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[rustfmt::skip] /// fn main() { } /// ``` @@ -290,13 +289,13 @@ declare_clippy_lint! { /// by the conditional compilation engine. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(linux)] /// fn conditional() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # mod hidden { /// #[cfg(target_os = "linux")] /// fn conditional() { } @@ -325,14 +324,14 @@ declare_clippy_lint! { /// ensure that others understand the reasoning /// /// ### Example - /// ```rust + /// ```no_run /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint)] /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] @@ -352,7 +351,7 @@ declare_clippy_lint! { /// panicking with the expected message, and not another unrelated panic. /// /// ### Example - /// ```rust + /// ```no_run /// fn random() -> i32 { 0 } /// /// #[should_panic] @@ -363,7 +362,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn random() -> i32 { 0 } /// /// #[should_panic = "attempt to divide by zero"] @@ -386,13 +385,13 @@ declare_clippy_lint! { /// If there is only one condition, no need to wrap it into `any` or `all` combinators. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(any(unix))] /// pub struct Bar; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(unix)] /// pub struct Bar; /// ``` @@ -409,16 +408,16 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Misspelling `feature` as `features` can be sometimes hard to spot. It - /// may cause conditional compilation not work quitely. + /// may cause conditional compilation not work quietly. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(features = "some-feature")] /// fn conditional() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(feature = "some-feature")] /// fn conditional() { } /// ``` @@ -602,9 +601,26 @@ fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) { if let AttrArgs::Delimited(args) = &normal_attr.item.args && let mut tt_iter = args.tokens.trees() - && let Some(TokenTree::Token(Token { kind: TokenKind::Ident(sym::expected, _), .. }, _)) = tt_iter.next() - && let Some(TokenTree::Token(Token { kind: TokenKind::Eq, .. }, _)) = tt_iter.next() - && let Some(TokenTree::Token(Token { kind: TokenKind::Literal(_), .. }, _)) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Ident(sym::expected, _), + .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Eq, .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Literal(_), + .. + }, + _, + )) = tt_iter.next() { // `#[should_panic(expected = "..")]` found, good return; @@ -914,7 +930,9 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { for item in items { if let NestedMetaItem::MetaItem(meta) = item { - if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() { + if meta.has_name(sym!(features)) + && let Some(val) = meta.value_str() + { span_lint_and_sugg( cx, MAYBE_MISUSED_CFG, @@ -933,16 +951,16 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { } fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) && - let Some(items) = attr.meta_item_list() + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() { check_nested_cfg(cx, &items); } } fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) && - let Some(items) = attr.meta_item_list() + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() { check_nested_misused_cfg(cx, &items); } diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 0c356934992..06b74b972b7 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -1,15 +1,14 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{CoroutineSource, Body, CoroutineKind}; +use rustc_hir::{Body, CoroutineKind, CoroutineSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use crate::utils::conf::DisallowedPath; - declare_clippy_lint! { /// ### What it does /// Checks for calls to await while holding a non-async-aware MutexGuard. @@ -29,7 +28,7 @@ declare_clippy_lint! { /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # async fn baz() {} /// async fn foo(x: &Mutex<u32>) { @@ -47,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # async fn baz() {} /// async fn foo(x: &Mutex<u32>) { @@ -87,7 +86,7 @@ declare_clippy_lint! { /// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # async fn baz() {} /// async fn foo(x: &RefCell<u32>) { @@ -105,7 +104,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # async fn baz() {} /// async fn foo(x: &RefCell<u32>) { @@ -151,7 +150,7 @@ declare_clippy_lint! { /// ] /// ``` /// - /// ```rust + /// ```no_run /// # async fn baz() {} /// struct CustomLockType; /// struct OtherCustomLockType; diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs index 1593d7b0fb3..04bf541a5bd 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Style, using blocks in the condition makes it hard to read. /// /// ### Examples - /// ```rust + /// ```no_run /// # fn somefunc() -> bool { true }; /// if { true } { /* ... */ } /// @@ -29,7 +29,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn somefunc() -> bool { true }; /// if true { /* ... */ } /// diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 4503597713a..665dbd6f708 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// It is shorter to use the equivalent. /// /// ### Example - /// ```rust + /// ```no_run /// assert_eq!("a".is_empty(), false); /// assert_ne!("a".is_empty(), true); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// assert!(!"a".is_empty()); /// ``` #[clippy::version = "1.53.0"] diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs index 1828dd65152..156cb34df9c 100644 --- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs +++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E /// /// ### Example - /// ```rust + /// ```no_run /// # let condition = false; /// if condition { /// 1_i64 @@ -30,12 +30,12 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let condition = false; /// i64::from(condition); /// ``` /// or - /// ```rust + /// ```no_run /// # let condition = false; /// condition as i64; /// ``` @@ -55,7 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { } fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr) + if let Some(If { + cond, + then, + r#else: Some(r#else), + }) = If::hir(expr) && let Some(then_lit) = int_literal(then) && let Some(else_lit) = int_literal(r#else) { @@ -90,19 +94,18 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx> let into_snippet = snippet.clone().maybe_par(); let as_snippet = snippet.as_ty(ty); - span_lint_and_then(cx, + span_lint_and_then( + cx, BOOL_TO_INT_WITH_IF, expr.span, "boolean to int conversion using if", |diag| { - diag.span_suggestion( - expr.span, - "replace with from", - suggestion, - applicability, - ); - diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options")); - }); + diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); + diag.note(format!( + "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" + )); + }, + ); }; } @@ -110,7 +113,7 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx> fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { if let ExprKind::Block(block, _) = expr.kind && let Block { - stmts: [], // Shouldn't lint if statements with side effects + stmts: [], // Shouldn't lint if statements with side effects expr: Some(expr), .. } = block diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 04cca9e3177..0e0d229e877 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -10,8 +10,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -472,8 +471,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { self.bool_expr(e); }, ExprKind::Unary(UnOp::Not, inner) => { - if let ExprKind::Unary(UnOp::Not, ex) = inner.kind && - !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() { + if let ExprKind::Unary(UnOp::Not, ex) = inner.kind + && !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() + { return; } if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { @@ -500,10 +500,10 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && - !inner.span.from_expansion() && - let Some(suggestion) = simplify_not(self.cx, inner) - && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind + && !inner.span.from_expansion() + && let Some(suggestion) = simplify_not(self.cx, inner) + && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow { span_lint_and_sugg( self.cx, diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index b3dbbb08f8e..739ce8f67c2 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// /// ### Known problems /// False negative on such code: - /// ``` + /// ```no_run /// let x = &12; /// let addr_x = &x as *const _ as usize; /// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered. @@ -28,14 +28,14 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// ```rust + /// ```no_run /// let s = &String::new(); /// /// let a: &String = &* s; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = &String::new(); /// let a: &String = s; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index cc9bd727937..9c78c6e532d 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). /// /// ### Example - /// ```rust + /// ```no_run /// let x: Box<String> = Box::new(Default::default()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: Box<String> = Box::default(); /// ``` #[clippy::version = "1.66.0"] @@ -61,9 +61,9 @@ impl LateLintPass<'_> for BoxDefault { } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) } else { - return + return; }, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } @@ -110,7 +110,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Node::Expr(Expr { kind: ExprKind::Call(path, args), .. - }) | Node::Block(Block { + }) + | Node::Block(Block { expr: Some(Expr { kind: ExprKind::Call(path, args), @@ -119,10 +120,10 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .. }), ) => { - if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && - let Some(sig) = expr_sig(cx, path) && - let Some(input) = sig.input(index) && - !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() + if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(sig) = expr_sig(cx, path) + && let Some(input) = sig.input(index) + && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() { input.no_bound_vars().is_some() } else { diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs index 805121bcced..99fe6c1e790 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs @@ -3,7 +3,7 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::CARGO_COMMON_METADATA; diff --git a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs index 37c169dbd95..9e69919c727 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs @@ -1,7 +1,7 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint_and_help; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::{NEGATIVE_FEATURE_NAMES, REDUNDANT_FEATURE_NAMES}; diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs index f9b17d45e9f..f7a5b1857be 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use itertools::Itertools; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::MULTIPLE_CRATE_VERSIONS; diff --git a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs index 7fa6acbf557..4dcc9cbe3a7 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -2,7 +2,7 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_lint::LateContext; -use rustc_span::source_map::DUMMY_SP; +use rustc_span::DUMMY_SP; use super::WILDCARD_DEPENDENCIES; diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs index 1e56ed5f450..55294f5f386 100644 --- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -9,12 +9,19 @@ use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::AS_PTR_CAST_MUT; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) { - if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind() - && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = - cx.typeck_results().node_type(cast_expr.hir_id).kind() + if let ty::RawPtr( + ptrty @ TypeAndMut { + mutbl: Mutability::Mut, .. + }, + ) = cast_to.kind() + && let ty::RawPtr(TypeAndMut { + mutbl: Mutability::Not, .. + }) = cx.typeck_results().node_type(cast_expr.hir_id).kind() && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind && method_name.ident.name == rustc_span::sym::as_ptr - && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id) + && let Some(as_ptr_did) = cx + .typeck_results() + .type_dependent_def_id(cast_expr.peel_blocks().hir_id) && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() @@ -30,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, &format!("casting the result of `as_ptr` to *{ptrty}"), "replace with", format!("{recv}.as_mut_ptr()"), - applicability + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 44226298333..c1663348321 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index c586b572be9..fe2455f4b23 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_constant; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 9e8ef282537..f12f03fbe79 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -26,8 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { // There probably is no obvious reason to do this, just to be consistent with `as` cases. && !is_hir_ty_cfg_dependant(cx, cast_to) { - let (cast_from, cast_to) = - (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); + let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } } @@ -81,9 +80,9 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { cx.tcx.get_diagnostic_name(def_id), Some( sym::ptr_write_unaligned - | sym::ptr_read_unaligned - | sym::intrinsics_unaligned_volatile_load - | sym::intrinsics_unaligned_volatile_store + | sym::ptr_read_unaligned + | sym::intrinsics_unaligned_volatile_load + | sym::intrinsics_unaligned_volatile_store ) ) { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs index 4d9cc4cacc3..d1410402913 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source; use if_chain::if_chain; use rustc_ast::Mutability; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index eb0f75b2f60..badadf2c9f6 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index b00130ffd76..49a90a2f3c2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -22,8 +22,8 @@ mod unnecessary_cast; mod utils; mod zero_ptr; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::is_hir_ty_cfg_dependant; -use clippy_utils::msrvs::{self, Msrv}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -45,7 +45,7 @@ declare_clippy_lint! { /// those places in the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = u64::MAX; /// x as f64; /// ``` @@ -67,7 +67,7 @@ declare_clippy_lint! { /// as a one-time check to see where numerical wrapping can arise. /// /// ### Example - /// ```rust + /// ```no_run /// let y: i8 = -1; /// y as u128; // will return 18446744073709551615 /// ``` @@ -90,13 +90,13 @@ declare_clippy_lint! { /// checks could be beneficial. /// /// ### Example - /// ```rust + /// ```no_run /// fn as_u8(x: u64) -> u8 { /// x as u8 /// } /// ``` /// Use instead: - /// ``` + /// ```no_run /// fn as_u8(x: u64) -> u8 { /// if let Ok(x) = u8::try_from(x) { /// x @@ -132,7 +132,7 @@ declare_clippy_lint! { /// example below. /// /// ### Example - /// ```rust + /// ```no_run /// u32::MAX as i32; // will yield a value of `-1` /// ``` #[clippy::version = "pre 1.29.0"] @@ -155,7 +155,7 @@ declare_clippy_lint! { /// people reading the code to know that the conversion is lossless. /// /// ### Example - /// ```rust + /// ```no_run /// fn as_u64(x: u8) -> u64 { /// x as u64 /// } @@ -163,7 +163,7 @@ declare_clippy_lint! { /// /// Using `::from` would look like this: /// - /// ```rust + /// ```no_run /// fn as_u64(x: u8) -> u64 { /// u64::from(x) /// } @@ -191,14 +191,14 @@ declare_clippy_lint! { /// intermediate references, raw pointers and trait objects may or may not work. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = 2i32 as i32; /// let _ = 0.5 as f32; /// ``` /// /// Better: /// - /// ```rust + /// ```no_run /// let _ = 2_i32; /// let _ = 0.5_f32; /// ``` @@ -223,7 +223,7 @@ declare_clippy_lint! { /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (&1u8 as *const u8) as *const u16; /// let _ = (&mut 1u8 as *mut u8) as *mut u16; /// @@ -249,13 +249,13 @@ declare_clippy_lint! { /// Casting to isize also doesn't make sense since there are no signed addresses. /// /// ### Example - /// ```rust + /// ```no_run /// fn fun() -> i32 { 1 } /// let _ = fun as i64; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn fun() -> i32 { 1 } /// let _ = fun as usize; /// ``` @@ -276,7 +276,7 @@ declare_clippy_lint! { /// a comment) to perform the truncation. /// /// ### Example - /// ```rust + /// ```no_run /// fn fn1() -> i16 { /// 1 /// }; @@ -284,7 +284,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Cast to usize first, then comment with the reason for the truncation /// fn fn1() -> i16 { /// 1 @@ -310,7 +310,7 @@ declare_clippy_lint! { /// pointer casts in your code. /// /// ### Example - /// ```rust + /// ```no_run /// // fn1 is cast as `usize` /// fn fn1() -> u16 { /// 1 @@ -319,7 +319,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // maybe you intended to call the function? /// fn fn2() -> u16 { /// 1 @@ -378,14 +378,14 @@ declare_clippy_lint! { /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; /// let _ = ptr as *const i32; /// let _ = mut_ptr as *mut i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; /// let _ = ptr.cast::<i32>(); @@ -408,13 +408,13 @@ declare_clippy_lint! { /// type. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr as *mut u32; /// let ptr = mut_ptr as *const u32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); @@ -434,7 +434,7 @@ declare_clippy_lint! { /// The resulting integral value will not match the value of the variant it came from. /// /// ### Example - /// ```rust + /// ```no_run /// enum E { X = 256 }; /// let _ = E::X as u8; /// ``` @@ -457,7 +457,7 @@ declare_clippy_lint! { /// /// ### Example /// // Missing data - /// ```rust + /// ```no_run /// let a = [1_i32, 2, 3, 4]; /// let p = &a as *const [i32] as *const [u8]; /// unsafe { @@ -465,7 +465,7 @@ declare_clippy_lint! { /// } /// ``` /// // Undefined Behavior (note: also potential alignment issues) - /// ```rust + /// ```no_run /// let a = [1_u8, 2, 3, 4]; /// let p = &a as *const [u8] as *const [u32]; /// unsafe { @@ -473,7 +473,7 @@ declare_clippy_lint! { /// } /// ``` /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length - /// ```rust + /// ```no_run /// let a = [1_i32, 2, 3, 4]; /// let old_ptr = &a as *const [i32]; /// // The data pointer is cast to a pointer to the target `u8` not `[u8]` @@ -497,7 +497,7 @@ declare_clippy_lint! { /// The cast is easily confused with casting a c-like enum value to an integer. /// /// ### Example - /// ```rust + /// ```no_run /// enum E { X(i32) }; /// let _ = E::X as usize; /// ``` @@ -515,12 +515,12 @@ declare_clippy_lint! { /// The `unsigned_abs()` method avoids panic when called on the MIN value. /// /// ### Example - /// ```rust + /// ```no_run /// let x: i32 = -42; /// let y: u32 = x.abs() as u32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: i32 = -42; /// let y: u32 = x.unsigned_abs(); /// ``` @@ -541,13 +541,13 @@ declare_clippy_lint! { /// The lint is allowed by default as using `_` is less wordy than always specifying the type. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(n: usize) {} /// let n: u16 = 256; /// foo(n as _); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(n: usize) {} /// let n: u16 = 256; /// foo(n as usize); @@ -570,7 +570,7 @@ declare_clippy_lint! { /// Read the `ptr::addr_of` docs for more information. /// /// ### Example - /// ```rust + /// ```no_run /// let val = 1; /// let p = &val as *const i32; /// @@ -578,7 +578,7 @@ declare_clippy_lint! { /// let p_mut = &mut val_mut as *mut i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let val = 1; /// let p = std::ptr::addr_of!(val); /// @@ -627,13 +627,13 @@ declare_clippy_lint! { /// mutability is used, making it unlikely that having it as a mutable pointer is correct. /// /// ### Example - /// ```rust + /// ```no_run /// let mut vec = Vec::<u8>::with_capacity(1); /// let ptr = vec.as_ptr() as *mut u8; /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = Vec::<u8>::with_capacity(1); /// let ptr = vec.as_mut_ptr(); /// unsafe { ptr.write(4) }; @@ -675,12 +675,12 @@ declare_clippy_lint! { /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 0 as *const u32; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = std::ptr::null::<u32>(); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 181dbcf6e9a..0c555c1acc5 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs index ce1ab10910c..0172e933649 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -18,7 +18,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if_chain! { - if msrv.meets(POINTER_CAST_CONSTNESS); + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS); if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind(); if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind(); if matches!((from_mutbl, to_mutbl), diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 86057bb74ee..61bfce07e1a 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -97,7 +97,9 @@ pub(super) fn check<'tcx>( } // skip cast of fn call that returns type alias - if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) { + if let ExprKind::Cast(inner, ..) = expr.kind + && is_cast_from_ty_alias(cx, inner, cast_from) + { return false; } @@ -189,11 +191,10 @@ fn lint_unnecessary_cast( let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) && let ExprKind::MethodCall(..) = parent_expr.kind && literal_str.starts_with('-') - { - format!("({literal_str}_{cast_to})") - - } else { - format!("{literal_str}_{cast_to}") + { + format!("({literal_str}_{cast_to})") + } else { + format!("{literal_str}_{cast_to}") }; span_lint_and_sugg( @@ -269,7 +270,9 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx && let Some(parent) = get_parent_node(cx.tcx, hir_id) && let Node::Local(l) = parent { - if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) { + if let Some(e) = l.init + && is_cast_from_ty_alias(cx, e, cast_from) + { return ControlFlow::Break::<()>(()); } diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 9102a89e377..d31c2268a65 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -1,7 +1,7 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; use if_chain::if_chain; @@ -19,13 +19,13 @@ declare_clippy_lint! { /// Reduces the readability of statements & is error prone. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo: u32 = 5; /// foo <= i32::MAX as u32; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = 1; /// # #[allow(unused)] /// i32::try_from(foo).is_ok(); diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index a8926b29ac8..74ecaa60c7c 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -12,8 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::{sym, BytePos}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index b38e09dc09f..d21ef195d9b 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// makes code look more complex than it really is. /// /// ### Example - /// ```rust + /// ```no_run /// # let (x, y) = (true, true); /// if x { /// if y { @@ -42,7 +42,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let (x, y) = (true, true); /// if x && y { /// // … diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index ac5ac542cf9..1dfc2e251d9 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// instead. /// /// ### Example - /// ```rust + /// ```no_run /// # let samples = vec![3, 1, 2]; /// let mut sorted_samples = samples.clone(); /// sorted_samples.sort(); @@ -29,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let samples = vec![3, 1, 2]; /// let mut sorted_samples = samples.clone(); /// sorted_samples.sort(); diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index 726674d88f1..a2005638d24 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene /// /// ### Example - /// ```rust + /// ```no_run /// #[macro_export] /// macro_rules! print_message { /// () => { @@ -28,7 +28,7 @@ declare_clippy_lint! { /// pub const MESSAGE: &str = "Hello!"; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[macro_export] /// macro_rules! print_message { /// () => { diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 77438b27f90..1a646ba38c3 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -6,8 +6,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO, @@ -30,6 +28,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO, #[cfg(feature = "internal")] + crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO, + #[cfg(feature = "internal")] crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO, @@ -37,6 +37,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, + #[cfg(feature = "internal")] + crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO, crate::absolute_paths::ABSOLUTE_PATHS_INFO, crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, @@ -272,6 +274,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::NEVER_LOOP_INFO, crate::loops::SAME_ITEM_PUSH_INFO, crate::loops::SINGLE_ELEMENT_LOOP_INFO, + crate::loops::UNUSED_ENUMERATE_INDEX_INFO, crate::loops::WHILE_IMMUTABLE_CONDITION_INFO, crate::loops::WHILE_LET_LOOP_INFO, crate::loops::WHILE_LET_ON_ITERATOR_INFO, @@ -428,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::TYPE_ID_ON_BOX_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, crate::methods::UNIT_HASH_INFO, + crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, crate::methods::UNNECESSARY_FOLD_INFO, @@ -441,6 +445,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::USELESS_ASREF_INFO, crate::methods::VEC_RESIZE_TO_ZERO_INFO, crate::methods::VERBOSE_FILE_READS_INFO, + crate::methods::WAKER_CLONE_WAKE_INFO, crate::methods::WRONG_SELF_CONVENTION_INFO, crate::methods::ZST_OFFSET_INFO, crate::min_ident_chars::MIN_IDENT_CHARS_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 5787f19cc6c..c74b2b8831e 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// generic `Default`. /// /// ### Example - /// ```rust + /// ```no_run /// let s: String = Default::default(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let s = String::default(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -49,7 +49,7 @@ declare_clippy_lint! { /// Assignments to patterns that are of tuple type are not linted. /// /// ### Example - /// ``` + /// ```no_run /// # #[derive(Default)] /// # struct A { i: i32 } /// let mut a: A = Default::default(); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// # #[derive(Default)] /// # struct A { i: i32 } /// let a = A { diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index 0676777e796..bf070432ef9 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// This adds code complexity and an unnecessary function call. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::marker::PhantomData; /// #[derive(Default)] /// struct S<T> { @@ -29,7 +29,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::marker::PhantomData; /// struct S<T> { /// _marker: PhantomData<T> diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index 2d11fa6b647..553b670fdb7 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -14,12 +14,12 @@ declare_clippy_lint! { /// ### Why is this bad? /// `std::iter::empty()` is the more idiomatic way. /// ### Example - /// ```rust + /// ```no_run /// let _ = std::iter::Empty::<usize>::default(); /// let iter: std::iter::Empty<usize> = std::iter::Empty::default(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = std::iter::empty::<usize>(); /// let iter: std::iter::Empty<usize> = std::iter::empty(); /// ``` @@ -68,7 +68,10 @@ fn make_sugg( _ => None, }) { - format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0) + format!( + "std::iter::empty::<{}>()", + snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 + ) } else { "std::iter::empty()".to_owned() } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index d09428dbc1f..b296ea20f9c 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -31,13 +31,13 @@ declare_clippy_lint! { /// This lint can only be allowed at the function level or above. /// /// ### Example - /// ```rust + /// ```no_run /// let i = 10; /// let f = 1.23; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let i = 10i32; /// let f = 1.23f64; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 63ec8195020..8c6749a95fa 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// specified layout. These cases may lead to undefined behavior in unsafe blocks. /// /// ### Example - /// ```rust + /// ```no_run /// union Foo { /// a: i32, /// b: u32, @@ -30,7 +30,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// union Foo { /// a: i32, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index efe82036dc8..6c109a51f83 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// when not part of a method chain. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ops::Deref; /// let a: &mut String = &mut String::from("foo"); /// let b: &str = a.deref(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a: &mut String = &mut String::from("foo"); /// let b = &*a; /// ``` @@ -68,7 +68,7 @@ declare_clippy_lint! { /// in such a case can change the semantics of the code. /// /// ### Example - /// ```rust + /// ```no_run /// fn fun(_a: &i32) {} /// /// let x: &i32 = &&&&&&5; @@ -76,7 +76,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn fun(_a: &i32) {} /// let x: &i32 = &5; /// fun(x); @@ -95,7 +95,7 @@ declare_clippy_lint! { /// The address-of operator at the use site is clearer about the need for a reference. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(""); /// if let Some(ref x) = x { /// // use `x` here @@ -103,7 +103,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(""); /// if let Some(x) = x { /// // use `&x` here @@ -123,12 +123,12 @@ declare_clippy_lint! { /// This unnecessarily complicates the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = String::new(); /// let y: &str = &*x; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = String::new(); /// let y: &str = &x; /// ``` @@ -353,23 +353,26 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && let arg_ty - = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) + && let arg_ty = cx + .tcx + .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = cx .typeck_results() - .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() - && let impl_ty = if cx.tcx.fn_sig(fn_id) - .instantiate_identity() - .skip_binder() - .inputs()[0].is_ref() - { - // Trait methods taking `&self` - sub_ty - } else { - // Trait methods taking `self` - arg_ty - } && impl_ty.is_ref() + .node_args_opt(hir_id) + .map(|args| &args[1..]) + .unwrap_or_default() + && let impl_ty = + if cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder().inputs()[0] + .is_ref() + { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } + && impl_ty.is_ref() && implements_trait( cx, impl_ty, @@ -414,9 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let (required_refs, msg) = if can_auto_borrow { (1, if deref_count == 1 { borrow_msg } else { deref_msg }) } else if let Some(&Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), - .. - }) = next_adjust + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), + .. + }) = next_adjust && matches!(mutability, AutoBorrowMutability::Mut { .. }) && !stability.is_reborrow_stable() { @@ -705,9 +708,11 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo { match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) - if child.hir_id == e.hir_id => true, - ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) - | ExprKind::Field(_, _) => true, + if child.hir_id == e.hir_id => + { + true + }, + ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) | ExprKind::Field(_, _) => true, _ => false, } } else { diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index d2bfc4f8e27..a450becc647 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; @@ -21,7 +21,7 @@ declare_clippy_lint! { /// It is less concise. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// bar: bool /// } @@ -36,7 +36,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[derive(Default)] /// struct Foo { /// bar: bool diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 2bdac1352dc..3a331564db9 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -17,8 +17,7 @@ use rustc_middle::ty::{ }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -173,7 +172,7 @@ declare_clippy_lint! { /// `Eq` themselves. /// /// ### Example - /// ```rust + /// ```no_run /// #[derive(PartialEq)] /// struct Foo { /// i_am_eq: i32, @@ -181,7 +180,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[derive(PartialEq, Eq)] /// struct Foo { /// i_am_eq: i32, diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 7469f813ef8..324b5e0798e 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -1,3 +1,4 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -8,8 +9,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{ExpnId, Span}; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured macros in clippy.toml @@ -35,7 +34,7 @@ declare_clippy_lint! { /// { path = "serde::Serialize", reason = "no serializing" }, /// ] /// ``` - /// ``` + /// ```no_run /// use serde::Serialize; /// /// // Example code where clippy issues a warning @@ -55,13 +54,13 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec<conf::DisallowedPath>, + conf_disallowed: Vec<DisallowedPath>, disallowed: DefIdMap<usize>, seen: FxHashSet<ExpnId>, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self { + pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index 95d3f7547b4..d23aeebb5a8 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -1,13 +1,11 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; - use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured methods and functions in clippy.toml @@ -59,12 +57,12 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec<conf::DisallowedPath>, + conf_disallowed: Vec<DisallowedPath>, disallowed: DefIdMap<usize>, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self { + pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index 04c2d44137a..5e46b29b639 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// avoided. /// /// ### Example - /// ```rust + /// ```no_run /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index c9fad98e437..96a7f0e4fde 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents /// /// ### Example - /// ```rust + /// ```no_run /// // Assuming that `clippy.toml` contains the following line: /// // allowed-scripts = ["Latin", "Cyrillic"] /// let counter = 10; // OK, latin is allowed. diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 1f56d0118a4..3578fb640fc 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -1,5 +1,5 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; - use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; @@ -8,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured types in clippy.toml. @@ -50,15 +48,16 @@ declare_clippy_lint! { style, "use of disallowed types" } + #[derive(Clone, Debug)] pub struct DisallowedTypes { - conf_disallowed: Vec<conf::DisallowedPath>, + conf_disallowed: Vec<DisallowedPath>, def_ids: FxHashMap<DefId, usize>, prim_tys: FxHashMap<PrimTy, usize>, } impl DisallowedTypes { - pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self { + pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self { Self { conf_disallowed, def_ids: FxHashMap::default(), @@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { } } -fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) { +fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) { span_lint_and_then( cx, DISALLOWED_TYPES, diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index fc9b381664a..8982fca6e89 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -30,8 +30,8 @@ use rustc_resolve::rustdoc::{ use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::edition::Edition; -use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span}; -use rustc_span::{sym, FileName, Pos}; +use rustc_span::{sym, BytePos, FileName, Pos, Span}; +use rustc_span::source_map::{FilePathMapping, SourceMap}; use std::ops::Range; use std::{io, thread}; use url::Url; @@ -58,14 +58,14 @@ declare_clippy_lint! { /// would fail. /// /// ### Examples - /// ```rust + /// ```no_run /// /// Do something with the foo_bar parameter. See also /// /// that::other::module::foo. /// // ^ `foo_bar` and `that::other::module::foo` should be ticked. /// fn doit(foo_bar: usize) {} /// ``` /// - /// ```rust + /// ```no_run /// // Link text with `[]` brackets should be written as following: /// /// Consume the array and return the inner /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]. @@ -88,7 +88,7 @@ declare_clippy_lint! { /// preconditions, so that users can be sure they are using them safely. /// /// ### Examples - /// ```rust + /// ```no_run ///# type Universe = (); /// /// This function should really be documented /// pub unsafe fn start_apocalypse(u: &mut Universe) { @@ -98,7 +98,7 @@ declare_clippy_lint! { /// /// At least write a line about safety: /// - /// ```rust + /// ```no_run ///# type Universe = (); /// /// # Safety /// /// @@ -126,7 +126,7 @@ declare_clippy_lint! { /// Since the following function returns a `Result` it has an `# Errors` section in /// its doc comment: /// - /// ```rust + /// ```no_run ///# use std::io; /// /// # Errors /// /// @@ -155,7 +155,7 @@ declare_clippy_lint! { /// Since the following function may panic it has a `# Panics` section in /// its doc comment: /// - /// ```rust + /// ```no_run /// /// # Panics /// /// /// /// Will panic if y is 0 @@ -182,7 +182,7 @@ declare_clippy_lint! { /// if the `fn main()` is left implicit. /// /// ### Examples - /// ```rust + /// ```no_run /// /// An example of a doctest with a `main()` function /// /// /// /// # Examples @@ -210,12 +210,12 @@ declare_clippy_lint! { /// It is likely a typo when defining an intra-doc link /// /// ### Example - /// ```rust + /// ```no_run /// /// See also: ['foo'] /// fn bar() {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// /// See also: [`foo`] /// fn bar() {} /// ``` @@ -235,7 +235,7 @@ declare_clippy_lint! { /// need to describe safety preconditions that users are required to uphold. /// /// ### Examples - /// ```rust + /// ```no_run ///# type Universe = (); /// /// # Safety /// /// @@ -248,7 +248,7 @@ declare_clippy_lint! { /// The function is safe, so there shouldn't be any preconditions /// that have to be explained for safety reasons. /// - /// ```rust + /// ```no_run ///# type Universe = (); /// /// This function should really be documented /// pub fn start_apocalypse(u: &mut Universe) { @@ -569,9 +569,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize if let End(Heading(_, _, _)) = event { in_heading = false; } - if ticks_unbalanced - && let Some(span) = fragments.span(cx, paragraph_range.clone()) - { + if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { span_lint_and_help( cx, DOC_MARKDOWN, @@ -617,8 +615,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize check_link_quotes(cx, trimmed_text, range.clone(), fragments); } if let Some(link) = in_link.as_ref() - && let Ok(url) = Url::parse(link) - && (url.scheme() == "https" || url.scheme() == "http") { + && let Ok(url) = Url::parse(link) + && (url.scheme() == "https" || url.scheme() == "http") + { // Don't check the text associated with external URLs continue; } @@ -716,7 +715,9 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<u // Because of the global session, we need to create a new session in a different thread with // the edition we need. let text = text.to_owned(); - if thread::spawn(move || has_needless_main(text, edition)).join().expect("thread::spawn failed") + if thread::spawn(move || has_needless_main(text, edition)) + .join() + .expect("thread::spawn failed") && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) { span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); @@ -756,11 +757,12 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str } fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { - /// Checks if a string is camel-case, i.e., contains at least two uppercase - /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok). + /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and + /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case + /// letter (`NASA` is ok). /// Plurals are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { - if s.starts_with(|c: char| c.is_ascii_digit()) { + if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index 29425b2e554..63f32173b05 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// mistake. /// /// ### Example - /// ```rust + /// ```no_run /// fn simple_double_parens() -> i32 { /// ((0)) /// } @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn simple_no_parens() -> i32 { /// 0 /// } diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 14122abbf2c..177e04dfa6b 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// have been intended. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// let x = Foo; /// std::mem::drop(x); @@ -36,7 +36,7 @@ declare_clippy_lint! { /// have been intended. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// let x = Foo; /// std::mem::forget(x); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// destructor, possibly causing leaks. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::mem; /// # use std::rc::Rc; /// mem::forget(Rc::new(55)) @@ -90,7 +90,8 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg, note_span) = match fn_name { - // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types + // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, + // forgetting_copy_types sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return, sym::mem_forget if arg_ty.is_ref() => return, sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return, @@ -100,8 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { if !(arg_ty.needs_drop(cx.tcx, cx.param_env) || is_must_use_func_call(cx, arg) || is_must_use_ty(cx, arg_ty) - || drop_is_single_call_in_arm - ) => + || drop_is_single_call_in_arm) => { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span)) }, @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { } else { (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span)) } - } + }, _ => return, }; span_lint_and_note( diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index bf4488570ea..61db1c1abd1 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// /// ### Example - /// ```rust + /// ```no_run /// # fn a() {} /// # fn b() {} /// # let x: i32 = 1; @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// # fn a() {} /// # fn b() {} /// # let x: i32 = 1; diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs index 209fb66fa40..5fcdca7cf36 100644 --- a/src/tools/clippy/clippy_lints/src/empty_drop.rs +++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// destructured, which might be the intention behind adding the implementation as a marker. /// /// ### Example - /// ```rust + /// ```no_run /// struct S; /// /// impl Drop for S { @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct S; /// ``` #[clippy::version = "1.62.0"] diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 1701d061128..a5699727b5b 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// /// /// ### Example - /// ```rust + /// ```no_run /// enum Test {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![feature(never_type)] /// /// struct Test(!); diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs index 282157181ab..4e2a8b73c0a 100644 --- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs @@ -15,11 +15,11 @@ declare_clippy_lint! { /// Empty brackets after a struct declaration can be omitted. /// /// ### Example - /// ```rust + /// ```no_run /// struct Cookie {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Cookie; /// ``` #[clippy::version = "1.62.0"] @@ -35,7 +35,8 @@ impl EarlyLintPass for EmptyStructsWithBrackets { if let ItemKind::Struct(var_data, _) = &item.kind && has_brackets(var_data) - && has_no_fields(cx, var_data, span_after_ident) { + && has_no_fields(cx, var_data, span_after_ident) + { span_lint_and_then( cx, EMPTY_STRUCTS_WITH_BRACKETS, @@ -46,8 +47,9 @@ impl EarlyLintPass for EmptyStructsWithBrackets { span_after_ident, "remove the brackets", ";", - Applicability::Unspecified); - }, + Applicability::Unspecified, + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 70a467dde61..3e3c62e85d0 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// /// ### Known problems /// The suggestion may have type inference errors in some cases. e.g. - /// ```rust + /// ```no_run /// let mut map = std::collections::HashMap::new(); /// let _ = if !map.contains_key(&0) { /// map.insert(0, 0) @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); /// # let k = 1; @@ -43,7 +43,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); /// # let k = 1; diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 646767868e2..003b5fc7261 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// architectures, but works fine on 64 bit. /// /// ### Example - /// ```rust + /// ```no_run /// # #[cfg(target_pointer_width = "64")] /// #[repr(usize)] /// enum NonPortable { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index c691e6c5402..575fead5bf3 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Let(let_expr) = expr.kind - && unary_pattern(let_expr.pat) { + && unary_pattern(let_expr.pat) + { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; @@ -79,7 +80,9 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { "({})", snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, ), - _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(), + _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability) + .0 + .to_string(), }; span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs index 6d429fbd035..bc878555c66 100644 --- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs +++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs @@ -41,10 +41,11 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { }; match item.kind { - ItemKind::TyAlias(..) if item.ident.name == sym::Error - && is_visible_outside_module(cx, item.owner_id.def_id) - && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() - && implements_trait(cx, ty, error_def_id, &[]) => + ItemKind::TyAlias(..) + if item.ident.name == sym::Error + && is_visible_outside_module(cx, item.owner_id.def_id) + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && implements_trait(cx, ty, error_def_id, &[]) => { span_lint( cx, @@ -53,13 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { "exported type alias named `Error` that implements `Error`", ); }, - ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) - && error_def_id == trait_def_id - && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) - && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) - && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) - && ident.name == sym::Error - && is_visible_outside_module(cx, def_id) => + ItemKind::Impl(imp) + if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) + && error_def_id == trait_def_id + && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) + && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) + && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) + && ident.name == sym::Error + && is_visible_outside_module(cx, def_id) => { span_lint_hir_and_then( cx, @@ -69,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { "exported type named `Error` that implements `Error`", |diag| { diag.span_note(item.span, "`Error` was implemented here"); - } + }, ); - } + }, _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index dbe3453e7bf..3d0ddca19c9 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::kw; use rustc_target::spec::abi::Abi; @@ -28,12 +28,12 @@ declare_clippy_lint! { /// into something. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: Box<u32>) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(x: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 38066503c07..fad8fbf0449 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -119,19 +119,21 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { match body.value.kind { ExprKind::Call(callee, args) - if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) => + if matches!( + callee.kind, + ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..)) + ) => { let callee_ty = typeck.expr_ty(callee).peel_refs(); - if matches!( - type_diagnostic_name(cx, callee_ty), - Some(sym::Arc | sym::Rc) - ) || !check_inputs(typeck, body.params, None, args) { + if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) + || !check_inputs(typeck, body.params, None, args) + { return; } - let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or( - callee_ty, - |a| a.target.peel_refs(), - ); + let callee_ty_adjusted = typeck + .expr_adjustments(callee) + .last() + .map_or(callee_ty, |a| a.target.peel_refs()); let sig = match callee_ty_adjusted.kind() { ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(), @@ -160,36 +162,26 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { // For now ignore all callee types which reference a type parameter. && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_))) { - span_lint_and_then( - cx, - REDUNDANT_CLOSURE, - expr.span, - "redundant closure", - |diag| { - if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if let Ok((ClosureKind::FnMut, _)) - = cx.tcx.infer_ctxt().build().type_implements_fn_trait( - cx.param_env, - Binder::bind_with_vars(callee_ty_adjusted, List::empty()), - ImplPolarity::Positive, - ) && path_to_local(callee) - .map_or( - false, - |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr), - ) - { - // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {snippet}"); - } - diag.span_suggestion( - expr.span, - "replace the closure with the function itself", - snippet, - Applicability::MachineApplicable, - ); + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { + if let Some(mut snippet) = snippet_opt(cx, callee.span) { + if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait( + cx.param_env, + Binder::bind_with_vars(callee_ty_adjusted, List::empty()), + ImplPolarity::Positive, + ) && path_to_local(callee).map_or(false, |l| { + local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) + }) { + // Mutable closure is used after current expr; we cannot consume it. + snippet = format!("&mut {snippet}"); } + diag.span_suggestion( + expr.span, + "replace the closure with the function itself", + snippet, + Applicability::MachineApplicable, + ); } - ); + }); } }, ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => { diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index aef2db38583..1d18e194d15 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// readability and API. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { /// is_pending: bool, /// is_processing: bool, @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// enum S { /// Pending, /// Processing, @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { // functions with a body are already checked by `check_fn` if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind && fn_sig.header.abi == Abi::Rust - { + { self.check_fn_sig(cx, fn_sig.decl, fn_sig.span); } } @@ -174,11 +174,8 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust - && get_parent_as_impl(cx.tcx, hir_id) - .map_or(true, - |impl_item| impl_item.of_trait.is_none() - ) - { + && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none()) + { self.check_fn_sig(cx, fn_decl, span); } } diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 9fd13084dc9..f976cfd3f22 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -17,14 +17,14 @@ declare_clippy_lint! { /// disable them by default. /// /// ### Example - /// ```rust + /// ```no_run /// enum Foo { /// Bar, /// Baz /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// enum Foo { /// Bar, @@ -47,14 +47,14 @@ declare_clippy_lint! { /// disable them by default. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// bar: u8, /// baz: String, /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// struct Foo { /// bar: u8, diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs index 5ecd0ffadf3..e14b1c556ec 100644 --- a/src/tools/clippy/clippy_lints/src/exit.rs +++ b/src/tools/clippy/clippy_lints/src/exit.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// the main function. /// /// ### Example - /// ``` + /// ```no_run /// std::process::exit(0) /// ``` /// diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 6f6177340f4..4b5bcb06a1e 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// Using `(e)println! is clearer and more concise /// /// ### Example - /// ```rust + /// ```no_run /// # use std::io::Write; /// # let bar = "furchtbar"; /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); @@ -27,7 +27,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::io::Write; /// # let bar = "furchtbar"; /// eprintln!("foo: {:?}", bar); @@ -58,7 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { Some(sym::io_stderr) => ("stderr", "e"), _ => return, }; - let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { return; }; + let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { + return; + }; // ordering is important here, since `writeln!` uses `write!` internally let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { @@ -78,18 +80,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { macro_name.replace("write", "print"), ) } else { - ( - format!("{dest_name}().write_fmt(...)"), - "print".into(), - ) + (format!("{dest_name}().write_fmt(...)"), "print".into()) }; let mut applicability = Applicability::MachineApplicable; - let inputs_snippet = snippet_with_applicability( - cx, - format_args_inputs_span(&format_args), - "..", - &mut applicability, - ); + let inputs_snippet = + snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_WRITE, diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 0a885984abb..d6c746901fc 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -23,13 +23,13 @@ declare_clippy_lint! { /// requires using a turbofish, which serves no purpose but to satisfy the compiler. /// /// ### Example - /// ```rust + /// ```no_run /// fn unused_ty<T>(x: u8) { /// // .. /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn no_unused_ty(x: u8) { /// // .. /// } @@ -177,20 +177,22 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .iter() .rev() .map(|(idx, param)| { - if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) { - // Extend the current span forward, up until the next param in the list. - param.span.until(next.span) - } else { - // Extend the current span back to include the comma following the previous - // param. If the span of the next param in the list has already been - // extended, we continue the chain. This is why we're iterating in reverse. - end = Some(param.def_id); + if let Some(next) = explicit_params.get(idx + 1) + && end != Some(next.def_id) + { + // Extend the current span forward, up until the next param in the list. + param.span.until(next.span) + } else { + // Extend the current span back to include the comma following the previous + // param. If the span of the next param in the list has already been + // extended, we continue the chain. This is why we're iterating in reverse. + end = Some(param.def_id); - // idx will never be 0, else we'd be removing the entire list of generics - let prev = explicit_params[idx - 1]; - let prev_span = self.get_bound_span(prev); - self.get_bound_span(param).with_lo(prev_span.hi()) - } + // idx will never be 0, else we'd be removing the entire list of generics + let prev = explicit_params[idx - 1]; + let prev_span = self.get_bound_span(prev); + self.get_bound_span(param).with_lo(prev_span.hi()) + } }) .collect() }; diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 2ef547526d4..efb69476b94 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `TryFrom` should be used if there's a possibility of failure. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo(i32); /// /// impl From<String> for Foo { @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// struct Foo(i32); /// /// impl TryFrom<String> for Foo { diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index d182bb62195..506a1191747 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// Rust will truncate the literal silently. /// /// ### Example - /// ```rust + /// ```no_run /// let v: f32 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let v: f64 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789_9 /// ``` @@ -44,12 +44,12 @@ declare_clippy_lint! { /// conversion to a float. /// /// ### Example - /// ```rust + /// ```no_run /// let _: f32 = 16_777_217.0; // 16_777_216.0 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let _: f32 = 16_777_216.0; /// let _: f64 = 16_777_217.0; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index 29e5315f88b..09a9d9924de 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// Negatively impacts accuracy. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 3f32; /// let _ = a.powf(1.0 / 3.0); /// let _ = (1.0 + a).ln(); @@ -35,7 +35,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = 3f32; /// let _ = a.cbrt(); /// let _ = a.ln_1p(); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// Negatively impacts accuracy and performance. /// /// ### Example - /// ```rust + /// ```no_run /// use std::f32::consts::E; /// /// let a = 3f32; @@ -83,7 +83,7 @@ declare_clippy_lint! { /// /// is better expressed as /// - /// ```rust + /// ```no_run /// use std::f32::consts::E; /// /// let a = 3f32; @@ -323,9 +323,9 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: let maybe_neg_sugg = |expr, hir_id| { let sugg = Sugg::hir(cx, expr, ".."); if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { - format!("-{}", sugg.maybe_par()) + -sugg } else { - sugg.to_string() + sugg } }; @@ -470,25 +470,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { let maybe_neg_sugg = |expr| { let sugg = Sugg::hir(cx, expr, ".."); - if let BinOpKind::Sub = op { - format!("-{sugg}") - } else { - sugg.to_string() - } + if let BinOpKind::Sub = op { -sugg } else { sugg } }; let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { - ( - inner_lhs, - Sugg::hir(cx, inner_rhs, "..").to_string(), - maybe_neg_sugg(rhs), - ) + (inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs)) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { - ( - inner_lhs, - maybe_neg_sugg(inner_rhs), - Sugg::hir(cx, lhs, "..").to_string(), - ) + (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "..")) } else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index b748d329367..18ed05c1ca6 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -23,13 +23,13 @@ declare_clippy_lint! { /// if `foo: &str`. /// /// ### Examples - /// ```rust + /// ```no_run /// let foo = "foo"; /// format!("{}", foo); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo = "foo"; /// foo.to_owned(); /// ``` @@ -54,7 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let Some(snippet) = snippet_opt(cx, format_args.span) else { + return; + }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); @@ -76,13 +78,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { _ => false, }; let sugg = if is_new_string { - snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability) + .0 + .into_owned() } else { let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability); format!("{}.to_string()", sugg.maybe_par()) }; span_useless_format(cx, call_site, sugg, applicability); - } }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 39abf5c2def..3c1f2d9d5dc 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -1,11 +1,11 @@ use arrayvec::ArrayVec; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, }; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; @@ -35,12 +35,12 @@ declare_clippy_lint! { /// The recommended code is both shorter and avoids a temporary allocation. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: {}", format!("something failed at {}", Location::caller())); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` @@ -61,12 +61,12 @@ declare_clippy_lint! { /// unnecessary. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller().to_string()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` @@ -87,7 +87,7 @@ declare_clippy_lint! { /// The inlined syntax, where allowed, is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// # let var = 42; /// # let width = 1; /// # let prec = 2; @@ -98,7 +98,7 @@ declare_clippy_lint! { /// format!("{:.*}", prec, var); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let var = 42; /// # let width = 1; /// # let prec = 2; @@ -111,12 +111,12 @@ declare_clippy_lint! { /// /// If allow-mixed-uninlined-format-args is set to false in clippy.toml, /// the following code will also trigger the lint: - /// ```rust + /// ```no_run /// # let var = 42; /// format!("{} {}", var, 1+2); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let var = 42; /// format!("{var} {}", 1+2); /// ``` @@ -141,13 +141,13 @@ declare_clippy_lint! { /// an expected formatting operation such as adding padding isn't happening. /// /// ### Example - /// ```rust + /// ```no_run /// println!("{:.}", 1.0); /// /// println!("not padded: {:5}", format_args!("...")); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// println!("{}", 1.0); /// /// println!("not padded: {}", format_args!("...")); @@ -370,7 +370,7 @@ fn check_one_arg( }; fixes.push((pos_span, replacement)); fixes.push((arg_span, String::new())); - true // successful inlining, continue checking + true // successful inlining, continue checking } else { // Do not continue inlining (return false) in case // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 1d2f7cb7130..08ee7032c09 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// use std::fmt; /// /// struct Structure(i32); @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// struct Structure(i32); @@ -59,7 +59,7 @@ declare_clippy_lint! { /// should write to the `Formatter`, not stdout/stderr. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt::{Display, Error, Formatter}; /// /// struct S; @@ -72,7 +72,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::{Display, Error, Formatter}; /// /// struct S; diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs index 45f67020c2d..ac45f5aedfa 100644 --- a/src/tools/clippy/clippy_lints/src/format_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer. /// /// ### Example - /// ```rust + /// ```no_run /// let mut s = String::new(); /// s += &format!("0x{:X}", 1024); /// s.push_str(&format!("0x{:X}", 1024)); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::Write as _; // import without risk of name clashing /// /// let mut s = String::new(); @@ -58,7 +58,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { arms.iter().any(|arm| is_format(cx, arm.body)) }, Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => { - is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e)) + is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) }, _ => false, } @@ -69,17 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let arg = match expr.kind { ExprKind::MethodCall(_, _, [arg], _) => { - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && - match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, fn_def_id, &paths::PUSH_STR) + { arg } else { return; } - } - ExprKind::AssignOp(op, left, arg) - if op.node == BinOpKind::Add && is_string(cx, left) => { - arg }, + ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg, _ => return, }; if is_format(cx, arg) { diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 4ebf0e9667d..2c9c43d3ea7 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ declare_clippy_lint! { /// This is either a typo in the binary operator or confusing. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = true; /// # let bar = false; /// // &&! looks like a different operator @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = true; /// # let bar = false; /// if foo && !bar {} diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs index 0ec52f89e71..69bc0b726fc 100644 --- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs +++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// comment. /// /// ### Example - /// ```rust + /// ```no_run /// //// My amazing data structure /// pub struct Foo { /// // ... @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// /// My amazing data structure /// pub struct Foo { /// // ... diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 2b899e21ef5..5477532bb95 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::path_def_id; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; @@ -24,7 +24,7 @@ declare_clippy_lint! { /// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. /// /// ### Example - /// ```rust + /// ```no_run /// struct StringWrapper(String); /// /// impl Into<StringWrapper> for String { @@ -34,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct StringWrapper(String); /// /// impl From<String> for StringWrapper { @@ -88,7 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { cx.tcx.sess.source_map().guess_head_span(item.span), "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true", |diag| { - // If the target type is likely foreign mention the orphan rules as it's a common source of confusion + // If the target type is likely foreign mention the orphan rules as it's a common source of + // confusion if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) { diag.help( "`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\ @@ -96,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { ); } - let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty()); + let message = format!( + "replace the `Into` implementation with `From<{}>`", + middle_trait_ref.self_ty() + ); if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) { diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable); } else { @@ -110,12 +114,12 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { extract_msrv_attr!(LateContext); } -/// Finds the occurences of `Self` and `self` +/// Finds the occurrences of `Self` and `self` struct SelfFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, - /// Occurences of `Self` + /// Occurrences of `Self` upper: Vec<Span>, - /// Occurences of `self` + /// Occurrences of `self` lower: Vec<Span>, /// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding /// already named `val` diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index 617c96b4fcb..d9138d48b2c 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::ffi::c_void; /// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; /// let _ = unsafe { Box::from_raw(ptr) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::ffi::c_void; /// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; /// let _ = unsafe { Box::from_raw(ptr as *mut usize) }; @@ -40,14 +40,22 @@ declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]); impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name == sym!(from_raw) - && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) - && let arg_kind = cx.typeck_results().expr_ty(arg).kind() - && let RawPtr(TypeAndMut { ty, .. }) = arg_kind - && is_c_void(cx, *ty) { + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind + && seg.ident.name == sym!(from_raw) + && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) + && let arg_kind = cx.typeck_results().expr_ty(arg).kind() + && let RawPtr(TypeAndMut { ty, .. }) = arg_kind + && is_c_void(cx, *ty) + { let msg = format!("creating a `{type_str}` from a void raw pointer"); - span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type"); + span_lint_and_help( + cx, + FROM_RAW_WITH_VOID_PTR, + expr.span, + &msg, + Some(arg.span), + "cast this to a pointer of the appropriate type", + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 716908483e9..3f5cceec70e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// grouping some parameters into a new type. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Color; /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { /// // .. @@ -46,7 +46,7 @@ declare_clippy_lint! { /// multiple functions. /// /// ### Example - /// ```rust + /// ```no_run /// fn im_too_long() { /// println!(""); /// // ... 100 more LoC @@ -129,7 +129,7 @@ declare_clippy_lint! { /// a remnant of a refactoring that removed the return type. /// /// ### Examples - /// ```rust + /// ```no_run /// #[must_use] /// fn useless() { } /// ``` @@ -151,7 +151,7 @@ declare_clippy_lint! { /// attribute to improve the lint message. /// /// ### Examples - /// ```rust + /// ```no_run /// #[must_use] /// fn double_must_use() -> Result<(), ()> { /// unimplemented!(); @@ -183,7 +183,7 @@ declare_clippy_lint! { /// `#[must_use]`. /// /// ### Examples - /// ```rust + /// ```no_run /// // this could be annotated with `#[must_use]`. /// pub fn id<T>(t: T) -> T { t } /// ``` @@ -211,7 +211,7 @@ declare_clippy_lint! { /// instead. /// /// ### Examples - /// ```rust + /// ```no_run /// pub fn read_u8() -> Result<u8, ()> { Err(()) } /// ``` /// should become @@ -262,7 +262,7 @@ declare_clippy_lint! { /// The size determined by Clippy is platform-dependent. /// /// ### Examples - /// ```rust + /// ```no_run /// pub enum ParseError { /// UnparsedBytes([u8; 512]), /// UnexpectedEof, @@ -274,7 +274,7 @@ declare_clippy_lint! { /// } /// ``` /// should be - /// ``` + /// ```no_run /// pub enum ParseError { /// UnparsedBytes(Box<[u8; 512]>), /// UnexpectedEof, @@ -301,7 +301,7 @@ declare_clippy_lint! { /// /// ### Example - /// ```rust + /// ```no_run /// struct A { /// a: String, /// b: String, @@ -315,7 +315,7 @@ declare_clippy_lint! { /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct A { /// a: String, /// b: String, @@ -340,14 +340,14 @@ declare_clippy_lint! { /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. /// /// ### Example - /// ```rust + /// ```no_run /// trait MyTrait {} /// fn foo(a: impl MyTrait) { /// // [...] /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// trait MyTrait {} /// fn foo<T: MyTrait>(a: T) { /// // [...] diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 57df5683c9d..3aaf63ce340 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -118,9 +118,10 @@ fn check_needless_must_use( if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(); if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) - && !is_must_use_ty(cx, future_ty) { - return; - } + && !is_must_use_ty(cx, future_ty) + { + return; + } } span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 90fc0d4f662..485235514de 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -21,7 +21,9 @@ fn result_err_ty<'tcx>( ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !in_external_macro(cx.sess(), item_span) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output()) + && let ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output()) && is_type_diagnostic_item(cx, ty, sym::Result) && let ty::Adt(_, args) = ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 621415c881c..eee5b7540ba 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -34,11 +34,11 @@ declare_clippy_lint! { /// produced. /// /// ### Example - /// ```rust + /// ```no_run /// async fn not_send(bytes: std::rc::Rc<[u8]>) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// async fn is_send(bytes: std::sync::Arc<[u8]>) {} /// ``` #[clippy::version = "1.44.0"] 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 3d59b783337..cae561f7802 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -1,6 +1,7 @@ //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -16,7 +17,7 @@ declare_clippy_lint! { /// Negations reduce the readability of statements. /// /// ### Example - /// ```rust + /// ```no_run /// # let v: Vec<usize> = vec![]; /// # fn a() {} /// # fn b() {} @@ -29,7 +30,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let v: Vec<usize> = vec![]; /// # fn a() {} /// # fn b() {} @@ -47,6 +48,13 @@ declare_clippy_lint! { declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]); +fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { + if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) { + return Constant::Int(0) == value; + } + false +} + 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. @@ -72,7 +80,9 @@ impl LateLintPass<'_> for IfNotElse { "remove the `!` and swap the blocks of the `if`/`else`", ); }, - ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => { + ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => { + // Disable firing the lint on `… != 0`, as these are likely to be bit tests. + // For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order. span_lint_and_help( cx, IF_NOT_ELSE, diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index e2d19e24557..66c10ab228f 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; @@ -21,7 +21,7 @@ declare_clippy_lint! { /// in comparison to `bool::then`. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = vec![0]; /// let a = if v.is_empty() { /// println!("true!"); @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let v = vec![0]; /// let a = v.is_empty().then(|| { /// println!("true!"); @@ -76,7 +76,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { let ctxt = expr.span.ctxt(); - if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) + if let Some(higher::If { + cond, + then, + r#else: Some(els), + }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind @@ -86,7 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && !contains_return(then_block.stmts) { let mut app = Applicability::Unspecified; - let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) + .maybe_par() + .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() @@ -100,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { "then" }; - let help = format!( - "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`", - ); + let help = + format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",); span_lint_and_help( cx, IF_THEN_SOME_ELSE_NONE, diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs index ef2a66d4a20..76bdfb94eb8 100644 --- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// would detect a type change that `_` would ignore. /// /// ### Example - /// ```rust + /// ```no_run /// match std::fs::create_dir("tmp-work-dir") { /// Ok(_) => println!("Working directory created"), /// Err(s) => eprintln!("Could not create directory: {s}"), /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// match std::fs::create_dir("tmp-work-dir") { /// Ok(()) => println!("Working directory created"), /// Err(s) => eprintln!("Could not create directory: {s}"), @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { }, _ => {}, } - if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() { + if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() { span_lint_and_sugg( cx, IGNORED_UNIT_PATTERNS, diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 2b2ea156cd4..eaf80de3857 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use if_chain::if_chain; @@ -35,7 +35,7 @@ declare_clippy_lint! { /// pieces of code, possibly including external crates. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; /// # trait Serialize {}; @@ -44,7 +44,7 @@ declare_clippy_lint! { /// pub fn foo(map: &mut HashMap<i32, i32>) { } /// ``` /// could be rewritten as - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; /// # trait Serialize {}; diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index a6b035d5106..c6bcf3ba40c 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -24,13 +24,13 @@ declare_clippy_lint! { /// corresponding statements. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// x /// } /// ``` /// add return - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// return x; /// } diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index ee7973b82ab..24f62490f96 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// The built-in function is more readable and may be faster. /// /// ### Example - /// ```rust + /// ```no_run ///let mut u:u32 = 7000; /// /// if u != u32::MAX { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run ///let mut u:u32 = 7000; /// /// u = u.saturating_add(1); @@ -82,18 +82,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { fn get_int_max(ty: Ty<'_>) -> Option<u128> { match ty.peel_refs().kind() { - Int(IntTy::I8) => i8::max_value().try_into().ok(), - Int(IntTy::I16) => i16::max_value().try_into().ok(), - Int(IntTy::I32) => i32::max_value().try_into().ok(), - Int(IntTy::I64) => i64::max_value().try_into().ok(), - Int(IntTy::I128) => i128::max_value().try_into().ok(), - Int(IntTy::Isize) => isize::max_value().try_into().ok(), - Uint(UintTy::U8) => u8::max_value().try_into().ok(), - Uint(UintTy::U16) => u16::max_value().try_into().ok(), - Uint(UintTy::U32) => u32::max_value().try_into().ok(), - Uint(UintTy::U64) => u64::max_value().try_into().ok(), - Uint(UintTy::U128) => Some(u128::max_value()), - Uint(UintTy::Usize) => usize::max_value().try_into().ok(), + Int(IntTy::I8) => i8::MAX.try_into().ok(), + Int(IntTy::I16) => i16::MAX.try_into().ok(), + Int(IntTy::I32) => i32::MAX.try_into().ok(), + Int(IntTy::I64) => i64::MAX.try_into().ok(), + Int(IntTy::I128) => i128::MAX.try_into().ok(), + Int(IntTy::Isize) => isize::MAX.try_into().ok(), + Uint(UintTy::U8) => Some(u8::MAX.into()), + Uint(UintTy::U16) => Some(u16::MAX.into()), + Uint(UintTy::U32) => Some(u32::MAX.into()), + Uint(UintTy::U64) => Some(u64::MAX.into()), + Uint(UintTy::U128) => Some(u128::MAX), + Uint(UintTy::Usize) => usize::MAX.try_into().ok(), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index b99d4544681..859404289d9 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Simplicity and readability. Instead we can easily use an builtin function. /// /// ### Example - /// ```rust + /// ```no_run /// # let end: u32 = 10; /// # let start: u32 = 5; /// let mut i: u32 = end - start; @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let end: u32 = 10; /// # let start: u32 = 5; /// let mut i: u32 = end - start; diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index ec9044bba5c..ff27a5d666d 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`) /// /// ### Example - /// ```rust + /// ```no_run /// # use std::ops::{Deref,DerefMut}; /// fn f() -> impl Deref<Target = i32> + DerefMut<Target = i32> { /// // ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound @@ -37,7 +37,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::ops::{Deref,DerefMut}; /// fn f() -> impl DerefMut<Target = i32> { /// Box::new(123) @@ -230,19 +230,24 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { // Example: // `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed. // `DerefMut::Target` needs to match `Deref::Target`. - let implied_bounds: Vec<_> = opaque_ty.bounds.iter().filter_map(|bound| { - if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound - && let [.., path] = poly_trait.trait_ref.path.segments - && poly_trait.bound_generic_params.is_empty() - && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates - && !predicates.is_empty() // If the trait has no supertrait, there is nothing to add. - { - Some((bound.span(), path, predicates, trait_def_id)) - } else { - None - } - }).collect(); + let implied_bounds: Vec<_> = opaque_ty + .bounds + .iter() + .filter_map(|bound| { + if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound + && let [.., path] = poly_trait.trait_ref.path.segments + && poly_trait.bound_generic_params.is_empty() + && let Some(trait_def_id) = path.res.opt_def_id() + && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates + && !predicates.is_empty() + // If the trait has no supertrait, there is nothing to add. + { + Some((bound.span(), path, predicates, trait_def_id)) + } else { + None + } + }) + .collect(); // Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec. // This involves some extra logic when generic arguments are present, since @@ -253,30 +258,31 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { && let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() - && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = implied_bounds - .iter() - .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { - let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); - let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); + && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = + implied_bounds + .iter() + .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { + let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); + let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); - preds.iter().find_map(|(clause, _)| { - if let ClauseKind::Trait(tr) = clause.kind().skip_binder() - && tr.def_id() == def_id - && is_same_generics( - cx.tcx, - tr.trait_ref.args, - implied_by_args, - implied_args, - implied_by_def_id, - def_id, - ) - { - Some((span, implied_by_args, implied_by_bindings)) - } else { - None - } + preds.iter().find_map(|(clause, _)| { + if let ClauseKind::Trait(tr) = clause.kind().skip_binder() + && tr.def_id() == def_id + && is_same_generics( + cx.tcx, + tr.trait_ref.args, + implied_by_args, + implied_args, + implied_by_def_id, + def_id, + ) + { + Some((span, implied_by_args, implied_by_bindings)) + } else { + None + } + }) }) - }) { emit_lint( cx, @@ -286,7 +292,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { implied_bindings, implied_by_bindings, implied_by_args, - implied_by_span + implied_by_span, ); } } diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 1ad886f2cf3..a84f7351ad6 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// Since the order of fields in a constructor doesn't affect the /// resulted instance as the below example indicates, /// - /// ```rust + /// ```no_run /// #[derive(Debug, PartialEq, Eq)] /// struct Foo { /// x: i32, @@ -35,7 +35,7 @@ declare_clippy_lint! { /// inconsistent order can be confusing and decreases readability and consistency. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// x: i32, /// y: i32, @@ -47,7 +47,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct Foo { /// # x: i32, /// # y: i32, diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index f507f45d5bb..c2f1f18e39d 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -1,7 +1,7 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use if_chain::if_chain; @@ -31,7 +31,7 @@ declare_clippy_lint! { /// patterns. /// /// ### Example - /// ```rust + /// ```no_run /// let slice: Option<&[u32]> = Some(&[1, 2, 3]); /// /// if let Some(slice) = slice { @@ -39,7 +39,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let slice: Option<&[u32]> = Some(&[1, 2, 3]); /// /// if let Some(&[first, ..]) = slice { diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 4f4f571773f..1ce7d85d382 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = [1, 2, 3, 4]; /// // Index within bounds /// @@ -65,7 +65,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #![allow(unused)] /// /// # let x = vec![0; 5]; diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index fe28c526be3..e9c53671a93 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// this lint is not clever enough to analyze it. /// /// ### Example - /// ```rust + /// ```no_run /// let infinite_iter = 0..; /// # #[allow(unused)] /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 3d1113ff9cc..a61a6416193 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Splitting the implementation of a type makes the code harder to navigate. /// /// ### Example - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn one() {} @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn one() {} diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index bc4ec33b733..fe5eb5ccac5 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct A; /// /// impl A { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; @@ -51,7 +51,7 @@ declare_clippy_lint! { /// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; @@ -70,7 +70,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs index f95d2c2edb1..269311a67d6 100644 --- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// benefit as opposed to tuple initializers /// /// ### Example - /// ```rust + /// ```no_run /// struct TupleStruct(u8, u16); /// /// let _ = TupleStruct { diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index d609a5ca4d4..899126565f7 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// The inline attribute is ignored for trait methods without bodies. /// /// ### Example - /// ```rust + /// ```no_run /// trait Animal { /// #[inline] /// fn name(&self) -> &'static str; diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index a1a115f6d79..32b2cb4385f 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{self, span_lint_and_sugg}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty; @@ -21,13 +21,13 @@ declare_clippy_lint! { /// `prev_instant.elapsed()` also more clearly signals intention. /// /// ### Example - /// ```rust + /// ```no_run /// use std::time::Instant; /// let prev_instant = Instant::now(); /// let duration = Instant::now() - prev_instant; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::time::Instant; /// let prev_instant = Instant::now(); /// let duration = prev_instant.elapsed(); @@ -47,13 +47,13 @@ declare_clippy_lint! { /// unintentional panics. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now() - Duration::from_secs(5); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); /// ``` 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 1b14e525d9a..9ffcee07d28 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -16,14 +16,14 @@ declare_clippy_lint! { /// Readability -- better to use `> y` instead of `>= y + 1`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 1; /// if x >= y + 1 {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 1; /// if x > y {} 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 6ea637412d5..de82935e66b 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// https://github.com/rust-lang/rust-clippy/issues/886 /// /// ### Example - /// ```rust + /// ```no_run /// let x: u8 = 1; /// (x as u32) > 300; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 8b4984da3dd..90048d96c9c 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -7,7 +7,7 @@ use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_sta use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::Symbol; declare_clippy_lint! { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹` /// /// ### Example - /// ```rust + /// ```no_run /// enum Cake { /// BlackForestCake, /// HummingbirdCake, @@ -34,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// enum Cake { /// BlackForest, /// Hummingbird, @@ -56,14 +56,14 @@ declare_clippy_lint! { /// It requires the user to type the module name twice. /// /// ### Example - /// ```rust + /// ```no_run /// mod cake { /// struct BlackForestCake; /// } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// mod cake { /// struct BlackForest; /// } @@ -119,7 +119,7 @@ declare_clippy_lint! { /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹` /// /// ### Example - /// ```rust + /// ```no_run /// struct Cake { /// cake_sugar: u8, /// cake_flour: u8, @@ -127,7 +127,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Cake { /// sugar: u8, /// flour: u8, @@ -320,6 +320,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n return; } + for var in def.variants { + check_enum_start(cx, item_name, var); + check_enum_end(cx, item_name, var); + } + let first = match def.variants.first() { Some(variant) => variant.ident.name.as_str(), None => return, @@ -328,8 +333,6 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n let mut post = pre.clone(); post.reverse(); for var in def.variants { - check_enum_start(cx, item_name, var); - check_enum_end(cx, item_name, var); let name = var.ident.name.as_str(); let variant_split = camel_case_split(name); diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index a7ec57e2850..9605d76fbf0 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// it's hard to figure out which item is meant in a statement. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() { /// println!("cake"); /// } @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo() { /// println!("cake"); /// } diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs index 41477242bcc..35e01862cee 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### Why is this bad? /// Having items declared after the testing module is confusing and may lead to bad test coverage. /// ### Example - /// ```rust + /// ```no_run /// #[cfg(test)] /// mod tests { /// // [...] @@ -25,7 +25,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn my_function() { /// // [...] /// } @@ -74,9 +74,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if let Some(last) = after.last() && after.iter().all(|&item| { - !matches!(item.kind, ItemKind::Mod(_)) - && !item.span.from_expansion() - && !is_from_proc_macro(cx, item) + !matches!(item.kind, ItemKind::Mod(_)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item) }) && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id())) { @@ -99,10 +97,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", - vec![ - (prev.span.shrink_to_hi(), items), - (items_span, String::new()) - ], + vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index 066d2c4b787..505aadd1a11 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Methods named `iter` or `iter_mut` conventionally return an `Iterator`. /// /// ### Example - /// ```rust + /// ```no_run /// // `String` does not implement `Iterator` /// struct Data {} /// impl Data { @@ -25,7 +25,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::str::Chars; /// struct Data {} /// impl Data { diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 0ee291a4e9d..3c291f25590 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -19,8 +19,13 @@ declare_clippy_lint! { /// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`. /// + /// ### Limitations + /// This lint focuses on providing an idiomatic API. Therefore, it will only + /// lint on types which are accessible outside of the crate. For internal types, + /// the `IntoIterator` trait can be implemented on demand if it is actually needed. + /// /// ### Example - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> MySlice<'a> { /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { @@ -29,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> MySlice<'a> { /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { @@ -61,8 +66,16 @@ declare_clippy_lint! { /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax /// in case of ambiguity with another `IntoIterator` impl. /// + /// ### Limitations + /// This lint focuses on providing an idiomatic API. Therefore, it will only + /// lint on types which are accessible outside of the crate. For internal types, + /// these methods can be added on demand if they are actually needed. Otherwise, + /// it would trigger the [`dead_code`] lint for the unused method. + /// + /// [`dead_code`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code + /// /// ### Example - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> IntoIterator for &MySlice<'a> { /// type Item = &'a u8; @@ -73,7 +86,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> MySlice<'a> { /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { @@ -104,6 +117,12 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool { !matches!(ty.kind, TyKind::OpaqueDef(..)) } +fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + ty.ty_adt_def() + .and_then(|adt| adt.did().as_local()) + .is_some_and(|did| cx.effective_visibilities.is_exported(did)) +} + /// Returns the deref chain of a type, starting with the type itself. fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx { iter::successors(Some(ty), |&ty| { @@ -136,17 +155,18 @@ impl LateLintPass<'_> for IterWithoutIntoIter { if let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait - && trait_ref.trait_def_id().is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && trait_ref + .trait_def_id() + .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() && let expected_method_name = match mtbl { Mutability::Mut => sym::iter_mut, Mutability::Not => sym::iter, } - && !deref_chain(cx, ty) - .any(|ty| { - // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method - ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) - }) + && !deref_chain(cx, ty).any(|ty| { + // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method + ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) + }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { if item.ident.name == sym!(IntoIter) { Some(cx.tcx.hir().impl_item(item.id).expect_type().span) @@ -154,6 +174,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { None } }) + && is_ty_exported(cx, ty) { span_lint_and_then( cx, @@ -165,7 +186,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { // to avoid name ambiguities, as there might be an inherent into_iter method // that we don't want to call. let sugg = format!( -" + " impl {self_ty_without_ref} {{ fn {expected_method_name}({ref_self}self) -> {iter_ty} {{ <{ref_self}Self as IntoIterator>::into_iter(self) @@ -183,9 +204,9 @@ impl {self_ty_without_ref} {{ sugg, // Just like iter_without_into_iter, this suggestion is on a best effort basis // and requires potentially adding lifetimes or moving them around. - Applicability::Unspecified + Applicability::Unspecified, ); - } + }, ); } } @@ -221,11 +242,12 @@ impl {self_ty_without_ref} {{ cx.tcx, cx.param_env, iterator_did, - sym!(Item), + sym::Item, [ret_ty], ) // Only lint if the `IntoIterator` impl doesn't actually exist && !implements_trait(cx, ref_ty, into_iter_did, &[]) + && is_ty_exported(cx, ref_ty.peel_refs()) { let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, "..")); @@ -233,22 +255,26 @@ impl {self_ty_without_ref} {{ cx, ITER_WITHOUT_INTO_ITER, item.span, - &format!("`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident), + &format!( + "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", + item.ident + ), |diag| { // Get the lower span of the `impl` block, and insert the suggestion right before it: // impl X { // ^ fn iter(&self) -> impl IntoIterator { ... } // } - let span_behind_impl = cx.tcx + let span_behind_impl = cx + .tcx .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id) .shrink_to_lo(); let sugg = format!( -" + " impl IntoIterator for {self_ty_snippet} {{ type IntoIter = {ret_ty}; - type Iter = {iter_ty}; - fn into_iter() -> Self::IntoIter {{ + type Item = {iter_ty}; + fn into_iter(self) -> Self::IntoIter {{ self.iter() }} }} @@ -262,7 +288,8 @@ impl IntoIterator for {self_ty_snippet} {{ // such as adding some lifetimes in the associated types, or importing types. Applicability::Unspecified, ); - }); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index b22b57a3006..0bf9b8718cd 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -38,7 +38,7 @@ declare_clippy_lint! { /// this may lead to a false positive. /// /// ### Example - /// ```rust + /// ```no_run /// enum Test { /// A(i32), /// B([i32; 8000]), @@ -46,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Possibly better /// enum Test2 { /// A(i32), diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index 90096f0f506..26a7278524e 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// large size of a `Future` may cause stack overflows. /// /// ### Example - /// ```rust + /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} /// /// pub async fn trigger() { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// /// `Box::pin` the big future instead. /// - /// ```rust + /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} /// /// pub async fn trigger() { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 0a5901bce04..5e312ab7240 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -39,27 +39,35 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind - && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) - && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) - && !cx.tcx.hir().parent_iter(expr.hir_id) - .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) - && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { - span_lint_and_help( - cx, - LARGE_STACK_ARRAYS, - expr.span, - &format!( - "allocating a local array larger than {} bytes", - self.maximum_allowed_size - ), - None, - &format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), - ); - } + && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() + && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) + && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { + matches!( + node, + Node::Item(Item { + kind: ItemKind::Static(..), + .. + }) + ) + }) + && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) + { + span_lint_and_help( + cx, + LARGE_STACK_ARRAYS, + expr.span, + &format!( + "allocating a local array larger than {} bytes", + self.maximum_allowed_size + ), + None, + &format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + ), + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index 1d28d7dd0e7..33636eb687f 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { /// ### Example /// This function creates four 500 KB arrays on the stack. Quite big but just small enough to not trigger `large_stack_arrays`. /// However, looking at the function as a whole, it's clear that this uses a lot of stack space. - /// ```rust + /// ```no_run /// struct QuiteLargeType([u8; 500_000]); /// fn foo() { /// // ... some function that uses a lot of stack space ... @@ -62,7 +62,7 @@ declare_clippy_lint! { /// /// Instead of doing this, allocate the arrays on the heap. /// This currently requires going through a `Vec` first and then converting it to a `Box`: - /// ```rust + /// ```no_run /// struct NotSoLargeType(Box<[u8]>); /// /// fn foo() { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index c06b35ca0da..0f17d26764c 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -15,7 +15,8 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{Span, Spanned, Symbol}; +use rustc_span::{Span, Symbol}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -181,8 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { let mut applicability = Applicability::MachineApplicable; let lit1 = peel_ref_operators(cx, lt.init); - let lit_str = - Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); + let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); span_lint_and_sugg( cx, @@ -288,18 +288,26 @@ enum LenOutput { } fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - if let ty::Alias(_, alias_ty) = ty.kind() && - let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) && - let Item { kind: ItemKind::OpaqueTy(opaque), .. } = item && - opaque.bounds.len() == 1 && - let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] && - generic_args.bindings.len() == 1 && - let TypeBindingKind::Equality { - term: rustc_hir::Term::Ty(rustc_hir::Ty {kind: TyKind::Path(QPath::Resolved(_, path)), .. }), - } = &generic_args.bindings[0].kind && - path.segments.len() == 1 { - return Some(&path.segments[0]); - } + if let ty::Alias(_, alias_ty) = ty.kind() + && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) + && let Item { + kind: ItemKind::OpaqueTy(opaque), + .. + } = item + && opaque.bounds.len() == 1 + && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] + && generic_args.bindings.len() == 1 + && let TypeBindingKind::Equality { + term: + rustc_hir::Term::Ty(rustc_hir::Ty { + kind: TyKind::Path(QPath::Resolved(_, path)), + .. + }), + } = &generic_args.bindings[0].kind + && path.segments.len() == 1 + { + return Some(&path.segments[0]); + } None } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index e7c875ab3a9..04f23a213f2 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// expr /// /// ### Example - /// ```rust + /// ```no_run /// fn f() -> Result<u32, u32> { /// Ok(0) /// } @@ -69,7 +69,7 @@ declare_clippy_lint! { /// and ignore the resulting value. /// /// ### Example - /// ```rust + /// ```no_run /// async fn foo() -> Result<(), ()> { /// Ok(()) /// } @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # async fn context() { /// async fn foo() -> Result<(), ()> { /// Ok(()) @@ -107,14 +107,14 @@ declare_clippy_lint! { /// lints. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> Result<u32, ()> { /// Ok(123) /// } /// let _ = foo(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo() -> Result<u32, ()> { /// Ok(123) /// } @@ -159,14 +159,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { binding or dropping explicitly with `std::mem::drop`", ); } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) { + && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) + { span_lint_and_help( cx, LET_UNDERSCORE_FUTURE, local.span, "non-binding `let` on a future", None, - "consider awaiting the future or dropping explicitly with `std::mem::drop`" + "consider awaiting the future or dropping explicitly with `std::mem::drop`", ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( @@ -203,17 +204,17 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { return; } - span_lint_and_help( + span_lint_and_help( cx, LET_UNDERSCORE_UNTYPED, local.span, "non-binding `let` without a type annotation", - Some( - Span::new(local.pat.span.hi(), - local.pat.span.hi() + BytePos(1), - local.pat.span.ctxt(), - local.pat.span.parent() - )), + Some(Span::new( + local.pat.span.hi(), + local.pat.span.hi() + BytePos(1), + local.pat.span.ctxt(), + local.pat.span.parent(), + )), "consider adding a type annotation", ); } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index a70a38ee08b..ab978a677c2 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -50,7 +50,6 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; -use clippy_utils::msrvs::Msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; use rustc_session::Session; @@ -358,9 +357,7 @@ mod zero_div_zero; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` -use crate::utils::conf::metadata::get_configuration_metadata; -pub use crate::utils::conf::{lookup_conf_file, Conf}; -use crate::utils::FindAll; +use clippy_config::{get_configuration_metadata, Conf}; /// Register all pre expansion lints /// @@ -462,16 +459,13 @@ pub fn explain(name: &str) -> i32 { if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { println!("{}", info.explanation); // Check if the lint has configuration - let mdconf = get_configuration_metadata(); - if let Some(config_vec_positions) = mdconf - .iter() - .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned())) - { - // If it has, print it + let mut mdconf = get_configuration_metadata(); + let name = name.to_ascii_lowercase(); + mdconf.retain(|cconf| cconf.lints.contains(&name)); + if !mdconf.is_empty() { println!("### Configuration for {}:\n", info.lint.name_lower()); - for position in config_vec_positions { - let conf = &mdconf[position]; - println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default); + for conf in mdconf { + println!("{conf}"); } } 0 @@ -519,7 +513,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: // all the internal lints #[cfg(feature = "internal")] { - store.register_early_pass(|| Box::new(utils::internal_lints::clippy_lints_internal::ClippyLintsInternal)); + store.register_early_pass(|| { + Box::new(utils::internal_lints::unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths) + }); store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls)); store.register_late_pass(|_| { diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 0004a150d51..7517003be23 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -20,7 +20,7 @@ use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{kw, Ident, Symbol}; declare_clippy_lint! { @@ -38,7 +38,7 @@ declare_clippy_lint! { /// are mentioned due to potential false positives. /// /// ### Example - /// ```rust + /// ```no_run /// // Unnecessary lifetime annotations /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { /// x @@ -46,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn elided(x: &u8, y: u8) -> &u8 { /// x /// } @@ -69,7 +69,7 @@ declare_clippy_lint! { /// them leads to more readable code. /// /// ### Example - /// ```rust + /// ```no_run /// // unnecessary lifetimes /// fn unused_lifetime<'a>(x: u8) { /// // .. @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn no_lifetime(x: u8) { /// // ... /// } @@ -517,9 +517,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) { let trait_ref = &poly_tref.trait_ref; - if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| { - self.cx.tcx.lang_items().get(item) == Some(id) - }) { + if let Some(id) = trait_ref.trait_def_id() + && lang_items::FN_TRAITS + .iter() + .any(|&item| self.cx.tcx.lang_items().get(item) == Some(id)) + { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_trait_ref(trait_ref); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs index ac949b67260..0a5f5a80cb7 100644 --- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs @@ -34,7 +34,7 @@ declare_clippy_lint! { /// successful results, using `map_while()` would stop at the first error. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::{fs::File, io::{self, BufRead, BufReader}}; /// # let _ = || -> io::Result<()> { /// let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok); @@ -43,7 +43,7 @@ declare_clippy_lint! { /// # Ok(()) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::{fs::File, io::{self, BufRead, BufReader}}; /// # let _ = || -> io::Result<()> { /// let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok); @@ -59,41 +59,56 @@ declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && - is_trait_method(cx, expr, sym::Iterator) && - (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) + if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind + && is_trait_method(cx, expr, sym::Iterator) + && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) { let lint = match &fm_arg.kind { // Detect `Result::ok` - ExprKind::Path(qpath) => - cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did| - match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(), + ExprKind::Path(qpath) => cx + .qpath_res(qpath, fm_arg.hir_id) + .opt_def_id() + .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)) + .unwrap_or_default(), // Detect `|x| x.ok()` - ExprKind::Closure(Closure { body, .. }) => - if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) && - let ExprKind::MethodCall(method, receiver, [], _) = value.kind && - path_to_local_id(receiver, param.pat.hir_id) && - let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) + ExprKind::Closure(Closure { body, .. }) => { + if let Body { + params: [param], value, .. + } = cx.tcx.hir().body(*body) + && let ExprKind::MethodCall(method, receiver, [], _) = value.kind + && path_to_local_id(receiver, param.pat.hir_id) + && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) { is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" } else { false } + }, _ => false, }; if lint { - span_lint_and_then(cx, + span_lint_and_then( + cx, LINES_FILTER_MAP_OK, fm_span, - &format!("`{}()` will run forever if the iterator repeatedly produces an `Err`", fm_method.ident), + &format!( + "`{}()` will run forever if the iterator repeatedly produces an `Err`", + fm_method.ident + ), |diag| { diag.span_note( fm_receiver.span, "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); - diag.span_suggestion(fm_span, "replace with", "map_while(Result::ok)", Applicability::MaybeIncorrect); - }); - } + diag.span_suggestion( + fm_span, + "replace with", + "map_while(Result::ok)", + Applicability::MaybeIncorrect, + ); + }, + ); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 09ca0317337..2c14bb72a9e 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -23,14 +23,14 @@ declare_clippy_lint! { /// Reading long numbers is difficult without separators. /// /// ### Example - /// ```rust + /// ```no_run /// # let _: u64 = /// 61864918973511 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _: u64 = /// 61_864_918_973_511 /// # ; @@ -73,14 +73,14 @@ declare_clippy_lint! { /// grouped digits. /// /// ### Example - /// ```rust + /// ```no_run /// # let _: u64 = /// 618_64_9189_73_511 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _: u64 = /// 61_864_918_973_511 /// # ; @@ -100,7 +100,7 @@ declare_clippy_lint! { /// Negatively impacts readability. /// /// ### Example - /// ```rust + /// ```no_run /// let x: u32 = 0xFFF_FFF; /// let y: u8 = 0b01_011_101; /// ``` @@ -120,7 +120,7 @@ declare_clippy_lint! { /// Negatively impacts readability. /// /// ### Example - /// ```rust + /// ```no_run /// let x: u64 = 6186491_8973511; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 6ab256ef001..1c2b7a169fc 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,6 +1,6 @@ use super::EXPLICIT_ITER_LOOP; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, make_normalized_projection, @@ -113,7 +113,9 @@ fn is_ref_iterable<'tcx>( let typeck = cx.typeck_results(); if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let Some(fn_id) = typeck.type_dependent_def_id(call_expr.hir_id) - && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) + && let sig = cx + .tcx + .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output && let param_env = cx.tcx.param_env(fn_id) && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[]) @@ -131,8 +133,9 @@ fn is_ref_iterable<'tcx>( return Some((AdjustKind::None, self_ty)); } - let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty) - .instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); + let res_ty = cx + .tcx + .erase_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() { Some(mutbl) } else { @@ -157,7 +160,7 @@ fn is_ref_iterable<'tcx>( let self_ty = if mutbl.is_mut() { self_ty } else { - Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl }) + Ty::new_ref(cx.tcx, region, TypeAndMut { ty, mutbl }) }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = @@ -172,10 +175,7 @@ fn is_ref_iterable<'tcx>( && !self_ty.is_ref() { // Attempt to borrow - let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut { - ty: self_ty, - mutbl, - }); + let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl }); if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty @@ -187,12 +187,14 @@ fn is_ref_iterable<'tcx>( match adjustments { [] => Some((AdjustKind::None, self_ty)), &[ - Adjustment { kind: Adjust::Deref(_), ..}, + Adjustment { + kind: Adjust::Deref(_), .. + }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), target, }, - .. + .., ] => { if enforce_iter_loop_reborrow && target != self_ty @@ -205,8 +207,14 @@ fn is_ref_iterable<'tcx>( } else { None } - } - &[Adjustment { kind: Adjust::Deref(_), target }, ..] => { + }, + &[ + Adjustment { + kind: Adjust::Deref(_), + target, + }, + .., + ] => { if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = @@ -217,13 +225,13 @@ fn is_ref_iterable<'tcx>( } else { None } - } + }, &[ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), target, }, - .. + .., ] => { if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) @@ -235,7 +243,7 @@ fn is_ref_iterable<'tcx>( } else { None } - } + }, _ => None, } } else { diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs index ed620460dbe..94c951fc10a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs @@ -1,9 +1,8 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -55,12 +54,3 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx } } } - -/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs index 0aaa66e6bce..a9a9058c93f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -10,7 +10,7 @@ use rustc_hir::def::Res; use rustc_hir::lang_items::LangItem; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 559a2c03f14..124a35f8f54 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the /// iterator element is used. diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 1fb16adad7a..67c80fb8387 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -14,17 +14,18 @@ mod needless_range_loop; mod never_loop; mod same_item_push; mod single_element_loop; +mod unused_enumerate_index; mod utils; mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; +use clippy_config::msrvs::Msrv; use clippy_utils::higher; -use clippy_utils::msrvs::Msrv; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; declare_clippy_lint! { @@ -36,7 +37,7 @@ declare_clippy_lint! { /// It is not as fast as a memcpy. /// /// ### Example - /// ```rust + /// ```no_run /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; /// for i in 0..src.len() { @@ -45,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]); @@ -67,7 +68,7 @@ declare_clippy_lint! { /// the bounds check that is done when indexing. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec!['a', 'b', 'c']; /// for i in 0..vec.len() { /// println!("{}", vec[i]); @@ -75,7 +76,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec!['a', 'b', 'c']; /// for i in vec { /// println!("{}", i); @@ -100,7 +101,7 @@ declare_clippy_lint! { /// types. /// /// ### Example - /// ```rust + /// ```no_run /// // with `y` a `Vec` or slice: /// # let y = vec![1]; /// for x in y.iter() { @@ -109,7 +110,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = vec![1]; /// for x in &y { /// // .. @@ -130,7 +131,7 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = vec![1]; /// // with `y` a `Vec` or slice: /// for x in y.into_iter() { @@ -138,7 +139,7 @@ declare_clippy_lint! { /// } /// ``` /// can be rewritten to - /// ```rust + /// ```no_run /// # let y = vec![1]; /// for x in y { /// // .. @@ -217,7 +218,7 @@ declare_clippy_lint! { /// declutters the code and may be faster in some instances. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} /// let mut i = 0; @@ -228,7 +229,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} /// for (i, item) in v.iter().enumerate() { bar(i, *item); } @@ -339,7 +340,7 @@ declare_clippy_lint! { /// code. /// /// ### Example - /// ```rust + /// ```no_run /// loop { /// ..; /// break; @@ -362,7 +363,7 @@ declare_clippy_lint! { /// False positive when mutation is followed by a `break`, but the `break` is not immediately /// after the mutation: /// - /// ```rust + /// ```no_run /// let mut x = 5; /// for _ in 0..x { /// x += 1; // x is a range bound that is mutated @@ -374,7 +375,7 @@ declare_clippy_lint! { /// False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072)) /// /// ### Example - /// ```rust + /// ```no_run /// let mut foo = 42; /// for i in 0..foo { /// foo -= 1; @@ -402,7 +403,7 @@ declare_clippy_lint! { /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger. /// /// ### Example - /// ```rust + /// ```no_run /// let i = 0; /// while i > 10 { /// println!("let me loop forever!"); @@ -425,7 +426,7 @@ declare_clippy_lint! { /// have better performance. /// /// ### Example - /// ```rust + /// ```no_run /// let item1 = 2; /// let item2 = 3; /// let mut vec: Vec<u8> = Vec::new(); @@ -438,7 +439,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let item1 = 2; /// let item2 = 3; /// let mut vec: Vec<u8> = vec![item1; 20]; @@ -459,7 +460,7 @@ declare_clippy_lint! { /// single element. /// /// ### Example - /// ```rust + /// ```no_run /// let item1 = 2; /// for item in &[item1] { /// println!("{}", item); @@ -467,7 +468,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let item1 = 2; /// let item = &item1; /// println!("{}", item); @@ -489,7 +490,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// let x = vec![Some(1), Some(2), Some(3)]; /// for n in x { /// if let Some(n) = n { @@ -498,7 +499,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![Some(1), Some(2), Some(3)]; /// for n in x.into_iter().flatten() { /// println!("{}", n); @@ -555,7 +556,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// fn example(arr: Vec<i32>) -> Option<i32> { /// for el in arr { /// if el == 1 { @@ -566,7 +567,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn example(arr: Vec<i32>) -> Option<i32> { /// arr.into_iter().find(|&el| el == 1) /// } @@ -579,6 +580,33 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for uses of the `enumerate` method where the index is unused (`_`) + /// + /// ### Why is this bad? + /// The index from `.enumerate()` is immediately dropped. + /// + /// ### Example + /// ```rust + /// let v = vec![1, 2, 3, 4]; + /// for (_, x) in v.iter().enumerate() { + /// println!("{x}"); + /// } + /// ``` + /// Use instead: + /// ```rust + /// let v = vec![1, 2, 3, 4]; + /// for x in v.iter() { + /// println!("{x}"); + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub UNUSED_ENUMERATE_INDEX, + style, + "using `.enumerate()` and immediately dropping the index" +} + +declare_clippy_lint! { + /// ### What it does /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element /// in the body as a separate operation. /// @@ -587,7 +615,7 @@ declare_clippy_lint! { /// pattern matching on the return value of `Vec::pop()`. /// /// ### Example - /// ```rust + /// ```no_run /// let mut numbers = vec![1, 2, 3, 4, 5]; /// while !numbers.is_empty() { /// let number = numbers.pop().unwrap(); @@ -595,7 +623,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut numbers = vec![1, 2, 3, 4, 5]; /// while let Some(number) = numbers.pop() { /// // use `number` @@ -619,6 +647,7 @@ impl Loops { } } } + impl_lint_pass!(Loops => [ MANUAL_MEMCPY, MANUAL_FLATTEN, @@ -638,7 +667,8 @@ impl_lint_pass!(Loops => [ SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, MANUAL_FIND, - MANUAL_WHILE_LET_SOME + MANUAL_WHILE_LET_SOME, + UNUSED_ENUMERATE_INDEX, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -717,6 +747,7 @@ impl Loops { same_item_push::check(cx, pat, arg, body, expr); manual_flatten::check(cx, pat, arg, body, span); manual_find::check(cx, pat, arg, body, span, expr); + unused_enumerate_index::check(cx, pat, arg, body); } fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index b83d148b5f2..2c12d9582d6 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 3d8a4cd948a..cc054cb4669 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -271,9 +271,9 @@ fn never_loop_expr<'tcx>( NeverLoopResult::Normal } }); - if let NeverLoopResult::Diverging = result && - let Some(macro_call) = root_macro_call_first_node(cx, expr) && - let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) + if let NeverLoopResult::Diverging = result + && let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) { // We return MayContinueMainLoop here because we treat `todo!()` // as potentially containing any code, including a continue of the main loop. diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs new file mode 100644 index 00000000000..62a2ab1ccb4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs @@ -0,0 +1,62 @@ +use super::UNUSED_ENUMERATE_INDEX; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::{pat_is_wild, sugg}; +use rustc_hir::def::DefKind; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +/// Checks for the `UNUSED_ENUMERATE_INDEX` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { + let PatKind::Tuple(tuple, _) = pat.kind else { + return; + }; + + let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind else { + return; + }; + + let ty = cx.typeck_results().expr_ty(arg); + + if !pat_is_wild(cx, &tuple[0].kind, body) { + return; + } + + let name = match *ty.kind() { + ty::Adt(base, _substs) => cx.tcx.def_path_str(base.did()), + _ => return, + }; + + if name != "std::iter::Enumerate" && name != "core::iter::Enumerate" { + return; + } + + let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) else { + return; + }; + + let call_name = cx.tcx.def_path_str(call_id); + + if call_name != "std::iter::Iterator::enumerate" && call_name != "core::iter::Iterator::enumerate" { + return; + } + + span_lint_and_then( + cx, + UNUSED_ENUMERATE_INDEX, + arg.span, + "you seem to use `.enumerate()` and immediately discard the index", + |diag| { + let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter"); + multispan_sugg( + diag, + "remove the `.enumerate()` call", + vec![ + (pat.span, snippet(cx, tuple[1].span, "..").into_owned()), + (arg.span, base_iter.to_string()), + ], + ); + }, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index 45ea5aab4c2..9a3da975f83 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -16,14 +16,14 @@ declare_clippy_lint! { /// `assert!` is simpler than `if`-then-`panic!`. /// /// ### Example - /// ```rust + /// ```no_run /// let sad_people: Vec<&str> = vec![]; /// if !sad_people.is_empty() { /// panic!("there are sad people: {:?}", sad_people); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let sad_people: Vec<&str> = vec![]; /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` @@ -64,7 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); - // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block + // we show to the user the suggestion without the comments, but when applying the fix, include the + // comments in the block span_lint_and_then( cx, MANUAL_ASSERT, @@ -77,16 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { expr.span.shrink_to_lo(), "add comments back", comments, - applicability + applicability, ); } - diag.span_suggestion( - expr.span, - "try instead", - sugg, - applicability - ); - } + diag.span_suggestion(expr.span, "try instead", sugg, applicability); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index a75c76d6fe0..998de38a995 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, + Block, Body, Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -20,13 +20,13 @@ declare_clippy_lint! { /// It's more idiomatic to use the dedicated syntax. /// /// ### Example - /// ```rust + /// ```no_run /// use std::future::Future; /// /// fn foo() -> impl Future<Output = i32> { async { 42 } } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// async fn foo() -> i32 { 42 } /// ``` #[clippy::version = "1.45.0"] diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 552c57d5e02..cd614c8951c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -20,11 +20,11 @@ declare_clippy_lint! { /// Can be written as the shorter `T::BITS`. /// /// ### Example - /// ```rust + /// ```no_run /// std::mem::size_of::<usize>() * 8; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// usize::BITS as usize; /// ``` #[clippy::version = "1.60.0"] diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index e75666e61f5..09c90e38e11 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; @@ -38,7 +38,7 @@ declare_clippy_lint! { /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613). /// /// ### Examples - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// if input > max { /// max @@ -50,13 +50,13 @@ declare_clippy_lint! { /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// input.max(min).min(max) /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// match input { /// x if x > max => max, @@ -66,14 +66,14 @@ declare_clippy_lint! { /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// let mut x = input; /// if x < min { x = min; } /// if x > max { x = max; } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// input.clamp(min, max) /// # ; @@ -207,7 +207,7 @@ impl TypeClampability { /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// if input < min { @@ -225,11 +225,11 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx then, r#else: Some(else_if), }) = If::hir(expr) - && let Some(If { - cond: else_if_cond, - then: else_if_then, - r#else: Some(else_body), - }) = If::hir(peel_blocks(else_if)) + && let Some(If { + cond: else_if_cond, + then: else_if_then, + r#else: Some(else_body), + }) = If::hir(peel_blocks(else_if)) { let params = is_clamp_meta_pattern( cx, @@ -256,7 +256,7 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min_value, max_value) = (0, -3, 12); /// /// input.max(min_value).min(max_value) @@ -275,7 +275,12 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O _ => return None, }; Some(ClampSuggestion { - params: InputMinMax { input, min, max, is_float }, + params: InputMinMax { + input, + min, + max, + is_float, + }, span: expr.span, make_assignment: None, hir_with_ignore_attr: None, @@ -287,7 +292,7 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min_value, max_value) = (0, -3, 12); /// # use std::cmp::{max, min}; /// min(max(input, min_value), max_value) @@ -346,11 +351,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) ("max", "min") => (inner_arg, outer_arg), _ => return None, } - } + }, _ => return None, }; Some(ClampSuggestion { - params: InputMinMax { input, min, max, is_float }, + params: InputMinMax { + input, + min, + max, + is_float, + }, span, make_assignment: None, hir_with_ignore_attr: None, @@ -369,7 +379,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// match input { @@ -384,7 +394,8 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt // Find possible min/max branches let minmax_values = |a: &'tcx Arm<'tcx>| { if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind - && let Some(Guard::If(e)) = a.guard { + && let Some(Guard::If(e)) = a.guard + { Some((e, var_hir_id, a.body)) } else { None @@ -428,7 +439,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// let mut x = input; @@ -441,18 +452,20 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> .filter_map(|(maybe_set_first, maybe_set_second)| { if let StmtKind::Expr(first_expr) = *maybe_set_first && let StmtKind::Expr(second_expr) = *maybe_set_second - && let Some(If { cond: first_cond, then: first_then, r#else: None }) = If::hir(first_expr) - && let Some(If { cond: second_cond, then: second_then, r#else: None }) = If::hir(second_expr) - && let ExprKind::Assign( - maybe_input_first_path, - maybe_min_max_first, - _ - ) = peel_blocks_with_stmt(first_then).kind - && let ExprKind::Assign( - maybe_input_second_path, - maybe_min_max_second, - _ - ) = peel_blocks_with_stmt(second_then).kind + && let Some(If { + cond: first_cond, + then: first_then, + r#else: None, + }) = If::hir(first_expr) + && let Some(If { + cond: second_cond, + then: second_then, + r#else: None, + }) = If::hir(second_expr) + && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = + peel_blocks_with_stmt(first_then).kind + && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) = + peel_blocks_with_stmt(second_then).kind && eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path) && let Some(first_bin) = BinaryOp::new(first_cond) && let Some(second_bin) = BinaryOp::new(second_cond) @@ -462,7 +475,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> &second_bin, maybe_min_max_first, maybe_min_max_second, - None + None, ) { Some(ClampSuggestion { @@ -485,7 +498,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (mut input, min, max) = (0, -3, 12); /// /// if input < min { @@ -505,16 +518,9 @@ fn is_if_elseif_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> then: else_if_then, r#else: None, }) = If::hir(peel_blocks(else_if)) - && let ExprKind::Assign( - maybe_input_first_path, - maybe_min_max_first, - _ - ) = peel_blocks_with_stmt(then).kind - && let ExprKind::Assign( - maybe_input_second_path, - maybe_min_max_second, - _ - ) = peel_blocks_with_stmt(else_if_then).kind + && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = peel_blocks_with_stmt(then).kind + && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) = + peel_blocks_with_stmt(else_if_then).kind { let params = is_clamp_meta_pattern( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index f0994695565..0c4101ceb6b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -17,12 +17,12 @@ declare_clippy_lint! { /// The method `is_infinite` is shorter and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x == f32::INFINITY || x == f32::NEG_INFINITY {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x.is_infinite() {} /// ``` @@ -40,13 +40,13 @@ declare_clippy_lint! { /// The method `is_finite` is shorter and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x != f32::INFINITY && x != f32::NEG_INFINITY {} /// if x.abs() < f32::INFINITY {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x.is_finite() {} /// if x.is_finite() {} @@ -114,46 +114,40 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { _ => return, }; - span_lint_and_then( - cx, - variant.lint(), - expr.span, - variant.msg(), - |diag| { - match variant { - Variant::ManualIsInfinite => { - diag.span_suggestion( - expr.span, - "use the dedicated method instead", - format!("{local_snippet}.is_infinite()"), - Applicability::MachineApplicable, - ); - }, - Variant::ManualIsFinite => { - // TODO: There's probably some better way to do this, i.e., create - // multiple suggestions with notes between each of them - diag.span_suggestion_verbose( - expr.span, - "use the dedicated method instead", - format!("{local_snippet}.is_finite()"), - Applicability::MaybeIncorrect, - ) - .span_suggestion_verbose( - expr.span, - "this will alter how it handles NaN; if that is a problem, use instead", - format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), - Applicability::MaybeIncorrect, - ) - .span_suggestion_verbose( - expr.span, - "or, for conciseness", - format!("!{local_snippet}.is_infinite()"), - Applicability::MaybeIncorrect, - ); - }, - } - }, - ); + span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| { + match variant { + Variant::ManualIsInfinite => { + diag.span_suggestion( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_infinite()"), + Applicability::MachineApplicable, + ); + }, + Variant::ManualIsFinite => { + // TODO: There's probably some better way to do this, i.e., create + // multiple suggestions with notes between each of them + diag.span_suggestion_verbose( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_finite()"), + Applicability::MaybeIncorrect, + ) + .span_suggestion_verbose( + expr.span, + "this will alter how it handles NaN; if that is a problem, use instead", + format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), + Applicability::MaybeIncorrect, + ) + .span_suggestion_verbose( + expr.span, + "or, for conciseness", + format!("!{local_snippet}.is_infinite()"), + Applicability::MaybeIncorrect, + ); + }, + } + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index ea911335450..472b4eb9006 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; @@ -19,7 +19,7 @@ declare_clippy_lint! { /// It is more concise to use the `hash_one` method. /// /// ### Example - /// ```rust + /// ```no_run /// use std::hash::{BuildHasher, Hash, Hasher}; /// use std::collections::hash_map::RandomState; /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// let hash = hasher.finish(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::hash::BuildHasher; /// use std::collections::hash_map::RandomState; /// @@ -117,12 +117,11 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, // `needless_borrows_for_generic_args` will take care of // removing the `&` when it isn't needed - format!("{build_hasher}.hash_one(&{hashed_value})") - ) + format!("{build_hasher}.hash_one(&{hashed_value})"), + ), ], Applicability::MachineApplicable, ); - } }, ); diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 9da20a28fba..468f4170732 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::root_macro_call; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, in_constant}; use rustc_ast::ast::RangeLimits; @@ -23,7 +23,7 @@ declare_clippy_lint! { /// clear that it's not a specific subset of characters, but all /// ASCII (lowercase|uppercase|digit|hexdigit) characters. /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// assert!(matches!('x', 'a'..='z')); /// assert!(matches!(b'X', b'A'..=b'Z')); @@ -37,7 +37,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// assert!('x'.is_ascii_lowercase()); /// assert!(b'X'.is_ascii_uppercase()); @@ -98,15 +98,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { } if let Some(macro_call) = root_macro_call(expr.span) - && is_matches_macro(cx, macro_call.def_id) { + && is_matches_macro(cx, macro_call.def_id) + { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); check_is_ascii(cx, macro_call.span, recv, &range); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind && path.ident.name == sym!(contains) - && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed }) - = higher::Range::hir(receiver) { + && let Some(higher::Range { + start: Some(start), + end: Some(end), + limits: RangeLimits::Closed, + }) = higher::Range::hir(receiver) + { let range = check_range(start, end); if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind { check_is_ascii(cx, expr.span, e, &range); @@ -168,7 +173,8 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { if let ExprKind::Lit(start_lit) = &start.kind - && let ExprKind::Lit(end_lit) = &end.kind { + && let ExprKind::Lit(end_lit) = &end.kind + { match (&start_lit.node, &end_lit.node) { (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar, (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar, diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 86bbdb4ea19..170a040d4ae 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -1,10 +1,12 @@ use crate::question_mark::{QuestionMark, QUESTION_MARK}; +use clippy_config::msrvs; +use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Descend, Visitable}; -use clippy_utils::{is_lint_allowed, msrvs, pat_and_expr_can_be_question_mark, peel_blocks}; +use clippy_utils::{is_lint_allowed, pat_and_expr_can_be_question_mark, peel_blocks}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -14,7 +16,6 @@ use rustc_middle::lint::in_external_macro; use rustc_session::declare_tool_lint; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use serde::Deserialize; use std::ops::ControlFlow; use std::slice; @@ -30,14 +31,14 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # let w = Some(0); /// let v = if let Some(v) = w { v } else { return }; /// ``` /// /// Could be written: /// - /// ```rust + /// ```no_run /// # fn main () { /// # let w = Some(0); /// let Some(v) = w else { return }; @@ -55,21 +56,20 @@ impl<'tcx> QuestionMark { return; } - if let StmtKind::Local(local) = stmt.kind && - let Some(init) = local.init && - local.els.is_none() && - local.ty.is_none() && - init.span.eq_ctxt(stmt.span) && - let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) + if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && local.els.is_none() + && local.ty.is_none() + && init.span.eq_ctxt(stmt.span) + && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => { - if - let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) && - let Some(if_else) = if_else && - expr_diverges(cx, if_else) && - let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) && - (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) + if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) + && let Some(if_else) = if_else + && expr_diverges(cx, if_else) + && let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) + && (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) { emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else); } @@ -95,7 +95,9 @@ impl<'tcx> QuestionMark { .iter() .enumerate() .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types)); - let Some((idx, diverging_arm)) = diverging_arm_opt else { return; }; + let Some((idx, diverging_arm)) = diverging_arm_opt else { + return; + }; // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement. // However, if it arrives in second position, its pattern may cover some cases already covered // by the diverging one. @@ -105,7 +107,7 @@ impl<'tcx> QuestionMark { } let pat_arm = &arms[1 - idx]; let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else { - return + return; }; emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body); @@ -216,8 +218,8 @@ fn replace_in_pattern( let fields = fields .iter() .map(|fld| { - if let PatKind::Binding(_, _, name, None) = fld.pat.kind && - let Some(pat_to_put) = ident_map.get(&name.name) + if let PatKind::Binding(_, _, name, None) = fld.pat.kind + && let Some(pat_to_put) = ident_map.get(&name.name) { let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app); let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app); @@ -463,8 +465,8 @@ fn expr_simple_identity_map<'a, 'hir>( } let mut ident_map = FxHashMap::default(); for (sub_pat, path) in sub_pats.iter().zip(paths.iter()) { - if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind && - let [path_seg] = path.segments + if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind + && let [path_seg] = path.segments { let ident = path_seg.ident; if !pat_bindings.remove(&ident) { @@ -477,10 +479,3 @@ fn expr_simple_identity_map<'a, 'hir>( } Some(ident_map) } - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)] -pub enum MatchLintBehaviour { - AllTypes, - WellKnownTypes, - Never, -} diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs index c292bbe4e93..23f47c86fcc 100644 --- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -19,11 +19,11 @@ declare_clippy_lint! { /// an extra memory allocation. /// /// ### Example - /// ```rust + /// ```no_run /// let s: &str = &std::path::MAIN_SEPARATOR.to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let s: &str = std::path::MAIN_SEPARATOR_STR; /// ``` #[clippy::version = "1.70.0"] @@ -47,27 +47,27 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); impl LateLintPass<'_> for ManualMainSeparatorStr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && - let (target, _) = peel_hir_expr_refs(expr) && - is_trait_method(cx, target, sym::ToString) && - let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && - path.ident.name == sym::to_string && - let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && - let Res::Def(DefKind::Const, receiver_def_id) = path.res && - match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && - let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && - ty.is_str() - { - span_lint_and_sugg( - cx, - MANUAL_MAIN_SEPARATOR_STR, - expr.span, - "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", - "replace with", - "std::path::MAIN_SEPARATOR_STR".to_owned(), - Applicability::MachineApplicable, - ); - } + if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) + && let (target, _) = peel_hir_expr_refs(expr) + && is_trait_method(cx, target, sym::ToString) + && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind + && path.ident.name == sym::to_string + && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind + && let Res::Def(DefKind::Const, receiver_def_id) = path.res + && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) + && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() + && ty.is_str() + { + span_lint_and_sugg( + cx, + MANUAL_MAIN_SEPARATOR_STR, + expr.span, + "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", + "replace with", + "std::path::MAIN_SEPARATOR_STR".to_owned(), + Applicability::MachineApplicable, + ); + } } extract_msrv_attr!(LateContext); diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index c12727c4a28..fc8f2363001 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::attr; @@ -22,7 +22,7 @@ declare_clippy_lint! { /// and allows possible optimizations when applied to enums. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { /// pub a: i32, /// pub b: i32, @@ -39,7 +39,7 @@ declare_clippy_lint! { /// struct T(pub i32, pub i32, ()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// struct S { /// pub a: i32, @@ -138,7 +138,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { ); } diag.span_help(field.span, "remove this field"); - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index 90557b55560..d24bfe18224 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// in order to support negative numbers. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 6; /// let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 6; /// let foo = matches!(x, 1..=10); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index 0e89ca132ef..bc8372fbd41 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::{in_constant, path_to_local}; use rustc_errors::Applicability; @@ -18,12 +18,12 @@ declare_clippy_lint! { /// It's simpler and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// let x: i32 = 24; /// let rem = ((x % 4) + 4) % 4; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: i32 = 24; /// let rem = x.rem_euclid(4); /// ``` @@ -76,30 +76,31 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { // Also ensures the const is nonzero since zero can't be a divisor && const1 == const2 && const2 == const3 && let Some(hir_id) = path_to_local(expr3) - && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) { - // Apply only to params or locals with annotated types - match cx.tcx.hir().find_parent(hir_id) { - Some(Node::Param(..)) => (), - Some(Node::Local(local)) => { - let Some(ty) = local.ty else { return }; - if matches!(ty.kind, TyKind::Infer) { - return; - } + && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) + { + // Apply only to params or locals with annotated types + match cx.tcx.hir().find_parent(hir_id) { + Some(Node::Param(..)) => (), + Some(Node::Local(local)) => { + let Some(ty) = local.ty else { return }; + if matches!(ty.kind, TyKind::Infer) { + return; } - _ => return, - }; + }, + _ => return, + }; - let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; - span_lint_and_sugg( - cx, - MANUAL_REM_EUCLID, - expr.span, - "manual `rem_euclid` implementation", - "consider using", - format!("{rem_of}.rem_euclid({const1})"), - app, - ); + let mut app = Applicability::MachineApplicable; + let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; + span_lint_and_sugg( + cx, + MANUAL_REM_EUCLID, + expr.span, + "manual `rem_euclid` implementation", + "consider using", + format!("{rem_of}.rem_euclid({const1})"), + app, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index f923413f434..2f8682d0418 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; @@ -35,13 +35,13 @@ declare_clippy_lint! { /// ### Why is this bad? /// `.retain()` is simpler and avoids needless allocation. /// ### Example - /// ```rust + /// ```no_run /// let mut vec = vec![0, 1, 2]; /// vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); /// vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = vec![0, 1, 2]; /// vec.retain(|x| x % 2 == 0); /// ``` @@ -97,7 +97,8 @@ fn check_into_iter( && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn() && match_acceptable_type(cx, left_expr, msrv) - && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) + { suggest(cx, parent_expr, left_expr, target_expr); } } @@ -120,7 +121,8 @@ fn check_iter( && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) && match_acceptable_def_path(cx, iter_expr_def_id) && match_acceptable_type(cx, left_expr, msrv) - && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) + { suggest(cx, parent_expr, left_expr, filter_expr); } } @@ -144,33 +146,35 @@ fn check_to_owned( && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() && is_type_lang_item(cx, ty, hir::LangItem::String) - && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) + { suggest(cx, parent_expr, left_expr, filter_expr); } } fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) { if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind - && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = closure.kind && let filter_body = cx.tcx.hir().body(body) && let [filter_params] = filter_body.params && let Some(sugg) = match filter_params.pat.kind { - hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) - }, - hir::PatKind::Tuple([key_pat, value_pat], _) => { - make_sugg(cx, key_pat, value_pat, left_expr, filter_body) - }, - hir::PatKind::Ref(pat, _) => { - match pat.kind { - hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) - }, - _ => None - } + hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!( + "{}.retain(|{filter_param_ident}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, filter_body.value.span, "..") + )), + hir::PatKind::Tuple([key_pat, value_pat], _) => make_sugg(cx, key_pat, value_pat, left_expr, filter_body), + hir::PatKind::Ref(pat, _) => match pat.kind { + hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!( + "{}.retain(|{filter_param_ident}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, filter_body.value.span, "..") + )), + _ => None, }, - _ => None - } { + _ => None, + } + { span_lint_and_sugg( cx, MANUAL_RETAIN, @@ -178,7 +182,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E "this expression can be written more simply using `.retain()`", "consider calling `.retain()` instead", sugg, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs index f97600b53e4..3b97d165998 100644 --- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs +++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// * Less turbofishing /// /// ### Example - /// ```rust + /// ```no_run /// # let data : &[i32] = &[1, 2, 3]; /// let newlen = data.len() * std::mem::size_of::<i32>(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let data : &[i32] = &[1, 2, 3]; /// let newlen = std::mem::size_of_val(data); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index c20d7959fc4..f8afae0e1f5 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -19,12 +19,12 @@ declare_clippy_lint! { /// be confusing. /// /// ### Example - /// ```rust + /// ```no_run /// let a = "".to_string(); /// let b: String = "".into(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = String::new(); /// let b = String::new(); /// ``` @@ -65,9 +65,9 @@ impl LateLintPass<'_> for ManualStringNew { /// Checks if an expression's kind corresponds to an empty &str. fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { - if let ExprKind::Lit(lit) = expr_kind && - let LitKind::Str(value, _) = lit.node && - value == symbol::kw::Empty + if let ExprKind::Lit(lit) = expr_kind + && let LitKind::Str(value, _) = lit.node + && value == symbol::kw::Empty { return true; } @@ -110,23 +110,22 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_ if let ExprKind::Path(qpath) = &func.kind { if let QPath::TypeRelative(_, _) = qpath { // String::from(...) or String::try_from(...) - if let QPath::TypeRelative(ty, path_seg) = qpath && - [sym::from, sym::try_from].contains(&path_seg.ident.name) && - let TyKind::Path(qpath) = &ty.kind && - let QPath::Resolved(_, path) = qpath && - let [path_seg] = path.segments && - path_seg.ident.name == sym::String && - is_expr_kind_empty_str(arg_kind) + if let QPath::TypeRelative(ty, path_seg) = qpath + && [sym::from, sym::try_from].contains(&path_seg.ident.name) + && let TyKind::Path(qpath) = &ty.kind + && let QPath::Resolved(_, path) = qpath + && let [path_seg] = path.segments + && path_seg.ident.name == sym::String + && is_expr_kind_empty_str(arg_kind) { warn_then_suggest(cx, span); } } else if let QPath::Resolved(_, path) = qpath { // From::from(...) or TryFrom::try_from(...) - if let [path_seg1, path_seg2] = path.segments && - is_expr_kind_empty_str(arg_kind) && ( - (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) || - (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from) - ) + if let [path_seg1, path_seg2] = path.segments + && is_expr_kind_empty_str(arg_kind) + && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) + || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)) { warn_then_suggest(cx, span); } diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 201bb56efcd..9a9e6af5084 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; use clippy_utils::{eq_expr_value, higher, match_def_path, paths}; @@ -27,14 +27,14 @@ declare_clippy_lint! { /// used by `str::{starts,ends}_with` and in the slicing. /// /// ### Example - /// ```rust + /// ```no_run /// let s = "hello, world!"; /// if s.starts_with("hello, ") { /// assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let s = "hello, world!"; /// if let Some(end) = s.strip_prefix("hello, ") { /// assert_eq!(end.to_uppercase(), "WORLD!"); diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index f0a0f482af2..817d072b9b3 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -8,8 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -21,7 +20,7 @@ declare_clippy_lint! { /// an if let statement /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff() -> Option<String> { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -33,7 +32,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn do_stuff() -> Option<String> { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -63,7 +62,7 @@ declare_clippy_lint! { /// an if let statement /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff() -> Result<String, String> { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -75,7 +74,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn do_stuff() -> Result<String, String> { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) } /// # fn format_msg(foo: String) -> String { String::new() } diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs index e0181a4757c..cdb51c33aaf 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs @@ -99,12 +99,20 @@ pub(super) fn check_match<'tcx>( ) { let ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, ty, sym::Option) - && let [first_arm, second_arm] = arms - && first_arm.guard.is_none() - && second_arm.guard.is_none() - { - check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body); - } + && let [first_arm, second_arm] = arms + && first_arm.guard.is_none() + && second_arm.guard.is_none() + { + check( + cx, + expr, + scrutinee, + first_arm.pat, + first_arm.body, + Some(second_arm.pat), + second_arm.body, + ); + } } pub(super) fn check_if_let<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index b5ab94b3a2f..dea46d4d360 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -24,7 +24,7 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; @@ -48,7 +48,7 @@ declare_clippy_lint! { /// Just readability – `if let` nests less than a `match`. /// /// ### Example - /// ```rust + /// ```no_run /// # fn bar(stool: &str) {} /// # let x = Some("abc"); /// match x { @@ -58,7 +58,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn bar(stool: &str) {} /// # let x = Some("abc"); /// if let Some(ref foo) = x { @@ -85,7 +85,7 @@ declare_clippy_lint! { /// ### Example /// Using `match`: /// - /// ```rust + /// ```no_run /// # fn bar(foo: &usize) {} /// # let other_ref: usize = 1; /// # let x: Option<&usize> = Some(&1); @@ -97,7 +97,7 @@ declare_clippy_lint! { /// /// Using `if let` with `else`: /// - /// ```rust + /// ```no_run /// # fn bar(foo: &usize) {} /// # let other_ref: usize = 1; /// # let x: Option<&usize> = Some(&1); @@ -155,7 +155,7 @@ declare_clippy_lint! { /// It makes the code less readable. /// /// ### Example - /// ```rust + /// ```no_run /// # fn foo() {} /// # fn bar() {} /// let condition: bool = true; @@ -165,7 +165,7 @@ declare_clippy_lint! { /// } /// ``` /// Use if/else instead: - /// ```rust + /// ```no_run /// # fn foo() {} /// # fn bar() {} /// let condition: bool = true; @@ -190,7 +190,7 @@ declare_clippy_lint! { /// less obvious. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 5; /// match x { /// 1..=10 => println!("1 ... 10"), @@ -214,7 +214,7 @@ declare_clippy_lint! { /// catching all exceptions in java with `catch(Exception)` /// /// ### Example - /// ```rust + /// ```no_run /// let x: Result<i32, &str> = Ok(3); /// match x { /// Ok(_) => println!("ok"), @@ -236,7 +236,7 @@ declare_clippy_lint! { /// Using `as_ref()` or `as_mut()` instead is shorter. /// /// ### Example - /// ```rust + /// ```no_run /// let x: Option<()> = None; /// /// let r: Option<&()> = match x { @@ -246,7 +246,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x: Option<()> = None; /// /// let r: Option<&()> = x.as_ref(); @@ -269,7 +269,7 @@ declare_clippy_lint! { /// variants, and also may not use correct path to enum if it's not present in the current scope. /// /// ### Example - /// ```rust + /// ```no_run /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { @@ -279,7 +279,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { @@ -305,7 +305,7 @@ declare_clippy_lint! { /// if it's not present in the current scope. /// /// ### Example - /// ```rust + /// ```no_run /// # enum Foo { A, B, C } /// # let x = Foo::B; /// match x { @@ -316,7 +316,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # enum Foo { A, B, C } /// # let x = Foo::B; /// match x { @@ -340,7 +340,7 @@ declare_clippy_lint! { /// It makes the code less readable, especially to spot wildcard pattern use in match arm. /// /// ### Example - /// ```rust + /// ```no_run /// # let s = "foo"; /// match s { /// "a" => {}, @@ -349,7 +349,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = "foo"; /// match s { /// "a" => {}, @@ -371,7 +371,7 @@ declare_clippy_lint! { /// Just readability – `let` doesn't nest, whereas a `match` does. /// /// ### Example - /// ```rust + /// ```no_run /// enum Wrapper { /// Data(i32), /// } @@ -384,7 +384,7 @@ declare_clippy_lint! { /// ``` /// /// The correct use would be: - /// ```rust + /// ```no_run /// enum Wrapper { /// Data(i32), /// } @@ -410,7 +410,7 @@ declare_clippy_lint! { /// is actually binding temporary value, bringing a 'dropped while borrowed' error. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// match (a, b) { @@ -421,7 +421,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// let (c, d) = (a, b); @@ -441,7 +441,7 @@ declare_clippy_lint! { /// matching all enum variants explicitly. /// /// ### Example - /// ```rust + /// ```no_run /// # struct A { a: i32 } /// let a = A { a: 5 }; /// @@ -452,7 +452,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct A { a: i32 } /// # let a = A { a: 5 }; /// match a { @@ -484,7 +484,7 @@ declare_clippy_lint! { /// drop order. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if let Ok(_) = Ok::<i32, i32>(42) {} @@ -503,7 +503,7 @@ declare_clippy_lint! { /// /// The more idiomatic use would be: /// - /// ```rust + /// ```no_run /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if Ok::<i32, i32>(42).is_ok() {} @@ -535,7 +535,7 @@ declare_clippy_lint! { /// `cfg` attributes that remove an arm evaluating to `false`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(5); /// /// let a = match x { @@ -551,7 +551,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(5); /// let a = matches!(x, Some(0)); /// ``` @@ -664,7 +664,7 @@ declare_clippy_lint! { /// It is unnecessarily verbose and complex. /// /// ### Example - /// ```rust + /// ```no_run /// fn func(opt: Option<Result<u64, String>>) { /// let n = match opt { /// Some(n) => match n { @@ -676,7 +676,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn func(opt: Option<Result<u64, String>>) { /// let n = match opt { /// Some(Ok(n)) => n, @@ -698,7 +698,7 @@ declare_clippy_lint! { /// Concise code helps focusing on behavior instead of boilerplate. /// /// ### Example - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// match foo { /// Some(v) => v, @@ -707,7 +707,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// foo.unwrap_or(1); /// ``` @@ -761,7 +761,7 @@ declare_clippy_lint! { /// The arm is unreachable, which is likely a mistake /// /// ### Example - /// ```rust + /// ```no_run /// # let text = "Foo"; /// match &*text.to_ascii_lowercase() { /// "foo" => {}, @@ -770,7 +770,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let text = "Foo"; /// match &*text.to_ascii_lowercase() { /// "foo" => {}, @@ -823,7 +823,7 @@ declare_clippy_lint! { /// println!("All done!"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # struct State {} /// # impl State { @@ -861,7 +861,7 @@ declare_clippy_lint! { /// always return), it is more clear to write `return Err(x)`. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(fail: bool) -> Result<i32, String> { /// if fail { /// Err("failed")?; @@ -871,7 +871,7 @@ declare_clippy_lint! { /// ``` /// Could be written: /// - /// ```rust + /// ```no_run /// fn foo(fail: bool) -> Result<i32, String> { /// if fail { /// return Err("failed".into()); @@ -893,14 +893,14 @@ declare_clippy_lint! { /// Using the `map` method is clearer and more concise. /// /// ### Example - /// ```rust + /// ```no_run /// match Some(0) { /// Some(x) => Some(x + 1), /// None => None, /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(0).map(|x| x + 1); /// ``` #[clippy::version = "1.52.0"] @@ -917,7 +917,7 @@ declare_clippy_lint! { /// Using the `filter` method is clearer and more concise. /// /// ### Example - /// ```rust + /// ```no_run /// match Some(0) { /// Some(x) => if x % 2 == 0 { /// Some(x) @@ -928,7 +928,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(0).filter(|&x| x % 2 == 0); /// ``` #[clippy::version = "1.66.0"] diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 0efeeacc9d9..4a44d596a46 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -27,8 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { arm, Arm { pat: Pat { - kind: PatKind::Wild, - .. + kind: PatKind::Wild, .. }, .. }, @@ -42,14 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => arm.pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - if_expr.span, - pat_span, - &binding, - arm.guard, - ); + emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard); } // `Some(x) if let Some(2) = x` else if let Guard::IfLet(let_expr) = guard @@ -60,14 +52,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => let_expr.pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - let_expr.span, - pat_span, - &binding, - None, - ); + emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None); } // `Some(x) if x == Some(2)` // `Some(x) if Some(2) == x` @@ -93,14 +78,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (ExprKind::AddrOf(..), None) | (_, Some(_)) => continue, _ => pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - if_expr.span, - pat_span, - &binding, - None, - ); + emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None); } } } @@ -116,7 +94,9 @@ fn get_pat_binding<'tcx>( guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>, ) -> Option<PatBindingInfo> { - if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) { + if let Some(local) = path_to_local(guard_expr) + && !is_local_used(cx, outer_arm.body, local) + { let mut span = None; let mut byref_ident = None; let mut multiple_bindings = false; @@ -223,10 +203,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..), ) }, - ExprKind::AddrOf(..) - | ExprKind::Array(..) - | ExprKind::Tup(..) - | ExprKind::Struct(..) => true, + ExprKind::AddrOf(..) | ExprKind::Array(..) | ExprKind::Tup(..) | ExprKind::Struct(..) => true, ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true, _ => false, } { diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 6b05c6bfffd..48efd023017 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -20,8 +20,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { if let Some(ff) = get_source_text(cx, span) && let Some(text) = ff.as_str() { - text.as_bytes().windows(2) - .any(|w| w == b"//" || w == b"/*") + text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") } else { false } @@ -51,7 +50,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: // block with 2+ statements or 1 expr and 1+ statement Some(els) } else { - // not a block or an emtpy block w/ comments, don't lint + // not a block or an empty block w/ comments, don't lint return; }; diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 8a921d4af16..760c8f59cec 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; @@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -25,14 +25,14 @@ declare_clippy_lint! { /// `None`. /// /// ### Example - /// ```rust + /// ```no_run /// use std::mem; /// /// let mut an_option = Some(0); /// let replaced = mem::replace(&mut an_option, None); /// ``` /// Is better expressed with: - /// ```rust + /// ```no_run /// let mut an_option = Some(0); /// let taken = an_option.take(); /// ``` @@ -53,7 +53,7 @@ declare_clippy_lint! { /// observed in the case of a panic. /// /// ### Example - /// ``` + /// ```no_run /// use std::mem; ///# fn may_panic(v: Vec<i32>) -> Vec<i32> { v } /// @@ -84,12 +84,12 @@ declare_clippy_lint! { /// take the current value and replace it with the default value of that type. /// /// ### Example - /// ```rust + /// ```no_run /// let mut text = String::from("foo"); /// let replaced = std::mem::replace(&mut text, String::default()); /// ``` /// Is better expressed with: - /// ```rust + /// ```no_run /// let mut text = String::from("foo"); /// let taken = std::mem::take(&mut text); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs index c5fc145b289..baafb7030aa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -24,8 +24,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability); if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) - && let Some((name, _, _, _, _)) = method_call(parent) - && name == "unwrap" { + && let Some((name, _, _, _, _)) = method_call(parent) + && name == "unwrap" + { span_lint_and_sugg( cx, BYTES_NTH, @@ -33,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes()[{n}]",), - applicability + applicability, ); } else { span_lint_and_sugg( @@ -42,8 +43,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E expr.span, &format!("called `.bytes().nth()` on a `{caller_type}`"), "try", - format!("{receiver}.as_bytes().get({n}).copied()"), - applicability + format!("{receiver}.as_bytes().get({n}).copied()"), + applicability, ); }; } diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index 4e6ec61f6a8..fcafa162236 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs index 3d82441c0e6..a8d4dd5e4f3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs @@ -1,6 +1,6 @@ use super::ERR_EXPECT; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 40e487bf650..a49970b5351 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs index 3fef53739fb..7818be81119 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs @@ -4,8 +4,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FILETYPE_IS_FILE; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index c9eaa185acc..5bb8c7a6b94 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -11,7 +11,7 @@ use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{sym, Ident, Symbol}; use std::borrow::Cow; @@ -159,7 +159,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome, OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk, OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"), - } + }, }) } else { None @@ -189,7 +189,8 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // scrutinee variant_span variant_ident else_ let (scrutinee, else_, variant_ident, variant_span) = match higher::IfLetOrMatch::parse(cx, map_body.value) { - // For `if let` we want to check that the variant matching arm references the local created by its pattern + // For `if let` we want to check that the variant matching arm references the local created by + // its pattern Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_))) if let Some((ident, span)) = expr_uses_local(pat, then) => { @@ -211,7 +212,10 @@ impl<'tcx> OffendingFilterExpr<'tcx> { && let Some(mac) = root_macro_call(else_.peel_blocks().span) && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable)) { - Some(CheckResult::PatternMatching { variant_span, variant_ident }) + Some(CheckResult::PatternMatching { + variant_span, + variant_ident, + }) } else { None } @@ -228,18 +232,20 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap()) // vs. // .filter_map(|x| effect(x)) - // + // // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) - && path.ident.name == sym!(is_some) - { - Some(Self::IsSome { receiver, side_effect_expr_span }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) - && path.ident.name == sym!(is_ok) - { - Some(Self::IsOk { receiver, side_effect_expr_span }) + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym!(is_some) { + Some(Self::IsSome { + receiver, + side_effect_expr_span, + }) + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym!(is_ok) { + Some(Self::IsOk { + receiver, + side_effect_expr_span, + }) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 33657254965..9950c442855 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & "use `filter` then `map` instead", format!( "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", - derefs="*".repeat(needed_derefs) + derefs = "*".repeat(needed_derefs) ), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs index 20878f1e4df..8291c373f37 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs @@ -3,8 +3,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FILTER_MAP_IDENTITY; diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs index 3f89e593148..f94fe221833 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::is_trait_method; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs index 8849a4f4942..651ea34f9d0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs @@ -3,8 +3,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FLAT_MAP_IDENTITY; diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs index 172c397fbc8..0a4a381b861 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs @@ -4,8 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::FLAT_MAP_OPTION; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs index 1f8863f8521..3e5162ef458 100644 --- a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs @@ -24,10 +24,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, m && let Some(mac) = root_macro_call_first_node(cx, value) && is_format_macro(cx, mac.def_id) { - span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| { - diag.span_help(map_span, "call `fold` instead") - .span_help(value.span.source_callsite(), "... and use the `write!` macro here") - .note("this can be written more efficiently by appending to a `String` directly"); - }); + span_lint_and_then( + cx, + FORMAT_COLLECT, + expr.span, + "use of `format!` to build up a string from an iterator", + |diag| { + diag.span_help(map_span, "call `fold` instead") + .span_help(value.span.source_callsite(), "... and use the `write!` macro here") + .note("this can be written more efficiently by appending to a `String` directly"); + }, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs index e7b4564c651..2e1dd3ec649 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Spanned; +use rustc_span::sym; use super::GET_FIRST; @@ -18,20 +20,34 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).instantiate_identity().is_slice(); + let identity = cx.tcx.type_of(impl_id).instantiate_identity(); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { - let mut app = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), - "try", - format!("{slice_name}.first()"), - app, - ); + if identity.is_slice() { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.first()"), + app, + ); + } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){ + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.front()"), + app, + ); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs index a8f090d1de1..afdcb3b6549 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs @@ -43,9 +43,9 @@ pub(super) fn check<'tcx>( // by not requiring an explicit reference let needs_ref = if let Some(parent) = get_parent_expr(cx, expr) && let hir::ExprKind::Unary(hir::UnOp::Deref, _) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::Index(..) = parent.kind + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Index(..) = parent.kind { if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { // if the user explicitly dereferences the result, we can adjust diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs index 23cc192c38e..ad4b6fa130e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs @@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::INSPECT_FOR_EACH; diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs index 8adf9e37059..bbd964c1099 100644 --- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{sym, Symbol}; use super::INTO_ITER_ON_REF; diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs index 120f3d5f42c..e963950960a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,9 +1,9 @@ //! Lint for `c.is_digit(10)` use super::IS_DIGIT_ASCII_RADIX; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index b44a2716dde..625325d4cf5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -3,9 +3,8 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; @@ -84,13 +83,3 @@ pub(super) fn check<'tcx>( } } } - -/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` -/// that is not locally used. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs index 99ea7f03df4..29e69b111de 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -51,7 +51,7 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> Some(0) } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) { Some(1) - } else { + } else { None } } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a49dd98db87..eac6df0545f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -60,9 +60,15 @@ pub(super) fn check<'tcx>( } if let Op::NeedlessMove(_, expr) = op { - let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ; - let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return }; - let mut delegate = MoveDelegate {used_move : HirIdSet::default()}; + let rustc_hir::ExprKind::Closure(closure) = expr.kind else { + return; + }; + let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { + return; + }; + let mut delegate = MoveDelegate { + used_move: HirIdSet::default(), + }; let infcx = cx.tcx.infer_ctxt().build(); ExprUseVisitor::new( @@ -77,7 +83,7 @@ pub(super) fn check<'tcx>( let mut to_be_discarded = false; p.pat.walk(|it| { - if delegate.used_move.contains(&it.hir_id){ + if delegate.used_move.contains(&it.hir_id) { to_be_discarded = true; return false; } @@ -87,8 +93,8 @@ pub(super) fn check<'tcx>( | PatKind::Ref(_, Mutability::Mut) => { to_be_discarded = true; false - } - _ => { true } + }, + _ => true, } }); @@ -99,46 +105,42 @@ pub(super) fn check<'tcx>( let (lint, msg, trailing_clone) = match op { Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), - Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"), + Op::LaterCloned | Op::FixClosure(_, _) => ( + ITER_OVEREAGER_CLONED, + "unnecessarily eager cloning of iterator items", + ".cloned()", + ), }; - span_lint_and_then( - cx, - lint, - expr.span, - msg, - |diag| { - match op { - Op::RmCloned | Op::LaterCloned => { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(mut snip) = snippet_opt(cx, method_span) { - snip.push_str(trailing_clone); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); - } - } - Op::FixClosure(name, predicate_expr) => { - if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { - let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { - predicate.replacen('|', "|&", 1) - } else { - format!("|&x| {predicate}(x)") - }; - let snip = format!(".{name}({new_closure}).cloned()" ); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); - } - } - Op::NeedlessMove(_, _) => { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(snip) = snippet_opt(cx, method_span) { - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); - } - } + span_lint_and_then(cx, lint, expr.span, msg, |diag| match op { + Op::RmCloned | Op::LaterCloned => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(mut snip) = snippet_opt(cx, method_span) { + snip.push_str(trailing_clone); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); } - } - ); + }, + Op::FixClosure(name, predicate_expr) => { + if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { + let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { + predicate.replacen('|', "|&", 1) + } else { + format!("|&x| {predicate}(x)") + }; + let snip = format!(".{name}({new_closure}).cloned()"); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); + } + }, + Op::NeedlessMove(_, _) => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(snip) = snippet_opt(cx, method_span) { + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); + } + }, + }); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index dabed0affcf..51145afda7f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; -use clippy_utils::msrvs::{Msrv, ITERATOR_TRY_FOLD}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if !in_external_macro(cx.sess(), fold_span) - && msrv.meets(ITERATOR_TRY_FOLD) + && msrv.meets(msrvs::ITERATOR_TRY_FOLD) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() && implements_trait(cx, init_ty, try_trait, &[]) @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( fold_span, "usage of `Iterator::fold` on a type that implements `Try`", "use `try_fold` instead", - format!("try_fold({init_snip}, {args_snip} ...)", ), + format!("try_fold({init_snip}, {args_snip} ...)",), Applicability::HasPlaceholders, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index 880efe60c1a..e0f8cb1b955 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use clippy_utils::{is_diag_trait_item, peel_blocks}; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs index 57581363cfa..bcfd0de8efe 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs @@ -4,8 +4,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::MAP_IDENTITY; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index e70a1bc9879..cb81b3919bf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::mutated_variables; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index a935aea5075..a71a136eba5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -99,6 +99,7 @@ mod suspicious_to_owned; mod type_id_on_box; mod uninit_assumed_init; mod unit_hash; +mod unnecessary_fallible_conversions; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; @@ -112,13 +113,14 @@ mod useless_asref; mod utils; mod vec_resize_to_zero; mod verbose_file_reads; +mod waker_clone_wake; mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; use if_chain::if_chain; @@ -142,11 +144,11 @@ declare_clippy_lint! { /// implements `Copy`. /// /// ### Example - /// ```rust + /// ```no_run /// [1, 2, 3].iter().cloned(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// [1, 2, 3].iter().copied(); /// ``` #[clippy::version = "1.53.0"] @@ -165,14 +167,14 @@ declare_clippy_lint! { /// with repetitive code. /// /// ### Example - /// ```rust + /// ```no_run /// let hello = "hesuo worpd" /// .replace('s', "l") /// .replace("u", "l") /// .replace('p', "l"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l"); /// ``` #[clippy::version = "1.65.0"] @@ -194,14 +196,14 @@ declare_clippy_lint! { /// A code that relies on that side-effect could fail. /// /// ### Examples - /// ```rust + /// ```no_run /// # let vec = vec!["string".to_string()]; /// vec.iter().cloned().take(10); /// vec.iter().cloned().last(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec!["string".to_string()]; /// vec.iter().take(10).cloned(); /// vec.iter().last().cloned(); @@ -222,11 +224,11 @@ declare_clippy_lint! { /// `Option` is used to produce 0 or 1 items. /// /// ### Example - /// ```rust + /// ```no_run /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); /// ``` #[clippy::version = "1.53.0"] @@ -254,7 +256,7 @@ declare_clippy_lint! { /// where they may get displayed. Activate this lint to do just that. /// /// ### Examples - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// option.unwrap(); @@ -262,7 +264,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// option.expect("more helpful message"); @@ -293,14 +295,14 @@ declare_clippy_lint! { /// It is better to write the value directly without the indirection. /// /// ### Examples - /// ```rust + /// ```no_run /// let val1 = Some(1).unwrap(); /// let val2 = Ok::<_, ()>(1).unwrap(); /// let val3 = Err::<(), _>(1).unwrap_err(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let val1 = 1; /// let val2 = 1; /// let val3 = 1; @@ -363,7 +365,7 @@ declare_clippy_lint! { /// them. /// /// ### Example - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn add(&self, other: &X) -> X { @@ -412,7 +414,7 @@ declare_clippy_lint! { /// mutable reference to a `as_..` function. /// /// ### Example - /// ```rust + /// ```no_run /// # struct X; /// impl X { /// fn as_str(self) -> &'static str { @@ -439,13 +441,13 @@ declare_clippy_lint! { /// The error type needs to implement `Debug` /// /// ### Example - /// ```rust + /// ```no_run /// # let x = Ok::<_, ()>(()); /// x.ok().expect("why did I do this again?"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = Ok::<_, ()>(()); /// x.expect("why did I do this again?"); /// ``` @@ -496,7 +498,7 @@ declare_clippy_lint! { /// heuristic to try to identify such cases. However, the heuristic can produce false negatives. /// /// ### Examples - /// ```rust + /// ```no_run /// # let x = Some(1); /// # let mut map = std::collections::HashMap::<u64, String>::new(); /// x.unwrap_or(Default::default()); @@ -504,7 +506,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = Some(1); /// # let mut map = std::collections::HashMap::<u64, String>::new(); /// x.unwrap_or_default(); @@ -529,7 +531,7 @@ declare_clippy_lint! { /// The order of the arguments is not in execution order /// /// ### Examples - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } @@ -539,7 +541,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result<usize, ()> = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } @@ -565,13 +567,13 @@ declare_clippy_lint! { /// The order of the arguments is not in execution order. /// /// ### Example - /// ```rust + /// ```no_run /// # let opt = Some(1); /// opt.map_or(None, |a| Some(a + 1)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let opt = Some(1); /// opt.and_then(|a| Some(a + 1)); /// ``` @@ -590,13 +592,13 @@ declare_clippy_lint! { /// `_.ok()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let r: Result<u32, &str> = Ok(1); /// assert_eq!(Some(1), r.map_or(None, Some)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let r: Result<u32, &str> = Ok(1); /// assert_eq!(Some(1), r.ok()); /// ``` @@ -616,7 +618,7 @@ declare_clippy_lint! { /// `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example - /// ```rust + /// ```no_run /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } /// let _ = opt().and_then(|s| Some(s.len())); @@ -626,7 +628,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } /// let _ = opt().map(|s| s.len()); @@ -648,13 +650,13 @@ declare_clippy_lint! { /// `_.find(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().filter(|x| **x == 0).next(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().find(|x| **x == 0); /// ``` @@ -673,13 +675,13 @@ declare_clippy_lint! { /// `_.find(!condition)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().skip_while(|x| **x == 0).next(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().find(|x| **x != 0); /// ``` @@ -698,7 +700,7 @@ declare_clippy_lint! { /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option` /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![vec![1]]; /// let opt = Some(5); /// @@ -707,7 +709,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![vec![1]]; /// # let opt = Some(5); /// vec.iter().flat_map(|x| x.iter()); @@ -729,7 +731,7 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// (0_i32..10) /// .filter(|n| n.checked_add(1).is_some()) @@ -737,7 +739,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[allow(unused)] /// (0_i32..10).filter_map(|n| n.checked_add(1)); /// ``` @@ -757,14 +759,14 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// ```rust + /// ```no_run /// (0_i32..10) /// .find(|n| n.checked_add(1).is_some()) /// .map(|n| n.checked_add(1).unwrap()); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// (0_i32..10).find_map(|n| n.checked_add(1)); /// ``` #[clippy::version = "1.51.0"] @@ -782,12 +784,12 @@ declare_clippy_lint! { /// `_.find_map(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next(); /// ``` /// Can be written as /// - /// ```rust + /// ```no_run /// (0..3).find_map(|x| if x == 2 { Some(x) } else { None }); /// ``` #[clippy::version = "1.36.0"] @@ -804,12 +806,12 @@ declare_clippy_lint! { /// Readability, this can be written more concisely by using `flatten`. /// /// ### Example - /// ```rust + /// ```no_run /// # let iter = vec![vec![0]].into_iter(); /// iter.flat_map(|x| x); /// ``` /// Can be written as - /// ```rust + /// ```no_run /// # let iter = vec![vec![0]].into_iter(); /// iter.flatten(); /// ``` @@ -830,7 +832,7 @@ declare_clippy_lint! { /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let vec = vec![1]; /// vec.iter().find(|x| **x == 0).is_some(); @@ -839,7 +841,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); /// @@ -862,13 +864,13 @@ declare_clippy_lint! { /// `_.starts_with(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// let name = "foo"; /// if name.chars().next() == Some('_') {}; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let name = "foo"; /// if name.starts_with('_') {}; /// ``` @@ -897,13 +899,13 @@ declare_clippy_lint! { /// actually expensive to call or not. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// foo.unwrap_or(String::from("empty")); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// foo.unwrap_or_else(|| String::from("empty")); /// ``` @@ -921,7 +923,7 @@ declare_clippy_lint! { /// You should use `.unwrap_or(…)` instead for clarity. /// /// ### Example - /// ```rust + /// ```no_run /// # let fallback = "fallback"; /// // Result /// # type Error = &'static str; @@ -933,7 +935,7 @@ declare_clippy_lint! { /// let value = option.or(Some(fallback)).unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let fallback = "fallback"; /// // Result /// # let result: Result<&str, &str> = Err("error"); @@ -962,7 +964,7 @@ declare_clippy_lint! { /// change the semantics of the program, but you shouldn't rely on that anyway. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; @@ -975,7 +977,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; @@ -996,7 +998,7 @@ declare_clippy_lint! { /// generics, not for using the `clone` method on a concrete type. /// /// ### Example - /// ```rust + /// ```no_run /// 42u64.clone(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1017,7 +1019,7 @@ declare_clippy_lint! { /// data. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// let x = Rc::new(1); /// @@ -1025,7 +1027,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// # let x = Rc::new(1); /// Rc::clone(&x); @@ -1047,7 +1049,7 @@ declare_clippy_lint! { /// facilities. /// /// ### Example - /// ```rust + /// ```no_run /// // Generic implementation for `T: Display` is used (slow) /// ["foo", "bar"].iter().map(|s| s.to_string()); /// @@ -1070,7 +1072,7 @@ declare_clippy_lint! { /// /// ### Example /// In an impl block: - /// ```rust + /// ```no_run /// # struct Foo; /// # struct NotAFoo; /// impl Foo { @@ -1080,7 +1082,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// ```rust + /// ```no_run /// # struct Foo; /// struct Bar(Foo); /// impl Foo { @@ -1091,7 +1093,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// ```rust + /// ```no_run /// # struct Foo; /// # struct FooError; /// impl Foo { @@ -1103,14 +1105,14 @@ declare_clippy_lint! { /// ``` /// /// Or in a trait definition: - /// ```rust + /// ```no_run /// pub trait Trait { /// // Bad. The type name must contain `Self` /// fn new(); /// } /// ``` /// - /// ```rust + /// ```no_run /// pub trait Trait { /// // Good. Return type contains `Self` /// fn new() -> Self; @@ -1178,11 +1180,11 @@ declare_clippy_lint! { /// automatically does this without suspicious-looking `unwrap` calls. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = std::iter::empty::<Option<i32>>().flatten(); /// ``` #[clippy::version = "1.53.0"] @@ -1201,7 +1203,7 @@ declare_clippy_lint! { /// but is more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); @@ -1209,7 +1211,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); @@ -1231,13 +1233,13 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.get(3); /// let bad_slice = &some_vec[..].get(3); @@ -1256,13 +1258,13 @@ declare_clippy_lint! { /// `.nth(x)` is cleaner /// /// ### Example - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().skip(3).next(); /// let bad_slice = &some_vec[..].iter().skip(3).next(); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); @@ -1281,13 +1283,13 @@ declare_clippy_lint! { /// `.into_iter()` is simpler with better performance. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// let mut foo = vec![0, 1, 2, 3]; /// let bar: HashSet<usize> = foo.drain(..).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// let foo = vec![0, 1, 2, 3]; /// let bar: HashSet<usize> = foo.into_iter().collect(); @@ -1315,13 +1317,13 @@ declare_clippy_lint! { /// `x.get(index).unwrap()` instead of `x[index]`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let last_element = x.get(x.len() - 1); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let last_element = x.last(); /// ``` @@ -1351,13 +1353,13 @@ declare_clippy_lint! { /// trait. /// /// ### Example - /// ```rust + /// ```no_run /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec.get(3).unwrap(); /// *some_vec.get_mut(0).unwrap() = 1; /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec[3]; /// some_vec[0] = 1; @@ -1376,7 +1378,7 @@ declare_clippy_lint! { /// Using `append` instead of `extend` is more concise and faster /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// @@ -1384,7 +1386,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// @@ -1405,7 +1407,7 @@ declare_clippy_lint! { /// `.push_str(s)` is clearer /// /// ### Example - /// ```rust + /// ```no_run /// let abc = "abc"; /// let def = String::from("def"); /// let mut s = String::new(); @@ -1413,7 +1415,7 @@ declare_clippy_lint! { /// s.extend(def.chars()); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let abc = "abc"; /// let def = String::from("def"); /// let mut s = String::new(); @@ -1435,12 +1437,12 @@ declare_clippy_lint! { /// `.to_vec()` is clearer /// /// ### Example - /// ```rust + /// ```no_run /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec<isize> = s[..].iter().cloned().collect(); /// ``` /// The better use would be: - /// ```rust + /// ```no_run /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec<isize> = s.to_vec(); /// ``` @@ -1460,13 +1462,13 @@ declare_clippy_lint! { /// `_.ends_with(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let name = "_"; /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let name = "_"; /// name.ends_with('_') || name.ends_with('-'); /// ``` @@ -1485,13 +1487,13 @@ declare_clippy_lint! { /// The call is unnecessary. /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x.as_ref()); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x); @@ -1512,13 +1514,13 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # #[allow(unused)] /// (0..3).fold(false, |acc, x| acc || x > 2); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// (0..3).any(|x| x > 2); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1538,14 +1540,14 @@ declare_clippy_lint! { /// operation is being performed. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); /// /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).filter(|&x| x > 2); /// ``` /// - /// ```rust + /// ```no_run /// let _ = (0..4).filter_map(|x| Some(x + 1)); /// /// // As there is no conditional check on the argument this could be written as: @@ -1568,14 +1570,14 @@ declare_clippy_lint! { /// operation is being performed. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None }); /// /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).find(|&x| x > 2); /// ``` /// - /// ```rust + /// ```no_run /// let _ = (0..4).find_map(|x| Some(x + 1)); /// /// // As there is no conditional check on the argument this could be written as: @@ -1598,13 +1600,13 @@ declare_clippy_lint! { /// `iter_mut` directly. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![3, 4, 5]; /// (&vec).into_iter(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![3, 4, 5]; /// (&vec).iter(); /// ``` @@ -1625,7 +1627,7 @@ declare_clippy_lint! { /// completion, you can just use `for_each` instead. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).map(|x| x + 2).count(); /// ``` #[clippy::version = "1.39.0"] @@ -1647,7 +1649,7 @@ declare_clippy_lint! { /// data, but those are not yet rigorously defined. /// /// ### Example - /// ```rust + /// ```no_run /// // Beware the UB /// use std::mem::MaybeUninit; /// @@ -1656,7 +1658,7 @@ declare_clippy_lint! { /// /// Note that the following is OK: /// - /// ```rust + /// ```no_run /// use std::mem::MaybeUninit; /// /// let _: [MaybeUninit<bool>; 5] = unsafe { @@ -1677,7 +1679,7 @@ declare_clippy_lint! { /// These can be written simply with `saturating_add/sub` methods. /// /// ### Example - /// ```rust + /// ```no_run /// # let y: u32 = 0; /// # let x: u32 = 100; /// let add = x.checked_add(y).unwrap_or(u32::MAX); @@ -1686,7 +1688,7 @@ declare_clippy_lint! { /// /// can be written using dedicated methods for saturating addition/subtraction as: /// - /// ```rust + /// ```no_run /// # let y: u32 = 0; /// # let x: u32 = 100; /// let add = x.saturating_add(y); @@ -1707,7 +1709,7 @@ declare_clippy_lint! { /// This is a no-op, and likely unintended /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { (&() as *const ()).offset(1) }; /// ``` #[clippy::version = "1.41.0"] @@ -1727,7 +1729,7 @@ declare_clippy_lint! { /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. /// /// ### Example - /// ```rust + /// ```no_run /// # || { /// let metadata = std::fs::metadata("foo.txt")?; /// let filetype = metadata.file_type(); @@ -1741,7 +1743,7 @@ declare_clippy_lint! { /// /// should be written as: /// - /// ```rust + /// ```no_run /// # || { /// let metadata = std::fs::metadata("foo.txt")?; /// let filetype = metadata.file_type(); @@ -1767,13 +1769,13 @@ declare_clippy_lint! { /// `_.as_deref()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let opt = Some("".to_string()); /// opt.as_ref().map(String::as_str) /// # ; /// ``` /// Can be written as - /// ```rust + /// ```no_run /// # let opt = Some("".to_string()); /// opt.as_deref() /// # ; @@ -1792,14 +1794,14 @@ declare_clippy_lint! { /// These can be shortened into `.get()` /// /// ### Example - /// ```rust + /// ```no_run /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; /// a[2..].iter().next(); /// b.iter().next(); /// ``` /// should be written as: - /// ```rust + /// ```no_run /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; /// a.get(2); @@ -1820,14 +1822,14 @@ declare_clippy_lint! { /// It's less clear that we are pushing a single character. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut string = String::new(); /// string.insert_str(0, "R"); /// string.push_str("R"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut string = String::new(); /// string.insert(0, 'R'); /// string.push('R'); @@ -1860,14 +1862,14 @@ declare_clippy_lint! { /// side effects. Eagerly evaluating them can change the semantics of the program. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let opt: Option<u32> = None; /// /// opt.unwrap_or_else(|| 42); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let opt: Option<u32> = None; /// /// opt.unwrap_or(42); @@ -1886,11 +1888,11 @@ declare_clippy_lint! { /// Using `try_for_each` instead is more readable and idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// (0..3).try_for_each(|t| Err(t)); /// ``` #[clippy::version = "1.49.0"] @@ -1909,7 +1911,7 @@ declare_clippy_lint! { /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) /// /// ### Example - /// ```rust + /// ```no_run /// let five_fives = std::iter::repeat(5).take(5); /// /// let v = Vec::from_iter(five_fives); @@ -1917,7 +1919,7 @@ declare_clippy_lint! { /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let five_fives = std::iter::repeat(5).take(5); /// /// let v: Vec<i32> = five_fives.collect(); @@ -1939,7 +1941,7 @@ declare_clippy_lint! { /// inside `inspect` at the beginning of the closure in `for_each`. /// /// ### Example - /// ```rust + /// ```no_run /// [1,2,3,4,5].iter() /// .inspect(|&x| println!("inspect the number: {}", x)) /// .for_each(|&x| { @@ -1947,7 +1949,7 @@ declare_clippy_lint! { /// }); /// ``` /// Can be written as - /// ```rust + /// ```no_run /// [1,2,3,4,5].iter() /// .for_each(|&x| { /// println!("inspect the number: {}", x); @@ -1968,12 +1970,12 @@ declare_clippy_lint! { /// Readability, this can be written more concisely by using `flatten`. /// /// ### Example - /// ```rust + /// ```no_run /// # let iter = vec![Some(1)].into_iter(); /// iter.filter_map(|x| x); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let iter = vec![Some(1)].into_iter(); /// iter.flatten(); /// ``` @@ -1991,12 +1993,12 @@ declare_clippy_lint! { /// It can be written more concisely without the call to `map`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); /// ``` @@ -2015,13 +2017,13 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// # #[allow(unused)] /// "Hello".bytes().nth(3); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[allow(unused)] /// "Hello".as_bytes().get(3); /// ``` @@ -2040,13 +2042,13 @@ declare_clippy_lint! { /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. /// /// ### Example - /// ```rust + /// ```no_run /// let a = vec![1, 2, 3]; /// let b = a.to_vec(); /// let c = a.to_owned(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = vec![1, 2, 3]; /// let b = a.clone(); /// let c = a.clone(); @@ -2066,7 +2068,7 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let some_vec = vec![0, 1, 2, 3]; /// @@ -2075,7 +2077,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// /// some_vec.len(); @@ -2104,7 +2106,7 @@ declare_clippy_lint! { /// was the original intent, using `into_owned` instead. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2113,7 +2115,7 @@ declare_clippy_lint! { /// assert!(matches!(data, Cow::Borrowed(_))) /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2122,7 +2124,7 @@ declare_clippy_lint! { /// assert!(matches!(data, Cow::Borrowed(_))) /// ``` /// or - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2146,7 +2148,7 @@ declare_clippy_lint! { /// likely to be intended as a different number. /// /// ### Example - /// ```rust + /// ```no_run /// # let s = ""; /// for x in s.splitn(1, ":") { /// // .. @@ -2154,7 +2156,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = ""; /// for x in s.splitn(2, ":") { /// // .. @@ -2174,12 +2176,12 @@ declare_clippy_lint! { /// These are both harder to read, as well as less performant. /// /// ### Example - /// ```rust + /// ```no_run /// let x: String = std::iter::repeat('x').take(10).collect(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x: String = "x".repeat(10); /// ``` #[clippy::version = "1.54.0"] @@ -2231,13 +2233,13 @@ declare_clippy_lint! { /// The function `split` is simpler and there is no performance difference in these cases, considering /// that both functions return a lazy iterator. /// ### Example - /// ```rust + /// ```no_run /// let str = "key=value=add"; /// let _ = str.splitn(3, '=').next().unwrap(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let str = "key=value=add"; /// let _ = str.split('=').next().unwrap(); /// ``` @@ -2261,13 +2263,13 @@ declare_clippy_lint! { /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148). /// /// ### Example - /// ```rust + /// ```no_run /// let path = std::path::Path::new("x"); /// foo(&path.to_string_lossy().to_string()); /// fn foo(s: &str) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let path = std::path::Path::new("x"); /// foo(&path.to_string_lossy()); /// fn foo(s: &str) {} @@ -2286,13 +2288,13 @@ declare_clippy_lint! { /// `.collect::<String>()` is more concise and might be more performant /// /// ### Example - /// ```rust + /// ```no_run /// let vector = vec!["hello", "world"]; /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join(""); /// println!("{}", output); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let vector = vec!["hello", "world"]; /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>(); /// println!("{}", output); @@ -2319,13 +2321,13 @@ declare_clippy_lint! { /// Redundant code and improving readability. /// /// ### Example - /// ```rust + /// ```no_run /// let a = Some(&1); /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = Some(&1); /// let b = a; /// ``` @@ -2345,13 +2347,13 @@ declare_clippy_lint! { /// `is_digit(..)` is slower and requires specifying the radix. /// /// ### Example - /// ```rust + /// ```no_run /// let c: char = '6'; /// c.is_digit(10); /// c.is_digit(16); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let c: char = '6'; /// c.is_ascii_digit(); /// c.is_ascii_hexdigit(); @@ -2371,12 +2373,12 @@ declare_clippy_lint! { /// In this case the modification is useless as it's a temporary that cannot be read from afterwards. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(3); /// x.as_ref().take(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(3); /// x.as_ref(); /// ``` @@ -2394,7 +2396,7 @@ declare_clippy_lint! { /// It's either a mistake or confusing. /// /// ### Example - /// ```rust + /// ```no_run /// "1234".replace("12", "12"); /// "1234".replacen("12", "12", 1); /// ``` @@ -2417,12 +2419,12 @@ declare_clippy_lint! { /// to account for similar patterns. /// /// ### Example - /// ```rust + /// ```no_run /// let x = true; /// x.then_some("a").unwrap_or("b"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = true; /// if x { "a" } else { "b" }; /// ``` @@ -2444,12 +2446,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// let a = [123].iter(); /// let b = Some(123).into_iter(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::iter; /// let a = iter::once(&123); /// let b = iter::once(123); @@ -2475,13 +2477,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// use std::{slice, option}; /// let a: slice::Iter<i32> = [].iter(); /// let f: option::IntoIter<i32> = None.into_iter(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::iter; /// let a: iter::Empty<i32> = iter::empty(); /// let b: iter::Empty<i32> = iter::empty(); @@ -2511,7 +2513,7 @@ declare_clippy_lint! { /// faster in those cases. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1_u8]; /// let count = vec.iter().filter(|x| **x == 0u8).count(); /// ``` @@ -2537,12 +2539,12 @@ declare_clippy_lint! { /// `str::len()`. /// /// ### Example - /// ```rust + /// ```no_run /// "hello".bytes().count(); /// String::from("hello").bytes().count(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// "hello".len(); /// String::from("hello").len(); /// ``` @@ -2561,13 +2563,13 @@ declare_clippy_lint! { /// `ends_with` is case-sensitive and may not detect files with a valid extension. /// /// ### Example - /// ```rust + /// ```no_run /// fn is_rust_file(filename: &str) -> bool { /// filename.ends_with(".rs") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn is_rust_file(filename: &str) -> bool { /// let filename = std::path::Path::new(filename); /// filename.extension() @@ -2590,13 +2592,13 @@ declare_clippy_lint! { /// result. /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let first_element = x.get(0); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let first_element = x.first(); /// ``` @@ -2616,13 +2618,13 @@ declare_clippy_lint! { /// Concise code helps focusing on behavior instead of boilerplate. /// /// ### Examples - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// foo.map_or(Err("error"), |v| Ok(v)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo: Option<i32> = None; /// foo.ok_or("error"); /// ``` @@ -2642,7 +2644,7 @@ declare_clippy_lint! { /// Readability, this can be written more concisely /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![42, 43]; /// let y = x.iter(); /// let z = y.map(|i| *i); @@ -2650,7 +2652,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// let x = vec![42, 43]; /// let y = x.iter(); /// let z = y.cloned(); @@ -2670,7 +2672,7 @@ declare_clippy_lint! { /// /// ### Example /// Before: - /// ```rust + /// ```no_run /// use std::fmt; /// /// #[derive(Debug)] @@ -2772,7 +2774,7 @@ declare_clippy_lint! { /// guarantee. /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::{Arc, Mutex}; /// /// let mut value_rc = Arc::new(Mutex::new(42_u8)); @@ -2782,7 +2784,7 @@ declare_clippy_lint! { /// *value += 1; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::{Arc, Mutex}; /// /// let mut value_rc = Arc::new(Mutex::new(42_u8)); @@ -2807,7 +2809,7 @@ declare_clippy_lint! { /// necessary. I don't know the worst case. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fs::OpenOptions; /// /// OpenOptions::new().read(true).truncate(true); @@ -2828,7 +2830,7 @@ declare_clippy_lint! { /// previous defined path. /// /// ### Example - /// ```rust + /// ```no_run /// use std::path::PathBuf; /// /// let mut x = PathBuf::from("/foo"); @@ -2837,7 +2839,7 @@ declare_clippy_lint! { /// ``` /// Could be written: /// - /// ```rust + /// ```no_run /// use std::path::PathBuf; /// /// let mut x = PathBuf::from("/foo"); @@ -2859,13 +2861,13 @@ declare_clippy_lint! { /// The code is better expressed with `.enumerate()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = vec![1]; /// let _ = x.iter().zip(0..x.len()); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = vec![1]; /// let _ = x.iter().enumerate(); /// ``` @@ -2890,13 +2892,13 @@ declare_clippy_lint! { /// the string is the intention behind this, `clone()` should be used. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// let x = String::from("hello world").repeat(1); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// let x = String::from("hello world").clone(); /// } @@ -2930,12 +2932,12 @@ declare_clippy_lint! { /// issue linked above. /// /// ### Example - /// ```rust + /// ```no_run /// let mut vec = vec![2, 1, 3]; /// vec.sort(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = vec![2, 1, 3]; /// vec.sort_unstable(); /// ``` @@ -2963,7 +2965,7 @@ declare_clippy_lint! { /// assert_eq!(any_box.type_id(), TypeId::of::<i32>()); // ⚠️ this fails! /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::any::{Any, TypeId}; /// /// let any_box: Box<dyn Any> = Box::new(42_i32); @@ -2984,7 +2986,7 @@ declare_clippy_lint! { /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::hash::Hash; /// # use std::collections::hash_map::DefaultHasher; /// # enum Foo { Empty, WithValue(u8) } @@ -2997,7 +2999,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::hash::Hash; /// # use std::collections::hash_map::DefaultHasher; /// # enum Foo { Empty, WithValue(u8) } @@ -3030,14 +3032,14 @@ declare_clippy_lint! { /// imported by a use statement, then it will need to be added manually. /// /// ### Example - /// ```rust + /// ```no_run /// # struct A; /// # impl A { fn foo(&self) {} } /// # let mut vec: Vec<A> = Vec::new(); /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct A; /// # impl A { fn foo(&self) {} } /// # let mut vec: Vec<A> = Vec::new(); @@ -3057,12 +3059,12 @@ declare_clippy_lint! { /// This is probably an argument inversion mistake. /// /// ### Example - /// ```rust + /// ```no_run /// vec![1, 2, 3, 4, 5].resize(0, 5) /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3, 4, 5].clear() /// ``` #[clippy::version = "1.46.0"] @@ -3111,14 +3113,14 @@ declare_clippy_lint! { /// /// ### Example /// - /// ``` + /// ```no_run /// # use std::collections::HashMap; /// let map: HashMap<u32, u32> = HashMap::new(); /// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// # use std::collections::HashMap; /// let map: HashMap<u32, u32> = HashMap::new(); /// let values = map.values().collect::<Vec<_>>(); @@ -3184,14 +3186,14 @@ declare_clippy_lint! { /// this exact scenario. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::io; /// fn foo<T: io::Seek>(t: &mut T) { /// t.seek(io::SeekFrom::Start(0)); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::io; /// fn foo<T: io::Seek>(t: &mut T) { /// t.rewind(); @@ -3213,12 +3215,12 @@ declare_clippy_lint! { /// when this allocation may not be needed. /// /// ### Example - /// ```rust + /// ```no_run /// # let iterator = vec![1].into_iter(); /// let len = iterator.collect::<Vec<_>>().len(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` @@ -3241,11 +3243,11 @@ declare_clippy_lint! { /// which is likely not what was intended. /// /// ### Example - /// ```rust + /// ```no_run /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); /// ``` #[clippy::version = "1.69.0"] @@ -3264,12 +3266,12 @@ declare_clippy_lint! { /// Calling `.clear()` also makes the intent clearer. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = vec![1, 2, 3]; /// v.drain(..); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut v = vec![1, 2, 3]; /// v.clear(); /// ``` @@ -3287,12 +3289,12 @@ declare_clippy_lint! { /// `.next_back()` is cleaner. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = [0; 10]; /// foo.iter().rev().next(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let foo = [0; 10]; /// foo.iter().next_back(); /// ``` @@ -3320,13 +3322,13 @@ declare_clippy_lint! { /// to keep the capacity on the original `Vec`. /// /// ### Example - /// ```rust + /// ```no_run /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> { /// v.drain(..).collect() /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::mem; /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> { /// mem::take(v) @@ -3354,11 +3356,11 @@ declare_clippy_lint! { /// desirable in those cases. /// /// ### Example - /// ```rust + /// ```no_run /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)); /// ``` #[clippy::version = "1.72.0"] @@ -3410,12 +3412,12 @@ declare_clippy_lint! { /// for situations where that additional performance is absolutely necessary. /// /// ### Example - /// ```rust + /// ```no_run /// # let c = 'c'; /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let c = 'c'; /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); /// ``` @@ -3439,13 +3441,13 @@ declare_clippy_lint! { /// so it can be safely ignored or unwrapped. /// /// ### Example - /// ```rust + /// ```no_run /// fn hex_encode(bytes: &[u8]) -> String { /// bytes.iter().map(|b| format!("{b:02X}")).collect() /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::Write; /// fn hex_encode(bytes: &[u8]) -> String { /// bytes.iter().fold(String::new(), |mut output, b| { @@ -3469,7 +3471,7 @@ declare_clippy_lint! { /// nothing. If not, the call should be removed. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![1, 2, 3]; /// let x = v.iter().skip(0).collect::<Vec<_>>(); /// let y = v.iter().collect::<Vec<_>>(); @@ -3495,13 +3497,13 @@ declare_clippy_lint! { /// This can create differing behavior, so better safe than sorry. /// /// ### Example - /// ```rust + /// ```no_run /// # fn really_expensive_fn(i: i32) -> i32 { i } /// # let v = vec![]; /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i))); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn really_expensive_fn(i: i32) -> i32 { i } /// # let v = vec![]; /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); @@ -3521,7 +3523,7 @@ declare_clippy_lint! { /// can access the lock while this writer is active. /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::RwLock; /// fn assert_is_zero(lock: &RwLock<i32>) { /// let num = lock.write().unwrap(); @@ -3530,7 +3532,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::RwLock; /// fn assert_is_zero(lock: &RwLock<i32>) { /// let num = lock.read().unwrap(); @@ -3554,11 +3556,11 @@ declare_clippy_lint! { /// This is most likely not what the user intended to do. /// /// ### Example - /// ```rust + /// ```no_run /// for _ in [1, 2, 3].iter().take(4) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// for _ in [1, 2, 3].iter() {} /// ``` #[clippy::version = "1.74.0"] @@ -3587,14 +3589,14 @@ declare_clippy_lint! { /// therefore ignored. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::path::Path; /// fn is_markdown(path: &Path) -> bool { /// path.ends_with(".md") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::path::Path; /// fn is_markdown(path: &Path) -> bool { /// path.extension().is_some_and(|ext| ext == "md") @@ -3614,14 +3616,14 @@ declare_clippy_lint! { /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); /// owned_string.as_str().as_bytes(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); /// owned_string.as_bytes(); @@ -3632,6 +3634,55 @@ declare_clippy_lint! { "`as_str` used to call a method on `str` that is also available on `String`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `waker.clone().wake()` + /// + /// ### Why is this bad? + /// Cloning the waker is not necessary, `wake_by_ref()` enables the same operation + /// without extra cloning/dropping. + /// + /// ### Example + /// ```rust,ignore + /// waker.clone().wake(); + /// ``` + /// Should be written + /// ```rust,ignore + /// waker.wake_by_ref(); + /// ``` + #[clippy::version = "1.75.0"] + pub WAKER_CLONE_WAKE, + perf, + "cloning a `Waker` only to wake it" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `TryInto::try_into` and `TryFrom::try_from` when their infallible counterparts + /// could be used. + /// + /// ### Why is this bad? + /// In those cases, the `TryInto` and `TryFrom` trait implementation is a blanket impl that forwards + /// to `Into` or `From`, which always succeeds. + /// The returned `Result<_, Infallible>` requires error handling to get the contained value + /// even though the conversion can never fail. + /// + /// ### Example + /// ```rust + /// let _: Result<i64, _> = 1i32.try_into(); + /// let _: Result<i64, _> = <_>::try_from(1i32); + /// ``` + /// Use `from`/`into` instead: + /// ```rust + /// let _: i64 = 1i32.into(); + /// let _: i64 = <_>::from(1i32); + /// ``` + #[clippy::version = "1.75.0"] + pub UNNECESSARY_FALLIBLE_CONVERSIONS, + style, + "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3777,6 +3828,8 @@ impl_lint_pass!(Methods => [ ITER_OUT_OF_BOUNDS, PATH_ENDS_WITH_EXT, REDUNDANT_AS_STR, + WAKER_CLONE_WAKE, + UNNECESSARY_FALLIBLE_CONVERSIONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3803,6 +3856,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); + unnecessary_fallible_conversions::check_function(cx, expr, func); }, hir::ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; @@ -3878,21 +3932,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } if sig.decl.implicit_self.has_implicit_self() - && !(self.avoid_breaking_exported_api + && !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)) - && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() - && let Some(first_arg_ty) = first_arg_ty_opt - { - wrong_self_convention::check( - cx, - name, - self_ty, - first_arg_ty, - first_arg.pat.span, - implements_trait, - false - ); - } + && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() + && let Some(first_arg_ty) = first_arg_ty_opt + { + wrong_self_convention::check( + cx, + name, + self_ty, + first_arg_ty, + first_arg.pat.span, + implements_trait, + false, + ); + } } // if this impl block implements a trait, lint in trait definition instead @@ -3977,10 +4031,16 @@ impl Methods { }, ("all", [arg]) => { if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::NeedlessMove(name, arg), false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ); } - } + }, ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); @@ -3988,24 +4048,35 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, - ("any", [arg]) => { - match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), - Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params => { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); - } - _ => {} - } - } + ("any", [arg]) => match method_call(recv) { + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ), + Some(("chars", recv, _, _, _)) + if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params => + { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + }, + _ => {}, + }, ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); - } + }, ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, - ("as_bytes" | "is_empty", []) => if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); }, + ("as_bytes" | "is_empty", []) => { + if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { + redundant_as_str::check(cx, expr, recv, as_str_span, span); + } + }, ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), @@ -4027,12 +4098,14 @@ impl Methods { }, Some(("drain", recv, args, ..)) => { drain_collect::check(cx, args, expr, recv); - } + }, _ => {}, } }, ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned , false), + Some(("cloned", recv2, [], _, _)) => { + iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false); + }, Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { iter_count::check(cx, expr, recv2, name2); }, @@ -4060,7 +4133,9 @@ impl Methods { ("expect", [_]) => { match method_call(recv) { Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), - Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv), + Some(("err", recv, [], err_span, _)) => { + err_expect::check(cx, expr, recv, span, err_span, &self.msrv); + }, _ => unwrap_expect_used::check( cx, expr, @@ -4087,13 +4162,19 @@ impl Methods { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, - (name @ ( "filter" | "find" ) , [arg]) => { + (name @ ("filter" | "find"), [arg]) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::FixClosure(name, arg), false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::FixClosure(name, arg), + false, + ); } - } + }, ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); @@ -4107,20 +4188,34 @@ impl Methods { flat_map_option::check(cx, expr, arg, span); }, ("flatten", []) => match method_call(recv) { - Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , true), + Some(("map", recv, [map_arg], map_span, _)) => { + map_flatten::check(cx, expr, recv, map_arg, map_span); + }, + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + true, + ), _ => {}, }, ("fold", [init, acc]) => { manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [arg]) => { - match method_call(recv) { - Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), - _ => {} - } + ("for_each", [arg]) => match method_call(recv) { + Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ), + _ => {}, }, ("get", [arg]) => { get_first::check(cx, expr, recv, arg); @@ -4144,8 +4239,14 @@ impl Methods { }, ("last", []) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned , false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } }, ("lock", []) => { @@ -4155,14 +4256,23 @@ impl Methods { if name == "map" { map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { - Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => iter_kv_map::check(cx, map_name, expr, recv2, m_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, m_arg), false), - _ => {} + Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { + iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + }, + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, m_arg), + false, + ), + _ => {}, } } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, recv2, args, span2,_)) = method_call(recv) { + if let Some((name, recv2, args, span2, _)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv), @@ -4184,20 +4294,34 @@ impl Methods { ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false), + ("cloned", []) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv), ("iter", []) => iter_next_slice::check(cx, expr, recv2), ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), ("skip_while", [_]) => skip_while_next::check(cx, expr), - ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2), + ("rev", []) => manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } }, ("nth", [n_arg]) => match method_call(recv) { Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , false), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ), Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), _ => iter_nth_zero::check(cx, expr, recv, n_arg), @@ -4222,7 +4346,7 @@ impl Methods { }, ("read_line", [arg]) => { read_line_without_trim::check(cx, expr, recv, arg); - } + }, ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, @@ -4253,10 +4377,16 @@ impl Methods { iter_out_of_bounds::check_skip(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned , false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } - } + }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, @@ -4281,8 +4411,14 @@ impl Methods { ("take", [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned, false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } }, ("take", []) => needless_option_take::check(cx, expr, recv), @@ -4292,6 +4428,9 @@ impl Methods { } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, + ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { + unnecessary_fallible_conversions::check_method(cx, expr); + }, ("to_owned", []) => { if !suspicious_to_owned::check(cx, expr, recv) { implicit_clone::check(cx, name, expr, recv); @@ -4302,7 +4441,7 @@ impl Methods { }, ("type_id", []) => { type_id_on_box::check(cx, recv, expr.span); - } + }, ("unwrap", []) => { match method_call(recv) { Some(("get", recv, [get_arg], _, _)) => { @@ -4354,7 +4493,7 @@ impl Methods { }, ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - } + }, ("unwrap_or_else", [u_arg]) => { match method_call(recv) { Some(("map", recv, [map_arg], _, _)) @@ -4365,9 +4504,12 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, + ("wake", []) => { + waker_clone_wake::check(cx, expr, recv); + }, ("write", []) => { readonly_write_lock::check(cx, expr, recv); - } + }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index dbd965d6506..2ef71be3217 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -87,21 +87,17 @@ pub(super) fn check<'tcx>( } }, Node::Local(l) => { - if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) - = l.pat.kind + if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) - && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter() + && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList] + .into_iter() .any(|item| is_type_diagnostic_item(cx, ty, item)) && let iter_ty = cx.typeck_results().expr_ty(iter_expr) && let Some(block) = get_enclosing_block(cx, l.hir_id) && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) && let [iter_call] = &*iter_calls { - let mut used_count_visitor = UsedCountVisitor { - cx, - id, - count: 0, - }; + let mut used_count_visitor = UsedCountVisitor { cx, id, count: 0 }; walk_block(&mut used_count_visitor, block); if used_count_visitor.count > 1 { return; @@ -117,13 +113,11 @@ pub(super) fn check<'tcx>( span, NEEDLESS_COLLECT_MSG, |diag| { - let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); + let iter_replacement = + format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); diag.multipart_suggestion( iter_call.get_suggestion_text(), - vec![ - (l.span, String::new()), - (iter_call.span, iter_replacement) - ], + vec![(l.span, String::new()), (iter_call.span, iter_replacement)], Applicability::MaybeIncorrect, ); }, @@ -175,11 +169,12 @@ fn check_collect_into_intoiterator<'tcx>( .into_iter() .filter_map(|p| { if let ClauseKind::Trait(t) = p.kind().skip_binder() - && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { - Some(t.self_ty()) - } else { - None - } + && cx.tcx.is_diagnostic_item(sym::IntoIterator, t.trait_ref.def_id) + { + Some(t.self_ty()) + } else { + None + } }) .any(|ty| ty == inputs[arg_idx]) { @@ -207,14 +202,13 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { /// Checks if `<iter_ty as Iterator>::Item` is the same as `<collect_ty as IntoIter>::Item` fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool { - let item = Symbol::intern("Item"); if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator) - && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty]) - && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty]) + && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, sym::Item, [iter_ty]) + && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.args) + Ty::new_projection(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args), ) { iter_item_ty == into_iter_item_ty @@ -233,11 +227,14 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let [_, search_ty] = *sig.skip_binder().inputs() && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind() && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(iter_item) = cx.tcx - .associated_items(iter_trait) - .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait) + && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind( + cx.tcx, + Ident::with_dummy_span(sym::Item), + AssocKind::Type, + iter_trait, + ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) - && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, args) + && let proj_ty = Ty::new_projection(cx.tcx, iter_item.def_id, args) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id)) diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index c0f5a279945..65c986dcacc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -3,8 +3,8 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::{Span, Spanned}; -use rustc_span::sym; +use rustc_span::source_map::Spanned; +use rustc_span::{sym, Span}; use super::NONSENSICAL_OPEN_OPTIONS; diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index d0c27f9631f..7b81d4571b2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks}; diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index fcbe005fb28..c78f8b71c78 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; @@ -9,8 +9,7 @@ use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::MAP_UNWRAP_OR; 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 942f3bd79a6..b89c151461c 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 @@ -7,7 +7,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::{self, sym, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; @@ -235,10 +235,10 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) let body = cx.tcx.hir().body(body); if body.params.is_empty() - && let hir::Expr{ kind, .. } = &body.value - && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind + && let hir::Expr { kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, self_arg, _, _) = kind && ident.name == sym::to_string - && let hir::Expr{ kind, .. } = self_arg + && let hir::Expr { kind, .. } = self_arg && let hir::ExprKind::Lit(lit) = kind && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node { diff --git a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs index 3347c8c1620..094ead9f4ad 100644 --- a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs @@ -1,7 +1,6 @@ use super::PATH_ENDS_WITH_EXT; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs; -use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; @@ -47,7 +46,7 @@ pub(super) fn check( "this looks like a failed attempt at checking for the file extension", "try", sugg, - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index 81f9e2a77fc..3b903ec5cdb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -46,9 +46,12 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< span, "calling `.parse()` without trimming the trailing newline character", |diag| { - diag.span_note(call.span, "call to `.read_line()` here, \ + diag.span_note( + call.span, + "call to `.read_line()` here, \ which leaves a trailing newline character in the buffer, \ - which in turn will cause `.parse()` to fail"); + which in turn will cause `.parse()` to fail", + ); diag.span_suggestion( expr.span, @@ -56,7 +59,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< format!("{local_snippet}.trim_end()"), Applicability::MachineApplicable, ); - } + }, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs index e3ec921da0c..1184dd4525a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs +++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs @@ -26,13 +26,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id) && let Node::Local(local) = parent && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) - && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| { - local.span.contains(decl.source_info.span) - }) - && let Some(usages) = visit_local_usage(&[local], mir, Location { - block: START_BLOCK, - statement_index: 0, - }) + && let Some((local, _)) = mir + .local_decls + .iter_enumerated() + .find(|(_, decl)| local.span.contains(decl.source_info.span)) + && let Some(usages) = visit_local_usage( + &[local], + mir, + Location { + block: START_BLOCK, + statement_index: 0, + }, + ) && let [usage] = usages.as_slice() { let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty(); @@ -45,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver "this write lock is used only for reading", "consider using a read lock instead", format!("{}.read()", snippet(cx, receiver.span, "<receiver>")), - Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness + Applicability::MaybeIncorrect, // write lock might be intentional for enforcing exclusiveness ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index 04ddaaa2f46..05a9a06c8c7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs index 4ea87027a9e..63d41677fee 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs @@ -33,15 +33,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' } fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let ExprKind::Call(f, args) = expr.kind && - let ExprKind::Path(ref path) = f.kind && - let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) { + if let ExprKind::Call(f, args) = expr.kind + && let ExprKind::Path(ref path) = f.kind + && let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) + { // check if argument of `SeekFrom::Current` is `0` - if args.len() == 1 && - let ExprKind::Lit(lit) = args[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { - return true + if args.len() == 1 + && let ExprKind::Lit(lit) = args[0].kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + { + return true; } } diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 50d4de7a680..9f38460357b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -23,15 +23,15 @@ pub(super) fn check<'tcx>( return; } - if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) && - implements_trait(cx, ty, seek_trait_id, &[]) && - let ExprKind::Call(func, args1) = arg.kind && - let ExprKind::Path(ref path) = func.kind && - let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && - args1.len() == 1 && - let ExprKind::Lit(lit) = args1[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) + && implements_trait(cx, ty, seek_trait_id, &[]) + && let ExprKind::Call(func, args1) = arg.kind + && let ExprKind::Path(ref path) = func.kind + && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) + && args1.len() == 1 + && let ExprKind::Lit(lit) = args1[0].kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { let method_call_span = expr.span.with_lo(name_span.lo()); span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 7016ad0a80f..9da61bca52c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; @@ -115,7 +115,7 @@ fn check_manual_split_once( /// checks for /// -/// ``` +/// ```no_run /// let mut iter = "a.b.c".splitn(2, '.'); /// let a = iter.next(); /// let b = iter.next(); @@ -133,13 +133,11 @@ fn check_manual_split_once_indirect( && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? - && let mut stmts = enclosing_block .stmts .iter() .skip_while(|stmt| stmt.hir_id != iter_stmt_id) .skip(1) - && let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? && let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? && first.unwrap_kind == second.unwrap_kind @@ -173,18 +171,8 @@ fn check_manual_split_once_indirect( ); let remove_msg = format!("remove the `{iter_ident}` usages"); - diag.span_suggestion( - first.span, - remove_msg.clone(), - "", - app, - ); - diag.span_suggestion( - second.span, - remove_msg, - "", - app, - ); + diag.span_suggestion(first.span, remove_msg.clone(), "", app); + diag.span_suggestion(second.span, remove_msg, "", app); }); } diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs index 70da6ad58bd..5f6f027a3b5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{Msrv, MATCHES_MACRO}; use clippy_utils::source::snippet_opt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( body: &Expr<'_>, msrv: &Msrv, ) { - if msrv.meets(MATCHES_MACRO) + if msrv.meets(msrvs::MATCHES_MACRO) && is_trait_method(cx, expr, sym::Iterator) && let PatKind::Binding(_, arg, _, _) = param.pat.kind && let ExprKind::Lit(lit_kind) = recv.kind @@ -52,7 +52,7 @@ pub(super) fn check<'tcx>( format!("matches!({scrutinee_snip}, {pat_snip})"), Applicability::MachineApplicable, ); - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs index 8959e2c1d75..b2c5987e43d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -25,13 +25,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg |diag: &mut Diagnostic| { diag.multipart_suggestion_verbose( "consider splitting the argument", - vec![ - (span, "args".to_string()), - (arg.span, format!("[{arg1:?}, {arg2:?}]")), - ], + vec![(span, "args".to_string()), (arg.span, format!("[{arg1:?}, {arg2:?}]"))], Applicability::MaybeIncorrect, ); - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs index 3404bdfe79b..4917936a932 100644 --- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs +++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs @@ -44,11 +44,11 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) diag.note( "this returns the type id of the literal type `Box<dyn Any>` instead of the \ - type id of the boxed value, which is most likely not what you want" + type id of the boxed value, which is most likely not what you want", ) .note( "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \ - which makes it more clear" + which makes it more clear", ) .span_suggestion( receiver.span, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs new file mode 100644 index 00000000000..bb32b1bb7fc --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -0,0 +1,122 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::UNNECESSARY_FALLIBLE_CONVERSIONS; + +/// What function is being called and whether that call is written as a method call or a function +/// call +#[derive(Copy, Clone)] +#[expect(clippy::enum_variant_names)] +enum FunctionKind { + /// `T::try_from(U)` + TryFromFunction, + /// `t.try_into()` + TryIntoMethod, + /// `U::try_into(t)` + TryIntoFunction, +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'_>, + node_args: ty::GenericArgsRef<'tcx>, + kind: FunctionKind, + primary_span: Span, +) { + if let &[self_ty, other_ty] = node_args.as_slice() + // useless_conversion already warns `T::try_from(T)`, so ignore it here + && self_ty != other_ty + && let Some(self_ty) = self_ty.as_type() + && let Some(from_into_trait) = cx.tcx.get_diagnostic_item(match kind { + FunctionKind::TryFromFunction => sym::From, + FunctionKind::TryIntoMethod | FunctionKind::TryIntoFunction => sym::Into, + }) + // If `T: TryFrom<U>` and `T: From<U>` both exist, then that means that the `TryFrom` + // _must_ be from the blanket impl and cannot have been manually implemented + // (else there would be conflicting impls, even with #![feature(spec)]), so we don't even need to check + // what `<T as TryFrom<U>>::Error` is: it's always `Infallible` + && implements_trait(cx, self_ty, from_into_trait, &[other_ty]) + { + let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| { + if let ExprKind::MethodCall(path, .., span) = parent.kind + && let sym::unwrap | sym::expect = path.ident.name + { + Some(span) + } else { + None + } + }); + + let (sugg, span, applicability) = match kind { + FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => { + // Extend the span to include the unwrap/expect call: + // `foo.try_into().expect("..")` + // ^^^^^^^^^^^^^^^^^^^^^^^ + // + // `try_into().unwrap()` specifically can be trivially replaced with just `into()`, + // so that can be machine-applicable + + ( + "into()", + primary_span.with_hi(unwrap_span.hi()), + Applicability::MachineApplicable, + ) + }, + FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified), + FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified), + FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified), + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FALLIBLE_CONVERSIONS, + span, + "use of a fallible conversion when an infallible one could be used", + "use", + sugg.into(), + applicability, + ); + } +} + +/// Checks method call exprs: +/// - `0i32.try_into()` +pub(super) fn check_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(path, ..) = expr.kind { + check( + cx, + expr, + cx.typeck_results().node_args(expr.hir_id), + FunctionKind::TryIntoMethod, + path.ident.span, + ); + } +} + +/// Checks function call exprs: +/// - `<i64 as TryFrom<_>>::try_from(0i32)` +/// - `<_ as TryInto<i64>>::try_into(0i32)` +pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Expr<'_>) { + if let ExprKind::Path(ref qpath) = callee.kind + && let Some(item_def_id) = cx.qpath_res(qpath, callee.hir_id).opt_def_id() + && let Some(trait_def_id) = cx.tcx.trait_of_item(item_def_id) + { + check( + cx, + expr, + cx.typeck_results().node_args(callee.hir_id), + match cx.tcx.get_diagnostic_name(trait_def_id) { + Some(sym::TryFrom) => FunctionKind::TryFromFunction, + Some(sym::TryInto) => FunctionKind::TryIntoFunction, + _ => return, + }, + callee.span, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index 6e23754bf46..6d51c4ab054 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -8,8 +8,7 @@ use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::UNNECESSARY_FOLD; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 3e19d72ec91..a1125d70db3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -81,7 +81,7 @@ pub(super) fn check( { suggs.extend([ (block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()), - (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()) + (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()), ]); } Some(suggs) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 50d6f3b7e55..772686d93dd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,7 +1,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; @@ -382,10 +382,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Block(..) => continue, Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind - && let output_ty = return_ty(cx, item.owner_id) - && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) - && fn_ctxt.can_coerce(ty, output_ty) + && let output_ty = return_ty(cx, item.owner_id) + && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) + && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) + && fn_ctxt.can_coerce(ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { return false; @@ -393,12 +393,15 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let body = cx.tcx.hir().body(*body_id); let body_expr = &body.value; let mut count = 0; - return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 }); + return find_all_ret_expressions(cx, body_expr, |_| { + count += 1; + count <= 1 + }); } - } + }, Node::Expr(parent_expr) => { - if let Some((callee_def_id, call_generic_args, recv, call_args)) - = get_callee_generic_args_and_args(cx, parent_expr) + if let Some((callee_def_id, call_generic_args, recv, call_args)) = + get_callee_generic_args_and_args(cx, parent_expr) { // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually // call `tcx.try_instantiate_and_normalize_erasing_regions` further down @@ -420,40 +423,49 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< return false; } - let mut trait_predicates = cx.tcx.param_env(callee_def_id) - .caller_bounds().iter().filter(|predicate| { - if let ClauseKind::Trait(trait_predicate) - = predicate.kind().skip_binder() - && trait_predicate.trait_ref.self_ty() == *param_ty - { - true - } else { - false - } - }); + let mut trait_predicates = + cx.tcx + .param_env(callee_def_id) + .caller_bounds() + .iter() + .filter(|predicate| { + if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == *param_ty + { + true + } else { + false + } + }); - let new_subst = cx.tcx.mk_args_from_iter( - call_generic_args.iter() - .enumerate() - .map(|(i, t)| - if i == (*param_index as usize) { - GenericArg::from(ty) - } else { - t - })); + let new_subst = cx + .tcx + .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| { + if i == (*param_index as usize) { + GenericArg::from(ty) + } else { + t + } + })); if trait_predicates.any(|predicate| { let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); - !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) + !cx.tcx + .infer_ctxt() + .build() + .predicate_must_hold_modulo_regions(&obligation) }) { return false; } let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { - if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder::bind(output_ty)) { + if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( + new_subst, + cx.param_env, + EarlyBinder::bind(output_ty), + ) { expr = parent_expr; ty = new_ty; continue; @@ -515,10 +527,11 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) || - implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { - true - } else { - false - } + && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) + || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) + { + true + } else { + false + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs new file mode 100644 index 00000000000..da66632d55f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs @@ -0,0 +1,32 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_trait_method, match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::WAKER_CLONE_WAKE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + + if let Some(did) = ty.ty_adt_def() + && match_def_path(cx, did.did(), &paths::WAKER) + && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind + && is_trait_method(cx, recv, sym::Clone) + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, waker_ref.span.source_callsite(), "..", &mut applicability); + + span_lint_and_sugg( + cx, + WAKER_CLONE_WAKE, + expr.span, + "cloning a `Waker` only to wake it", + "replace with", + format!("{snippet}.wake_by_ref()"), + applicability, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index 1fbf783b886..0a810a13f3f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_copy; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use std::fmt; use super::WRONG_SELF_CONVENTION; diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index c79a1a7b9d4..4ad12e899fe 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -107,13 +107,17 @@ impl Visitor<'_> for IdentVisitor<'_, '_> { let str = ident.as_str(); if conf.is_ident_too_short(cx, str, ident.span) { - if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind { + if let Node::Item(item) = node + && let ItemKind::Use(..) = item.kind + { return; } // `struct Awa<T>(T)` // ^ if let Node::PathSegment(path) = node { - if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind { + if let Res::Def(def_kind, ..) = path.res + && let DefKind::TyParam = def_kind + { return; } if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local()) diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 9c8b47fb303..f4af5f37bf3 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -16,7 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use crate::ref_patterns::REF_PATTERNS; @@ -41,12 +41,12 @@ declare_clippy_lint! { /// dereferences, e.g., changing `*x` to `x` within the function. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(ref _x: u8) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(_x: &u8) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -70,7 +70,7 @@ declare_clippy_lint! { /// macro, it has been allowed in the mean time. /// /// ### Example - /// ```rust + /// ```no_run /// let _x = 0; /// let y = _x + 1; // Here we are using `_x`, even though it has a leading /// // underscore. We should rename `_x` to `x` @@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { ), |diag| { diag.span_note(definition_span, format!("`{name}` is defined here")); - } + }, ); } } 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 b226b878123..df0dd9e4e39 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -17,7 +17,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -28,7 +28,7 @@ declare_clippy_lint! { /// the fields that are actually bound. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Foo { /// # a: i32, /// # b: i32, @@ -43,7 +43,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct Foo { /// # a: i32, /// # b: i32, @@ -71,12 +71,12 @@ declare_clippy_lint! { /// It affects code readability. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(a: i32, _a: i32) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn bar(a: i32, _b: i32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -94,7 +94,7 @@ declare_clippy_lint! { /// decremented. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = 3; /// --x; /// ``` @@ -113,14 +113,14 @@ declare_clippy_lint! { /// It looks confusing. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 0x1a9BAcD /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 0x1A9BACD /// # ; @@ -142,14 +142,14 @@ declare_clippy_lint! { /// Suffix style should be consistent. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 123832i32 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 123832_i32 /// # ; @@ -170,14 +170,14 @@ declare_clippy_lint! { /// Suffix style should be consistent. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 123832_i32 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 123832i32 /// # ; @@ -202,7 +202,7 @@ declare_clippy_lint! { /// ### Example /// /// In Rust: - /// ```rust + /// ```no_run /// fn main() { /// let a = 0123; /// println!("{}", a); @@ -258,7 +258,7 @@ declare_clippy_lint! { /// bindings. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = Some("abc"); /// match v { /// Some(x) => (), @@ -267,7 +267,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let v = Some("abc"); /// match v { /// Some(x) => (), @@ -295,7 +295,7 @@ declare_clippy_lint! { /// can match that element as well. /// /// ### Example - /// ```rust + /// ```no_run /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// match t { @@ -305,7 +305,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// match t { diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index 7c4ae746e90..00f46629f10 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{Pat, PatKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::UNNEEDED_WILDCARD_PATTERN; diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs index 28e041dee0d..0d79ece087f 100644 --- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs +++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ignored. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo<A, B> { /// x: A, /// y: B, @@ -33,7 +33,7 @@ declare_clippy_lint! { /// impl<B, A> Foo<B, A> {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Foo<A, B> { /// x: A, /// y: B, diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs index 136947a2c8c..4e00215c5cb 100644 --- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs +++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs @@ -27,14 +27,14 @@ declare_clippy_lint! { /// don't provide any extra information. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Service { ready: bool } /// fn call(service: Service) { /// assert!(service.ready); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct Service { ready: bool } /// fn call(service: Service) { /// assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests"); diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 08fec2b8ec8..dccf72d3c84 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -43,14 +43,14 @@ declare_clippy_lint! { /// about the length of a slice, but this lint will not detect that. /// /// ### Example - /// ```rust + /// ```no_run /// fn sum(v: &[u8]) -> u8 { /// // 4 bounds checks /// v[0] + v[1] + v[2] + v[3] /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn sum(v: &[u8]) -> u8 { /// assert!(v.len() > 4); /// // no bounds checks @@ -200,9 +200,13 @@ impl<'hir> IndexEntry<'hir> { /// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`, /// for `..=5` this returns `Some(5)` fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> { - if let ExprKind::Lit(lit) = &expr.kind && let LitKind::Int(index, _) = lit.node { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(index, _) = lit.node + { Some(index as usize) - } else if let Some(higher::Range { end: Some(end), limits, .. }) = higher::Range::hir(expr) + } else if let Some(higher::Range { + end: Some(end), limits, .. + }) = higher::Range::hir(expr) && let ExprKind::Lit(lit) = &end.kind && let LitKind::Int(index @ 1.., _) = lit.node { @@ -228,7 +232,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh if let Some(entry) = entry { match entry { - IndexEntry::StrayAssert { asserted_len, comparison, assert_span, slice } => { + IndexEntry::StrayAssert { + asserted_len, + comparison, + assert_span, + slice, + } => { *entry = IndexEntry::AssertWithIndex { highest_index: index, asserted_len: *asserted_len, @@ -238,8 +247,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh comparison: *comparison, }; }, - IndexEntry::IndexWithoutAssert { highest_index, indexes, .. } - | IndexEntry::AssertWithIndex { highest_index, indexes, .. } => { + IndexEntry::IndexWithoutAssert { + highest_index, indexes, .. + } + | IndexEntry::AssertWithIndex { + highest_index, indexes, .. + } => { indexes.push(expr.span); *highest_index = (*highest_index).max(index); }, diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index f598a65d2e4..97522cbe6ce 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// Also, the lint only runs one pass over the code. Consider these two non-const functions: /// - /// ```rust + /// ```no_run /// fn a() -> i32 { /// 0 /// } @@ -42,7 +42,7 @@ declare_clippy_lint! { /// /// If you are marking a public function with `const`, removing it again will break API compatibility. /// ### Example - /// ```rust + /// ```no_run /// # struct Foo { /// # random_number: usize, /// # } @@ -55,7 +55,7 @@ declare_clippy_lint! { /// /// Could be a const fn: /// - /// ```rust + /// ```no_run /// # struct Foo { /// # random_number: usize, /// # } diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 0629dee4f72..973caa72b77 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -16,8 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs index fc088710e42..16ff98a5922 100644 --- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs +++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,6 +1,6 @@ +use clippy_config::types::Rename; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; - use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -10,8 +10,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; -use crate::utils::conf::Rename; - declare_clippy_lint! { /// ### What it does /// Checks for imports that do not rename the item as specified diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index d205237a591..95f9df4e42a 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// making it much less likely to accidentally forget to update the `Debug` impl when adding a new variant. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt; /// struct Foo { /// data: String, @@ -57,7 +57,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// struct Foo { /// data: String, diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 93f6025c71d..b815da79b69 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -3,8 +3,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -21,7 +20,7 @@ declare_clippy_lint! { /// then opt out for specific methods where this might not make sense. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn foo() {} // missing #[inline] /// fn ok() {} // ok /// #[inline] pub fn bar() {} // ok diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 1adecd2caac..ad5f45a3280 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Indicates that a method is missing. /// /// ### Example - /// ```rust + /// ```no_run /// trait Trait { /// fn required(); /// @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// trait Trait { /// fn required(); /// diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index e87aea263d4..215161b04c7 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// order, or which is correct for any evaluation order. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = 0; /// /// let a = { @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut x = 0; /// let tmp = { /// x = 1; diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs index 81eb1a085ae..b42dce7a13a 100644 --- a/src/tools/clippy/clippy_lints/src/multi_assignments.rs +++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs @@ -13,12 +13,12 @@ declare_clippy_lint! { /// where such assignments return a copy of the assigned value. /// /// ### Example - /// ```rust + /// ```no_run ///# let (a, b); /// a = b = 42; /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# let (a, b); /// b = 42; /// a = b; diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 2c42a7a3676..d4f8008aece 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// elimination of unnecessary unsafe blocks through refactoring. /// /// ### Example - /// ```rust + /// ```no_run /// /// Reads a `char` from the given pointer. /// /// /// /// # Safety @@ -36,7 +36,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// /// Reads a `char` from the given pointer. /// /// /// /// # Safety diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 5878f899541..ebfd53f1ee9 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -8,7 +8,7 @@ use rustc_middle::query::Key; use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::sym; use std::iter; @@ -47,7 +47,7 @@ declare_clippy_lint! { /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745). /// /// ### Example - /// ```rust + /// ```no_run /// use std::cmp::{PartialEq, Eq}; /// use std::collections::HashSet; /// use std::hash::{Hash, Hasher}; diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 64d8333a093..6989504a4a9 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// misunderstanding of references. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut y = 1; /// let x = &mut &mut y; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 01b850cdb11..4f8e244222d 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// the value. Also the code misleads about the intent of the call site. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut vec = Vec::new(); /// # let mut value = 5; /// vec.push(&mut value); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut vec = Vec::new(); /// # let value = 5; /// vec.push(&value); diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 99394b9e5fb..9d8c06cd077 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// for waiting before a critical section. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = true; /// # use std::sync::Mutex; /// let x = Mutex::new(&y); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = true; /// # use std::sync::atomic::AtomicBool; /// let x = AtomicBool::new(y); @@ -62,13 +62,13 @@ declare_clippy_lint! { /// for waiting before a critical section. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::atomic::AtomicUsize; /// let x = AtomicUsize::new(0usize); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 5457eeec4ea..97e8f1c030a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Increases the amount and decreases the readability of code /// /// ### Example - /// ```rust + /// ```no_run /// enum ValType { /// I32, /// I64, @@ -35,7 +35,7 @@ declare_clippy_lint! { /// /// Could be rewritten as /// - /// ```rust + /// ```no_run /// enum ValType { /// I32, /// I64, diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index f6b87b071b9..02c177c9227 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// shorter code. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = true; /// if x { /// false @@ -43,7 +43,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = true; /// !x /// # ; @@ -207,9 +207,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { _ => (), } } - if let Some((lhs_a, a)) = fetch_assign(then) && - let Some((lhs_b, b)) = fetch_assign(r#else) && - SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) + if let Some((lhs_a, a)) = fetch_assign(then) + && let Some((lhs_b, b)) = fetch_assign(r#else) + && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); @@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { "this if-then-else expression assigns a bool literal", "you can reduce it to", sugg, - applicability + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs index 11bf9e9ca17..fdb91f0dc0d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// This pattern has no effect in almost all cases. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = Vec::<String>::new(); /// v.iter_mut().filter(|&ref a| a.is_empty()); /// @@ -21,7 +21,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut v = Vec::<String>::new(); /// v.iter_mut().filter(|a| a.is_empty()); /// diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index d55c77a92b1..dcfb109a4c4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_copy; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; @@ -36,7 +36,7 @@ declare_clippy_lint! { /// in such a case can change the semantics of the code. /// /// ### Example - /// ```rust + /// ```no_run /// fn f(_: impl AsRef<str>) {} /// /// let x = "foo"; @@ -44,7 +44,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn f(_: impl AsRef<str>) {} /// /// let x = "foo"; @@ -87,18 +87,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { && let ty::Param(ty) = *ty.value.skip_binder().kind() && let Some((hir_id, fn_id, i)) = match use_cx.node { ExprUseNode::MethodArg(_, _, 0) => None, - ExprUseNode::MethodArg(hir_id, None, i) => { - cx.typeck_results().type_dependent_def_id(hir_id).map(|id| (hir_id, id, i)) - }, - ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i) - if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) { - Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => { - Some((hir_id, id, i)) + ExprUseNode::MethodArg(hir_id, None, i) => cx + .typeck_results() + .type_dependent_def_id(hir_id) + .map(|id| (hir_id, id, i)), + ExprUseNode::FnArg( + &Expr { + kind: ExprKind::Path(ref p), + hir_id, + .. }, + i, + ) if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) { + Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => Some((hir_id, id, i)), _ => None, }, _ => None, - } && let count = needless_borrow_count( + } + && let count = needless_borrow_count( cx, &mut self.possible_borrowers, fn_id, @@ -107,7 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { ty, expr, &self.msrv, - ) && count != 0 + ) + && count != 0 { span_lint_and_then( cx, @@ -119,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { let snip_span = peel_n_hir_expr_refs(expr, count).0.span; let snip = snippet_with_context(cx, snip_span, expr.span.ctxt(), "..", &mut app).0; diag.span_suggestion(expr.span, "change this to", snip.into_owned(), app); - } + }, ); } } @@ -245,7 +252,9 @@ fn needless_borrow_count<'tcx>( predicates.iter().all(|predicate| { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) + && cx + .tcx + .is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack() && ty.is_array() @@ -308,13 +317,13 @@ fn is_mixed_projection_predicate<'tcx>( match projection_ty.self_ty().kind() { ty::Alias(ty::Projection, inner_projection_ty) => { projection_ty = *inner_projection_ty; - } + }, ty::Param(param_ty) => { return (param_ty.index as usize) >= generics.parent_count; - } + }, _ => { return false; - } + }, } } } else { diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 377cbef7b99..cb2738947d4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -55,7 +55,7 @@ declare_clippy_lint! { /// statement within the THEN block and omitting the else block completely. /// /// ### Example - /// ```rust + /// ```no_run /// # fn condition() -> bool { false } /// # fn update_condition() {} /// # let x = false; @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// Could be rewritten as /// - /// ```rust + /// ```no_run /// # fn condition() -> bool { false } /// # fn update_condition() {} /// # let x = false; @@ -87,7 +87,7 @@ declare_clippy_lint! { /// /// As another example, the following code /// - /// ```rust + /// ```no_run /// # fn waiting() -> bool { false } /// loop { /// if waiting() { @@ -100,7 +100,7 @@ declare_clippy_lint! { /// ``` /// Could be rewritten as /// - /// ```rust + /// ```no_run /// # fn waiting() -> bool { false } /// loop { /// if waiting() { @@ -408,7 +408,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { /// till a non-whitespace character is found. e.g., the string. If no closing `}` is present, the /// string will be preserved. /// -/// ```rust +/// ```no_run /// { /// let x = 5; /// } diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs index 0c1fe881fc1..d881c13f84a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_else.rs +++ b/src/tools/clippy/clippy_lints/src/needless_else.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// An empty else branch does nothing and can be removed. /// /// ### Example - /// ```rust + /// ```no_run ///# fn check() -> bool { true } /// if check() { /// println!("Check successful!"); @@ -21,7 +21,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# fn check() -> bool { true } /// if check() { /// println!("Check successful!"); diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 98bf122fab7..c71996131db 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -3,8 +3,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, Span, Symbol}; use if_chain::if_chain; @@ -25,14 +24,14 @@ declare_clippy_lint! { /// But when none of these apply, a simple `for` loop is more idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![0, 1, 2]; /// v.iter().for_each(|elem| { /// println!("{}", elem); /// }) /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let v = vec![0, 1, 2]; /// for elem in v.iter() { /// println!("{}", elem); diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 948454d13ae..c8888c744b6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// Assigning in the `let` statement is less repetitive. /// /// ### Example - /// ```rust + /// ```no_run /// let a; /// a = 1; /// @@ -41,7 +41,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = 1; /// /// let b = match 3 { diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs index d17a383e882..7bbf1fb4cd9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// for i in (0)..10 { /// println!("{i}"); /// } @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// for i in 0..10 { /// println!("{i}"); /// } @@ -46,9 +46,9 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool { } fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { - if is_start && - let ExprKind::Lit(literal) = e.kind && - let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node + if is_start + && let ExprKind::Lit(literal) = e.kind + && let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node { // don't check floating point literals on the start expression of a range return; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 1d5874f6fea..d610ba520a4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -37,13 +37,13 @@ declare_clippy_lint! { /// opportunities for parallelization. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(y: &mut i32) -> i32 { /// 12 + *y /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(y: &i32) -> i32 { /// 12 + *y /// } @@ -225,7 +225,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind && !mutably_used_vars.contains(&canonical_id) { - self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input); + self.fn_def_ids_to_maybe_unused_mut + .entry(fn_def_id) + .or_default() + .push(input); } } } @@ -520,7 +523,11 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> { // #11182; do not lint if mutability is required elsewhere if let Node::Expr(expr) = cx.tcx.hir().get(hir_id) && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) - && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind() + && let ty::FnDef(def_id, _) = cx + .tcx + .typeck(cx.tcx.hir().enclosing_body_owner(hir_id)) + .expr_ty(expr) + .kind() && let Some(def_id) = def_id.as_local() { if let Node::Expr(e) = parent diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index f3c0d616473..8fa461ac12c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -43,13 +43,13 @@ declare_clippy_lint! { /// (by using `Borrow` trait, for example), depending on how the function is used. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(v: Vec<i32>) { /// assert_eq!(v.len(), 42); /// } /// ``` /// should be - /// ```rust + /// ```no_run /// fn foo(v: &[i32]) { /// assert_eq!(v.len(), 42); /// } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index b3a2060d6ac..074c9fef1b2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -16,7 +16,7 @@ declare_clippy_lint! { /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// /// ### Example - /// ```rust + /// ```no_run /// struct TO { /// magic: Option<usize>, /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct TO { /// magic: Option<usize>, /// } diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index 0bd29d1776b..f8888d36878 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// somewhere), and make the code less readable. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Point { /// # x: i32, /// # y: i32, diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index a022fc156fc..56c67406d6f 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// especially easy to miss if the operator based comparison result is negated. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 1.0; /// let b = f64::NAN; /// @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::cmp::Ordering; /// # let a = 1.0; /// # let b = f64::NAN; diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index db0e22842d1..8b69f94cbba 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index aee184252fb..3a28e511fdd 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// 0; /// ``` #[clippy::version = "pre 1.29.0"] @@ -103,11 +103,16 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { && final_stmt.hir_id == stmt.hir_id { let expr_ty = cx.typeck_results().expr_ty(expr); - let mut ret_ty = cx.tcx.fn_sig(item.owner_id).instantiate_identity().output().skip_binder(); + let mut ret_ty = cx + .tcx + .fn_sig(item.owner_id) + .instantiate_identity() + .output() + .skip_binder(); // Remove `impl Future<Output = T>` to get `T` - if cx.tcx.ty_is_opaque_future(ret_ty) && - let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + if cx.tcx.ty_is_opaque_future(ret_ty) + && let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index 8fd9ae351a0..04d75014892 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// Rust ABI can break this at any point. /// /// ### Example - /// ```rust + /// ```no_run /// #[no_mangle] /// fn example(arg_one: u32, arg_two: usize) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[no_mangle] /// extern "C" fn example(arg_one: u32, arg_two: usize) {} /// ``` @@ -48,7 +48,8 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { && let Some((fn_attrs, _)) = snippet.split_once("fn") && !fn_attrs.contains("extern") { - let sugg_span = fn_sig.span + let sugg_span = fn_sig + .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 0e4b6aa1b7d..9689f63a013 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { /// in `Some`. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); @@ -84,7 +84,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); @@ -131,12 +131,7 @@ impl LateLintPass<'_> for NonCanonicalImpls { if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) - && implements_trait( - cx, - trait_impl.self_ty(), - copy_def_id, - &[], - ) + && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[]) { if impl_item.ident.name == sym::clone { if block.stmts.is_empty() @@ -144,7 +139,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { && let ExprKind::Unary(UnOp::Deref, deref) = expr.kind && let ExprKind::Path(qpath) = deref.kind && last_path_segment(&qpath).ident.name == kw::SelfLower - {} else { + { + } else { span_lint_and_sugg( cx, NON_CANONICAL_CLONE_IMPL, @@ -197,10 +193,13 @@ impl LateLintPass<'_> for NonCanonicalImpls { && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) // Fix #11178, allow `Self::cmp(self, ..)` too && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified) - {} else { + { + } else { // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid // suggestion tons more complex. - if let [lhs, rhs, ..] = trait_impl.args.as_slice() && lhs != rhs { + if let [lhs, rhs, ..] = trait_impl.args.as_slice() + && lhs != rhs + { return; } @@ -238,12 +237,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { ], }; - diag.multipart_suggestion( - "change this to", - suggs, - Applicability::Unspecified, - ); - } + diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 613afa46a91..54cec066ba1 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -58,7 +58,7 @@ declare_clippy_lint! { /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); @@ -67,7 +67,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); /// STATIC_ATOM.store(9, SeqCst); @@ -105,7 +105,7 @@ declare_clippy_lint! { /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// @@ -114,7 +114,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index d562047cbf1..61622034d1a 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -6,8 +6,7 @@ use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use rustc_span::symbol::{Ident, Symbol}; use std::cmp::Ordering; @@ -63,7 +62,7 @@ declare_clippy_lint! { /// descriptive name. /// /// ### Example - /// ```rust + /// ```no_run /// let _1 = 1; /// let ___1 = 1; /// let __1___2 = 11; diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index bd194b93584..11c3a5417b5 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,6 +1,4 @@ -use std::fmt; -use std::hash::{Hash, Hasher}; - +use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; @@ -12,7 +10,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; -use serde::{de, Deserialize}; declare_clippy_lint! { /// ### What it does @@ -23,11 +20,11 @@ declare_clippy_lint! { /// doesn't give you a semicolon in item position, which can be unexpected. /// /// ### Example - /// ```rust + /// ```no_run /// vec!{1, 2, 3}; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3]; /// ``` #[clippy::version = "1.55.0"] @@ -36,8 +33,6 @@ declare_clippy_lint! { "check consistent use of braces in macro" } -const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")]; - /// The (callsite span, (open brace, close brace), source snippet) type MacroInfo<'a> = (Span, &'a (String, String), String); @@ -195,81 +190,3 @@ macro_rules! macro_matcher { }; } pub(crate) use macro_matcher; - -#[derive(Clone, Debug)] -pub struct MacroMatcher { - name: String, - braces: (String, String), -} - -impl Hash for MacroMatcher { - fn hash<H: Hasher>(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl PartialEq for MacroMatcher { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} -impl Eq for MacroMatcher {} - -impl<'de> Deserialize<'de> for MacroMatcher { - fn deserialize<D>(deser: D) -> Result<Self, D::Error> - where - D: de::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(field_identifier, rename_all = "lowercase")] - enum Field { - Name, - Brace, - } - struct MacVisitor; - impl<'de> de::Visitor<'de> for MacVisitor { - type Value = MacroMatcher; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("struct MacroMatcher") - } - - fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> - where - V: de::MapAccess<'de>, - { - let mut name = None; - let mut brace: Option<String> = None; - while let Some(key) = map.next_key()? { - match key { - Field::Name => { - if name.is_some() { - return Err(de::Error::duplicate_field("name")); - } - name = Some(map.next_value()?); - }, - Field::Brace => { - if brace.is_some() { - return Err(de::Error::duplicate_field("brace")); - } - brace = Some(map.next_value()?); - }, - } - } - let name = name.ok_or_else(|| de::Error::missing_field("name"))?; - let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?; - Ok(MacroMatcher { - name, - braces: BRACES - .iter() - .find(|b| b.0 == brace) - .map(|(o, c)| ((*o).to_owned(), (*c).to_owned())) - .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, - }) - } - } - - const FIELDS: &[&str] = &["name", "brace"]; - deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor) - } -} diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 6d3865080a6..0faf4ce3d3e 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -32,13 +32,13 @@ declare_clippy_lint! { /// can see it. /// /// ### Example - /// ```rust + /// ```no_run /// let one = "\033[1m Bold? \033[0m"; // \033 intended as escape /// let two = "\033\0"; // \033 intended as null-3-3 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let one = "\x1b[1mWill this be bold?\x1b[0m"; /// let two = "\x0033\x00"; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index f0f8d510c7e..ef7b367649f 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// In some cases, this would not catch all useless arguments. /// - /// ```rust + /// ```no_run /// fn foo(a: usize, b: usize) -> usize { /// let f = |x| x + 1; /// @@ -53,7 +53,7 @@ declare_clippy_lint! { /// Also, when you recurse the function name with path segments, it is not possible to detect. /// /// ### Example - /// ```rust + /// ```no_run /// fn f(a: usize, b: usize) -> usize { /// if a == 0 { /// 1 @@ -66,7 +66,7 @@ declare_clippy_lint! { /// # } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn f(a: usize) -> usize { /// if a == 0 { /// 1 @@ -244,7 +244,10 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { })) => { #[allow(trivial_casts)] if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into()) - && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity) + && let Some(trait_ref) = cx + .tcx + .impl_trait_ref(item.owner_id) + .map(EarlyBinder::instantiate_identity) && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id { ( @@ -288,8 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { // Recursive call. Track which index the parameter is used in. ExprKind::Call(callee, args) if path_def_id(cx, callee).map_or(false, |id| { - id == param.fn_id - && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) + id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) }) => { if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) { @@ -299,8 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { }, ExprKind::MethodCall(_, receiver, args, _) if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { - id == param.fn_id - && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) + id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) }) => { if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) { @@ -336,8 +337,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { // Only allow field accesses without auto-deref ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => { e = parent; - continue - } + continue; + }, _ => (), }, _ => (), diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index a10aa65e594..f7d9650b2f8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -7,9 +7,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::{Span, Symbol}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::Symbol; use {rustc_ast as ast, rustc_hir as hir}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]]; @@ -71,7 +71,7 @@ impl ArithmeticSideEffects { rhs_has_allowed_ty || rhs_from_specific.contains("*") } { - true + true } else if let Some(rhs_from_glob) = self.allowed_binary.get("*") { rhs_from_glob.contains(rhs_ty_string_elem) } else { @@ -144,8 +144,10 @@ impl ArithmeticSideEffects { /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`, fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> { let actual = peel_hir_expr_unary(expr).0; - if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { - return Some(n) + if let hir::ExprKind::Lit(lit) = actual.kind + && let ast::LitKind::Int(n, _) = lit.node + { + return Some(n); } if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); @@ -317,7 +319,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind { let body_span = cx.tcx.hir().span_with_body(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { + if let Some(span) = self.const_span + && span.contains(body_span) + { return; } self.const_span = Some(body_span); @@ -327,7 +331,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { let body_owner = cx.tcx.hir().body_owner(body.id()); let body_span = cx.tcx.hir().span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { + if let Some(span) = self.const_span + && span.contains(body_span) + { return; } self.const_span = None; diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index c146f3ae95b..2e026c369ee 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::{BAD_BIT_MASK, INEFFECTIVE_BIT_MASK}; diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs index abe8df19543..ec2bb869973 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -8,7 +8,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::Span; +use rustc_span::source_map::Spanned; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; diff --git a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs index 56a86d0ffa2..d48e8286f2c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::DOUBLE_COMPARISONS; diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs index 88d56631841..fd3502ad878 100644 --- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs @@ -8,13 +8,14 @@ use rustc_lint::LateContext; use super::EQ_OP; pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let Some((macro_call, macro_name)) - = first_node_macro_backtrace(cx, e).find_map(|macro_call| { - let name = cx.tcx.item_name(macro_call.def_id); - matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne") - .then(|| (macro_call, name)) - }) - && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) + if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { + let name = cx.tcx.item_name(macro_call.def_id); + matches!( + name.as_str(), + "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" + ) + .then(|| (macro_call, name)) + }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) && eq_expr_value(cx, lhs, rhs) && macro_call.is_local() && !is_in_test_function(cx.tcx, e.hir_id) @@ -42,7 +43,9 @@ pub(crate) fn check<'tcx>( e.span, &format!("equal expressions as operands to `{}`", op.as_str()), |diag| { - if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() { + if let BinOpKind::Ne = op + && cx.typeck_results().expr_ty(left).is_floating_point() + { diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead"); } }, diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs index 14a12da862e..8ecb038627f 100644 --- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::Span; use super::IDENTITY_OP; diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 6b247cf5f6a..ee79ea27689 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -48,7 +48,7 @@ declare_clippy_lint! { /// like `#[cfg(target_pointer_width = "64")] ..` instead. /// /// ### Example - /// ```rust + /// ```no_run /// let vec: Vec<isize> = Vec::new(); /// if vec.len() <= 0 {} /// if 100 > i32::MAX {} @@ -76,7 +76,7 @@ declare_clippy_lint! { /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. /// /// #### Example - /// ```rust + /// ```no_run /// // `n` can be any number, including `i32::MAX`. /// fn foo(n: i32) -> i32 { /// n + 1 @@ -105,7 +105,7 @@ declare_clippy_lint! { /// can be useful to rule out floating-point numbers. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 0.0; /// a + 1.0; /// ``` @@ -128,7 +128,7 @@ declare_clippy_lint! { /// implementations that differ from the regular `Op` impl. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 0; /// // ... @@ -137,7 +137,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 0; /// // ... @@ -165,7 +165,7 @@ declare_clippy_lint! { /// written as `a = a op a op b` as it's less confusing. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 2; /// // ... @@ -205,7 +205,7 @@ declare_clippy_lint! { /// test-case for this lint. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if (x & 1 == 2) { } /// ``` @@ -238,7 +238,7 @@ declare_clippy_lint! { /// uncommon). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if (x | 1 > 3) { } /// ``` @@ -261,7 +261,7 @@ declare_clippy_lint! { /// llvm generates better code for `x & 15 == 0` on x86 /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` @@ -280,7 +280,7 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 2; /// if x == y || x < y {} @@ -288,7 +288,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 2; /// if x <= y {} @@ -308,7 +308,7 @@ declare_clippy_lint! { /// which is probably not the programmer's intention /// /// ### Example - /// ```rust + /// ```no_run /// # let status_code = 200; /// if status_code <= 400 && status_code > 500 {} /// ``` @@ -328,7 +328,7 @@ declare_clippy_lint! { /// different value entirely. /// /// ### Example - /// ```rust + /// ```no_run /// # let status_code = 200; /// if status_code <= 400 && status_code < 500 {} /// ``` @@ -348,7 +348,7 @@ declare_clippy_lint! { /// `Duration::subsec_millis()` than to calculate them. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::time::Duration; /// # let duration = Duration::new(5, 0); /// let micros = duration.subsec_nanos() / 1_000; @@ -356,7 +356,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::time::Duration; /// # let duration = Duration::new(5, 0); /// let micros = duration.subsec_micros(); @@ -384,7 +384,7 @@ declare_clippy_lint! { /// calls. We may introduce a list of known pure functions in the future. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if x + 1 == x + 1 {} /// @@ -434,7 +434,7 @@ declare_clippy_lint! { /// corrected /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1; /// 0 / x; /// 0 * x; @@ -462,13 +462,13 @@ declare_clippy_lint! { /// with an allow. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { /// (a - b) < f32::EPSILON /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { /// (a - b).abs() < f32::EPSILON /// } @@ -488,7 +488,7 @@ declare_clippy_lint! { /// meaning. So it just obscures what's going on. Delete it mercilessly. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// x / 1 + 0 * 1 - 0 | 0; /// ``` @@ -508,13 +508,13 @@ declare_clippy_lint! { /// remainder. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 3 / 2; /// println!("{}", x); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = 3f32 / 2f32; /// println!("{}", x); /// ``` @@ -535,14 +535,14 @@ declare_clippy_lint! { /// needlessly consuming code and heap space. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = "foo"; /// # let y = String::from("foo"); /// if x.to_owned() == y {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = "foo"; /// # let y = String::from("foo"); /// if x == y {} @@ -566,7 +566,7 @@ declare_clippy_lint! { /// guide](http://www.floating-point-gui.de/errors/comparison). /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1.2331f64; /// let y = 1.2332f64; /// @@ -575,7 +575,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.2331f64; /// # let y = 1.2332f64; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison @@ -603,7 +603,7 @@ declare_clippy_lint! { /// guide](http://www.floating-point-gui.de/errors/comparison). /// /// ### Example - /// ```rust + /// ```no_run /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; /// @@ -611,7 +611,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x: f64 = 1.0; /// # const ONE: f64 = 1.00; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison @@ -638,7 +638,7 @@ declare_clippy_lint! { /// contest, it's probably a bad idea. Use something more underhanded. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// let a = x % 1; /// let a = x % -1; @@ -662,7 +662,7 @@ declare_clippy_lint! { /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = -17 % 3; /// ``` #[clippy::version = "1.42.0"] @@ -685,12 +685,12 @@ declare_clippy_lint! { /// determination is quite conservative. /// /// ### Example - /// ```rust + /// ```no_run /// let (x,y) = (true, false); /// if x & !y {} // where both x and y are booleans /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let (x,y) = (true, false); /// if x && !y {} /// ``` @@ -710,14 +710,14 @@ declare_clippy_lint! { /// comparing the values they point to. /// /// ### Example - /// ```rust + /// ```no_run /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; /// /// assert!(a as *const _ as usize == b as *const _ as usize); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; /// @@ -742,7 +742,7 @@ declare_clippy_lint! { /// indexing operations they are assumed not to have any side effects. /// /// ### Example - /// ```rust + /// ```no_run /// struct Event { /// x: i32, /// } @@ -753,7 +753,7 @@ declare_clippy_lint! { /// ``` /// /// Should be: - /// ```rust + /// ```no_run /// struct Event { /// x: i32, /// } diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 80389cbf84b..ea933168cfd 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; #[derive(Default)] pub struct Context { diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs index 9c7f7e1cd7f..7792efe6acd 100644 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs @@ -46,16 +46,19 @@ impl EarlyLintPass for OptionEnvUnwrap { ); } - if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind && - matches!(seg.ident.name, sym::expect | sym::unwrap) { - if let ExprKind::Call(caller, _) = &receiver.kind && + if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind + && matches!(seg.ident.name, sym::expect | sym::unwrap) + { + if let ExprKind::Call(caller, _) = &receiver.kind && // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() { - lint(cx, expr.span); - } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() { - lint(cx, expr.span); - } - } + is_direct_expn_of(caller.span, "option_env").is_some() + { + lint(cx, expr.span); + } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) + is_direct_expn_of(caller.span, "option_env").is_some() + { + lint(cx, expr.span); + } + } } } 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 a7a7f4fd8fa..d7cbbe13a26 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 @@ -32,7 +32,7 @@ declare_clippy_lint! { /// this lint will not be raised. /// /// ### Example - /// ```rust + /// ```no_run /// # let optional: Option<u32> = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = if let Some(foo) = optional { @@ -54,7 +54,7 @@ declare_clippy_lint! { /// /// should be /// - /// ```rust + /// ```no_run /// # let optional: Option<u32> = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = optional.map_or(5, |foo| foo); @@ -165,6 +165,12 @@ fn try_get_option_occurrence<'tcx>( } let mut app = Applicability::Unspecified; + + let (none_body, is_argless_call) = match none_body.kind { + ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true), + _ => (none_body, false), + }; + return Some(OptionOccurrence { option: format_option_in_sugg( Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), @@ -178,7 +184,7 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "}, + if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "}, Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), ), }); @@ -234,7 +240,7 @@ fn try_convert_match<'tcx>( if let [first_arm, second_arm] = arms && first_arm.guard.is_none() && second_arm.guard.is_none() - { + { return if is_none_or_err_arm(cx, second_arm) { Some((first_arm.pat, first_arm.body, second_arm.body)) } else if is_none_or_err_arm(cx, first_arm) { diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs index 6dabbd48031..38cd5043adc 100644 --- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs +++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// a + b < a; diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index a049427d85d..6a760f9fe64 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -22,14 +22,14 @@ declare_clippy_lint! { /// Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. /// /// ### Example - /// ```rust + /// ```no_run /// fn result_with_panic() -> Result<bool, String> /// { /// panic!("error"); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn result_without_panic() -> Result<bool, String> { /// Err(String::from("error")) /// } diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index a72aefe91c1..f4f1f6ddb3f 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// Checks for usage of `panic!`. /// /// ### Why is this bad? - /// `panic!` will stop the execution of the executable + /// `panic!` will stop the execution of the executable. /// /// ### Example /// ```no_run @@ -26,7 +26,7 @@ declare_clippy_lint! { /// Checks for usage of `unimplemented!`. /// /// ### Why is this bad? - /// This macro should not be present in production code + /// This macro should not be present in production code. /// /// ### Example /// ```no_run @@ -43,12 +43,17 @@ declare_clippy_lint! { /// Checks for usage of `todo!`. /// /// ### Why is this bad? - /// This macro should not be present in production code + /// The `todo!` macro is often used for unfinished code, and it causes + /// code to panic. It should not be present in production code. /// /// ### Example /// ```no_run /// todo!(); /// ``` + /// Finish the implementation, or consider marking it as explicitly unimplemented. + /// ```no_run + /// unimplemented!(); + /// ``` #[clippy::version = "1.40.0"] pub TODO, restriction, @@ -60,7 +65,7 @@ declare_clippy_lint! { /// Checks for usage of `unreachable!`. /// /// ### Why is this bad? - /// This macro can cause code to panic + /// This macro can cause code to panic. /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs index f60d9d65b12..99ba55b6b31 100644 --- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs +++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// * Data: relatively simple objects which group a bunch of related attributes together. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct Color { /// pub r: u8, /// pub g: u8, @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub struct Color { /// pub r: u8, /// pub g: u8, diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index a8c4823fe53..68d3d00ac16 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// re-implement it. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// /// impl PartialEq for Foo { diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs index d9f5d1642d7..11e9a2bc394 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// way relies on `T: PartialEq` to do the comparison, which is unneeded. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(f: Option<u32>) -> &'static str { /// if f != None { "yay" } else { "nay" } /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(f: Option<u32>) -> &'static str { /// if f.is_some() { "yay" } else { "nay" } /// } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 41513647f05..4d7a055dae1 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -58,12 +58,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// fn foo(v: &u32) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(v: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -86,7 +86,7 @@ declare_clippy_lint! { /// `memcpy`, which can be expensive. /// /// ### Example - /// ```rust + /// ```no_run /// #[derive(Clone, Copy)] /// struct TooLarge([u8; 2048]); /// @@ -94,7 +94,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[derive(Clone, Copy)] /// # struct TooLarge([u8; 2048]); /// fn foo(v: &TooLarge) {} @@ -208,7 +208,10 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size), + &format!( + "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", + self.ref_min_size + ), "consider passing by value instead", value_type, Applicability::Unspecified, diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 9f98195d311..dcd1e7af0c2 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs index f3089d716ff..b98005d5922 100644 --- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs +++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// On Unix platforms this results in the file being world writable, /// equivalent to `chmod a+w <file>`. /// ### Example - /// ```rust + /// ```no_run /// use std::fs::File; /// let f = File::create("foo.txt").unwrap(); /// let metadata = f.metadata().unwrap(); @@ -43,9 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { "call to `set_readonly` with argument `false`", |diag| { diag.note("on Unix platforms this results in the file being world writable"); - diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\ - https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html"); - } + diag.help( + "you can set the desired permissions using `PermissionsExt`. For more information, see\n\ + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html", + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 310051efc50..83863b92caf 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -21,8 +21,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; use rustc_span::symbol::Symbol; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -289,10 +288,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | sym::ptr_write_volatile | sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut => &[0], - sym::ptr_copy - | sym::ptr_copy_nonoverlapping - | sym::ptr_swap - | sym::ptr_swap_nonoverlapping => &[0, 1], + sym::ptr_copy | sym::ptr_copy_nonoverlapping | sym::ptr_swap | sym::ptr_swap_nonoverlapping => &[0, 1], _ => return, }; @@ -416,7 +412,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -438,104 +433,93 @@ fn check_fn_args<'cx, 'tcx: 'cx>( && let [.., name] = path.segments && cx.tcx.item_name(adt.did()) == name.ident.name { - let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); - let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { - Some(sym::Vec) => ( - [("clone", ".to_owned()")].as_slice(), - DerefTy::Slice( - name.args - .and_then(|args| args.args.first()) - .and_then(|arg| if let GenericArg::Type(ty) = arg { - Some(ty.span) - } else { - None - }), - args.type_at(0), - ), - ), - _ if Some(adt.did()) == cx.tcx.lang_items().string() => ( - [("clone", ".to_owned()"), ("as_str", "")].as_slice(), - DerefTy::Str, - ), - Some(sym::PathBuf) => ( - [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), - DerefTy::Path, - ), - Some(sym::Cow) if mutability == Mutability::Not => { - if let Some((lifetime, ty)) = name.args - .and_then(|args| { - if let [GenericArg::Lifetime(lifetime), ty] = args.args { - return Some((lifetime, ty)); - } + let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); + let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Vec) => ( + [("clone", ".to_owned()")].as_slice(), + DerefTy::Slice( + name.args.and_then(|args| args.args.first()).and_then(|arg| { + if let GenericArg::Type(ty) = arg { + Some(ty.span) + } else { None - }) - { - if !lifetime.is_anonymous() - && fn_sig.output() - .walk() - .filter_map(|arg| { - arg.as_region().and_then(|lifetime| { - match lifetime.kind() { - ty::ReEarlyBound(r) => Some(r.def_id), - ty::ReLateBound(_, r) => r.kind.get_id(), - ty::ReFree(r) => r.bound_region.get_id(), - ty::ReStatic - | ty::ReVar(_) - | ty::RePlaceholder(_) - | ty::ReErased - | ty::ReError(_) => None, - } - }) - }) - .any(|def_id| { - matches!( - lifetime.res, - LifetimeName::Param(param_def_id) if def_id - .as_local() - .is_some_and(|def_id| def_id == param_def_id), - ) - }) - { - // `&Cow<'a, T>` when the return type uses 'a is okay - return None; } - - let ty_name = - snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); - - span_lint_hir_and_then( - cx, - PTR_ARG, - emission_id, - hir_ty.span, - "using a reference to `Cow` is not recommended", - |diag| { - diag.span_suggestion( - hir_ty.span, - "change this to", - format!("&{}{ty_name}", mutability.prefix_str()), - Applicability::Unspecified, - ); - } - ); + }), + args.type_at(0), + ), + ), + _ if Some(adt.did()) == cx.tcx.lang_items().string() => { + ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str) + }, + Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path), + Some(sym::Cow) if mutability == Mutability::Not => { + if let Some((lifetime, ty)) = name.args.and_then(|args| { + if let [GenericArg::Lifetime(lifetime), ty] = args.args { + return Some((lifetime, ty)); + } + None + }) { + if !lifetime.is_anonymous() + && fn_sig + .output() + .walk() + .filter_map(|arg| { + arg.as_region().and_then(|lifetime| match lifetime.kind() { + ty::ReEarlyBound(r) => Some(r.def_id), + ty::ReLateBound(_, r) => r.kind.get_id(), + ty::ReFree(r) => r.bound_region.get_id(), + ty::ReStatic + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => None, + }) + }) + .any(|def_id| { + matches!( + lifetime.res, + LifetimeName::Param(param_def_id) if def_id + .as_local() + .is_some_and(|def_id| def_id == param_def_id), + ) + }) + { + // `&Cow<'a, T>` when the return type uses 'a is okay + return None; } - return None; - }, - _ => return None, - }; - return Some(PtrArg { - idx: i, - emission_id, - span: hir_ty.span, - ty_did: adt.did(), - ty_name: name.ident.name, - method_renames, - ref_prefix: RefPrefix { - lt: *lt, - mutability, - }, - deref_ty, - }); + + let ty_name = snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); + + span_lint_hir_and_then( + cx, + PTR_ARG, + emission_id, + hir_ty.span, + "using a reference to `Cow` is not recommended", + |diag| { + diag.span_suggestion( + hir_ty.span, + "change this to", + format!("&{}{ty_name}", mutability.prefix_str()), + Applicability::Unspecified, + ); + }, + ); + } + return None; + }, + _ => return None, + }; + return Some(PtrArg { + idx: i, + emission_id, + span: hir_ty.span, + ty_did: adt.did(), + ty_name: name.ident.name, + method_renames, + ref_prefix: RefPrefix { lt: *lt, mutability }, + deref_ty, + }); } None }) diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index 20e032d4b01..66d869bc45a 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// cast by using the `add` method instead. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); /// let offset = 1_usize; @@ -29,7 +29,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); /// let offset = 1_usize; diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs index 9d2b0cedb60..316a72988aa 100644 --- a/src/tools/clippy/clippy_lints/src/pub_use.rs +++ b/src/tools/clippy/clippy_lints/src/pub_use.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// unintentional exports or to encourage placing exported items directly in public modules /// /// ### Example - /// ```rust + /// ```no_run /// pub mod outer { /// mod inner { /// pub struct Test {} @@ -25,7 +25,7 @@ declare_clippy_lint! { /// use outer::Test; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub mod outer { /// pub struct Test {} /// } @@ -41,16 +41,17 @@ declare_lint_pass!(PubUse => [PUB_USE]); impl EarlyLintPass for PubUse { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Use(_) = item.kind && - let VisibilityKind::Public = item.vis.kind { - span_lint_and_help( - cx, - PUB_USE, - item.span, - "using `pub use`", - None, - "move the exported item to a public module instead", - ); - } + if let ItemKind::Use(_) = item.kind + && let VisibilityKind::Public = item.vis.kind + { + span_lint_and_help( + cx, + PUB_USE, + item.span, + "using `pub use`", + None, + "move the exported item to a public module instead", + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 734ca2914f5..b133635e883 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -1,7 +1,8 @@ -use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE}; +use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; +use clippy_config::msrvs::Msrv; +use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ @@ -97,16 +98,23 @@ enum IfBlockType<'hir> { } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind && - let Block { stmts: &[], expr: Some(els), .. } = els && - let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els) + if let StmtKind::Local(Local { + pat, + init: Some(init_expr), + els: Some(els), + .. + }) = stmt.kind + && let Block { + stmts: &[], + expr: Some(els), + .. + } = els + && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els) { let mut applicability = Applicability::MaybeIncorrect; let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability); let receiver_str = snippet_with_applicability(cx, inner_pat.span, "..", &mut applicability); - let sugg = format!( - "let {receiver_str} = {init_expr_str}?;", - ); + let sugg = format!("let {receiver_str} = {init_expr_str}?;",); span_lint_and_sugg( cx, QUESTION_MARK, diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 3287675a82d..1b3081abc13 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; @@ -11,7 +11,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::Span; +use rustc_span::source_map::Spanned; use std::cmp::Ordering; declare_clippy_lint! { @@ -39,7 +40,7 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..(y+1) { @@ -48,7 +49,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..=y { @@ -77,7 +78,7 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..=(y-1) { @@ -86,7 +87,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..y { @@ -118,7 +119,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// (0..=10).rev().for_each(|x| println!("{}", x)); /// @@ -142,14 +143,14 @@ declare_clippy_lint! { /// failure modes (such as fencepost errors or using `||` instead of `&&`). /// /// ### Example - /// ```rust + /// ```no_run /// // given /// let x = 6; /// /// assert!(x >= 3 && x < 8); /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# let x = 6; /// assert!((3..8).contains(&x)); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs index c951d9a4a09..391c77dbf90 100644 --- a/src/tools/clippy/clippy_lints/src/raw_strings.rs +++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// idiomatic than a string literal, so it's opt-in. /// /// ### Example - /// ```rust + /// ```no_run /// let r = r"Hello, world!"; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let r = "Hello, world!"; /// ``` #[clippy::version = "1.72.0"] @@ -41,11 +41,11 @@ declare_clippy_lint! { /// necessary. /// /// ### Example - /// ```rust + /// ```no_run /// let r = r###"Hello, "world"!"###; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let r = r#"Hello, "world"!"#; /// ``` #[clippy::version = "1.72.0"] diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs index bd0ca66b761..59ce289e7d2 100644 --- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// than different instances. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![std::sync::Arc::new("some data".to_string()); 100]; /// // or /// let v = vec![std::rc::Rc::new("some data".to_string()); 100]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // Initialize each value separately: /// let mut data = Vec::with_capacity(100); /// for _ in 0..100 { diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 2bf90815caa..b27d4cc6e4f 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// a zero-byte read would allocate a `Vec` for it. /// /// ### Example - /// ```rust + /// ```no_run /// use std::io; /// fn foo<F: io::Read>(mut f: F) { /// let mut data = Vec::with_capacity(100); @@ -32,7 +32,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::io; /// fn foo<F: io::Read>(mut f: F) { /// let mut data = Vec::with_capacity(100); @@ -42,7 +42,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.63.0"] pub READ_ZERO_BYTE_VEC, - correctness, + nursery, "checks for reads into a zero-length `Vec`" } declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]); @@ -59,7 +59,10 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { { let visitor = |expr: &Expr<'_>| { if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { ident: read_or_read_exact, .. } = *path + && let PathSegment { + ident: read_or_read_exact, + .. + } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind @@ -72,15 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } }; - let (read_found, next_stmt_span) = - if let Some(next_stmt) = block.stmts.get(idx + 1) { + let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { // case { .. stmt; stmt; .. } (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) } else if let Some(e) = block.expr { // case { .. stmt; expr } (for_each_expr(e, visitor).is_some(), e.span) } else { - return + return; }; if read_found && !next_stmt_span.from_expansion() { @@ -93,13 +95,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({len}, 0); {}", + format!( + "{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, next_stmt_span, "..") ), applicability, ); - } + }, VecInitKind::WithExprCapacity(hir_id) => { let e = cx.tcx.hir().expect_expr(hir_id); span_lint_and_sugg( @@ -108,14 +111,15 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({}, 0); {}", + format!( + "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), snippet(cx, next_stmt_span, "..") ), applicability, ); - } + }, _ => { span_lint( cx, @@ -123,8 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", ); - - } + }, } } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index bf9bdacba5b..90297ca8bb6 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource}; +use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -19,7 +19,7 @@ declare_clippy_lint! { /// It is simpler and more efficient to use the future directly. /// /// ### Example - /// ```rust + /// ```no_run /// let f = async { /// 1 + 2 /// }; @@ -28,7 +28,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let f = async { /// 1 + 2 /// }; @@ -69,12 +69,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { /// If `expr` is a desugared `async` block, return the original expression if it does not capture /// any variable by ref. fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && - let body = cx.tcx.hir().body(*body) && - matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) + if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind + && let body = cx.tcx.hir().body(*body) + && matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) { - cx - .typeck_results() + cx.typeck_results() .closure_min_captures .get(def_id) .map_or(true, |m| { @@ -93,12 +92,13 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op /// If `expr` is a desugared `.await`, return the original expression if it does not come from a /// macro expansion. fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && - let ExprKind::Call(_, [into_future_arg]) = match_value.kind && - let ctxt = expr.span.ctxt() && - for_each_expr(into_future_arg, |e| - walk_span_to_context(e.span, ctxt) - .map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))).is_none() + if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(_, [into_future_arg]) = match_value.kind + && let ctxt = expr.span.ctxt() + && for_each_expr(into_future_arg, |e| { + walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) + }) + .is_none() { Some(into_future_arg) } else { diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 2c0086b0981..8daf085a42f 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -12,8 +12,7 @@ use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::{BytePos, Span}; -use rustc_span::sym; +use rustc_span::{sym, BytePos, Span}; macro_rules! unwrap_or_continue { ($x:expr) => { @@ -37,7 +36,7 @@ declare_clippy_lint! { /// False-negatives: analysis performed by this lint is conservative and limited. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::path::Path; /// # #[derive(Clone)] /// # struct Foo; diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index c18237e887d..e679fab5323 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// complexity. /// /// ### Example - /// ```rust + /// ```no_run /// let a = (|| 42)(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = 42; /// ``` #[clippy::version = "pre 1.29.0"] @@ -98,11 +98,15 @@ fn find_innermost_closure<'tcx>( && steps > 0 { expr = body.value; - data = Some((body.value, closure.fn_decl, if is_async_closure(body) { - ty::Asyncness::Yes - } else { - ty::Asyncness::No - })); + data = Some(( + body.value, + closure.fn_decl, + if is_async_closure(body) { + ty::Asyncness::Yes + } else { + ty::Asyncness::No + }, + )); steps -= 1; } @@ -154,7 +158,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { |diag| { if fn_decl.inputs.is_empty() { let mut applicability = Applicability::MachineApplicable; - let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); + let mut hint = + Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind @@ -173,10 +178,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { full_expr.span, "try doing something like", hint.maybe_par(), - applicability + applicability, ); } - } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 73088ce1a87..221aa317e5d 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// Some may prefer to keep the `else` block for clarity. /// /// ### Example - /// ```rust + /// ```no_run /// fn my_func(count: u32) { /// if count == 0 { /// print!("Nothing to do"); @@ -27,7 +27,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn my_func(count: u32) { /// if count == 0 { /// print!("Nothing to do"); diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 61bff4a0e38..b8e606df737 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -16,7 +16,7 @@ declare_clippy_lint! { /// the field name is redundant. /// /// ### Example - /// ```rust + /// ```no_run /// let bar: u8 = 123; /// /// struct Foo { diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index a1a0e8f3520..6bc0d06183f 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 0; /// let a = a; /// @@ -29,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = 0; /// // no redefinition with the same name /// diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index c2a8db7df03..03673eb27f8 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -18,14 +18,14 @@ declare_clippy_lint! { /// module's visibility. /// /// ### Example - /// ```rust + /// ```no_run /// mod internal { /// pub(crate) fn internal_fn() { } /// } /// ``` /// This function is not visible outside the module and it can be declared with `pub` or /// private visibility - /// ```rust + /// ```no_run /// mod internal { /// pub fn internal_fn() { } /// } diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index 4abfa0fc35c..7adbd67912c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -51,12 +51,12 @@ declare_clippy_lint! { /// Some people may prefer to dereference rather than slice. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![1, 2, 3]; /// let slice = &vec[..]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec![1, 2, 3]; /// let slice = &*vec; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index ed42a422b4b..a70b831a80c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs index 1d4fdb43a0b..f6af9cac3de 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// - `Path` to anything else than a primitive type. /// /// ### Example - /// ```rust + /// ```no_run /// let foo: String = String::new(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let foo = String::new(); /// ``` #[clippy::version = "1.72.0"] @@ -145,8 +145,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { hir::ExprKind::Call(init_call, _) => { if let hir::TyKind::Path(ty_path) = &ty.kind && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path - - && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) { + && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) + { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } }, @@ -164,11 +164,11 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id) && let Some(return_type) = func_ty_to_return_type(cx, func_ty) - && is_same_type(cx, resolved_path_ty.res, if is_ref { - return_type.peel_refs() - } else { - return_type - }) + && is_same_type( + cx, + resolved_path_ty.res, + if is_ref { return_type.peel_refs() } else { return_type }, + ) { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } @@ -177,10 +177,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { hir::ExprKind::Path(init_path) => { // TODO: check for non primty if let Some(primty) = extract_primty(&ty.kind) - && let hir::QPath::TypeRelative(init_ty, _) = init_path && let Some(primty_init) = extract_primty(&init_ty.kind) - && primty == primty_init { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); @@ -205,8 +203,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { }, LitKind::Err => (), } - } - _ => () + }, + _ => (), } }; } diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs index b1530eed1c1..8b3dabde9be 100644 --- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs @@ -10,12 +10,12 @@ declare_clippy_lint! { /// The `ref` keyword can be confusing for people unfamiliar with it, and often /// it is more concise to use `&` instead. /// ### Example - /// ```rust + /// ```no_run /// let opt = Some(5); /// if let Some(ref foo) = opt {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let opt = Some(5); /// if let Some(foo) = &opt {} /// ``` @@ -29,7 +29,7 @@ declare_lint_pass!(RefPatterns => [REF_PATTERNS]); impl EarlyLintPass for RefPatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind - && !pat.span.from_expansion() + && !pat.span.from_expansion() { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index b795e4b15ba..cb78eec9e8d 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::{BytePos, Span}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index 0c8c904e374..1975946c6e6 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs @@ -18,18 +18,18 @@ declare_clippy_lint! { /// The `Vec::with_capacity` constructor is less complex. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v: Vec<usize> = vec![]; /// v.reserve(10); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut v: Vec<usize> = Vec::with_capacity(10); /// ``` #[clippy::version = "1.73.0"] pub RESERVE_AFTER_INITIALIZATION, complexity, - "`reserve` called immediatly after `Vec` creation" + "`reserve` called immediately after `Vec` creation" } impl_lint_pass!(ReserveAfterInitialization => [RESERVE_AFTER_INITIALIZATION]); @@ -74,15 +74,24 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) - && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) + && !matches!( + init, + VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: local.span, - init_part: snippet(cx, local.span.shrink_to_lo() - .to(init_expr.span.source_callsite().shrink_to_lo()), "..") - .into_owned(), - space_hint: String::new() + init_part: snippet( + cx, + local + .span + .shrink_to_lo() + .to(init_expr.span.source_callsite().shrink_to_lo()), + "..", + ) + .into_owned(), + space_hint: String::new(), }); } } @@ -94,15 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let Res::Local(id) = path.res && !in_external_macro(cx.sess(), expr.span) && let Some(init) = get_vec_init_kind(cx, right) - && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) + && !matches!( + init, + VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: expr.span, - init_part: snippet(cx, left.span.shrink_to_lo() - .to(right.span.source_callsite().shrink_to_lo()), "..") - .into_owned(), // see `assign_expression` test - space_hint: String::new() + init_part: snippet( + cx, + left.span.shrink_to_lo().to(right.span.source_callsite().shrink_to_lo()), + "..", + ) + .into_owned(), // see `assign_expression` test + space_hint: String::new(), }); } } @@ -118,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { self.searcher = Some(VecReserveSearcher { err_span: searcher.err_span.to(stmt.span), space_hint: snippet(cx, space_hint.span, "..").into_owned(), - .. searcher + ..searcher }); } else { searcher.display_err(cx); diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index bccf421e8f3..245029a066d 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// if it was added on constructors for example. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct Bar; /// impl Bar { /// // Missing attribute @@ -37,7 +37,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # { /// // It's better to have the `#[must_use]` attribute on the method like this: /// pub struct Bar; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index d6b9a49d2fe..f2a3dc5099d 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi}; use core::ops::ControlFlow; @@ -14,8 +15,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; declare_clippy_lint! { @@ -34,14 +34,14 @@ declare_clippy_lint! { /// bound without first assigning it to a let-binding. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> String { /// let x = String::new(); /// x /// } /// ``` /// instead, use - /// ``` + /// ```no_run /// fn foo() -> String { /// String::new() /// } @@ -61,13 +61,13 @@ declare_clippy_lint! { /// more rusty. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// return x; /// } /// ``` /// simplify to - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// x /// } @@ -213,6 +213,9 @@ impl<'tcx> LateLintPass<'tcx> for Return { if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { + if !has_enclosing_paren(&snippet) { + snippet = format!("({snippet})"); + } snippet.push_str(" as _"); } err.multipart_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index a37e2772d35..fd1f3d3903a 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Confusing. /// /// ### Example - /// ```rust + /// ```no_run /// trait T { /// fn foo(&self) {} /// } @@ -120,9 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { } }; - for impl_item_ref in (*items).iter().filter(|impl_item_ref| { - matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) - }) { + for impl_item_ref in (*items) + .iter() + .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })) + { let method_name = impl_item_ref.ident.name; methods_in_trait.remove(&method_name); check_trait_method(method_name, impl_item_ref.span); @@ -133,9 +134,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { } }, None => { - for impl_item_ref in (*items).iter().filter(|impl_item_ref| { - matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) - }) { + for impl_item_ref in (*items) + .iter() + .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })) + { let method_name = impl_item_ref.ident.name; let impl_span = impl_item_ref.span; let hir_id = impl_item_ref.id.hir_id(); diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index 88f295c72eb..b0601bba4af 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -19,13 +19,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } @@ -48,13 +48,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index c9547cd95dc..ccf8b997705 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -17,13 +17,13 @@ declare_clippy_lint! { /// code, it doesn't require a change in previous last line. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// println!("Hello world") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// println!("Hello world"); /// } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 78418b22392..41c10b34a42 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// lint to `Warn`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// let x = &x; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1; /// let y = &x; // use different variable name /// ``` @@ -49,12 +49,12 @@ declare_clippy_lint! { /// the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 2; /// let x = x + 1; /// ``` /// use different variable name: - /// ```rust + /// ```no_run /// let x = 2; /// let y = x + 1; /// ``` @@ -77,7 +77,7 @@ declare_clippy_lint! { /// names to bindings or introducing more scopes to contain the bindings. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = 1; /// # let z = 2; /// let x = y; @@ -85,7 +85,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = 1; /// # let z = 2; /// let x = y; diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index 4b248c9c790..57bcee1a871 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -236,9 +236,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx fn manage_has_expensive_expr_after_last_attr(&mut self) { let has_expensive_stmt = match self.ap.curr_stmt.kind { hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false, - hir::StmtKind::Local(local) if let Some(expr) = local.init - && let hir::ExprKind::Path(_) = expr.kind => false, - _ => true + hir::StmtKind::Local(local) + if let Some(expr) = local.init + && let hir::ExprKind::Path(_) = expr.kind => + { + false + }, + _ => true, }; if has_expensive_stmt { for apa in self.ap.apas.values_mut() { @@ -292,8 +296,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o && { if let Some(local_hir_id) = path_to_local(expr) { local_hir_id == hir_id - } - else { + } else { true } } @@ -306,8 +309,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o let expr_or_init = expr_or_init(self.cx, expr); if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind { local_expr.span.to(span) - } - else { + } else { expr_or_init.span } }, @@ -317,8 +319,12 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o modify_apa_params(&mut apa); let _ = self.ap.apas.insert(hir_id, apa); } else { - let Some(hir_id) = path_to_local(expr) else { return; }; - let Some(apa) = self.ap.apas.get_mut(&hir_id) else { return; }; + let Some(hir_id) = path_to_local(expr) else { + return; + }; + let Some(apa) = self.ap.apas.get_mut(&hir_id) else { + return; + }; match self.ap.curr_stmt.kind { hir::StmtKind::Local(local) => { if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { @@ -437,19 +443,20 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_ { let has_ident = |local_expr: &hir::Expr<'_>| { if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind - && let [first_arg_ps, .. ] = arg_path.segments + && let [first_arg_ps, ..] = arg_path.segments && &first_arg_ps.ident == first_bind_ident { true - } - else { + } else { false } }; if has_ident(first_arg) { return true; } - if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) { + if let hir::ExprKind::Tup(value) = &first_arg.kind + && value.iter().any(has_ident) + { return true; } } diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index 7bbe98e0a7f..ae81e1198af 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// Note: If this lint is used, prepare to allow this a lot. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn a<T>(t: &T) /// where /// T: AsRef<str>, @@ -37,7 +37,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub fn a<T>(t: &T) /// where /// T: AsRef<str>, diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs index 3dc995e2fa5..74ee8ce2de7 100644 --- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs +++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs @@ -22,13 +22,13 @@ declare_clippy_lint! { /// be obvious or, rarely, expressible in one character. /// /// ### Example - /// ```rust + /// ```no_run /// struct DiagnosticCtx<'a> { /// source: &'a str, /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct DiagnosticCtx<'src> { /// source: &'src str, /// } diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 321c8988988..099743d229d 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -21,11 +21,11 @@ declare_clippy_lint! { /// the end of the range to be the length instead. /// /// ### Example - /// ```rust + /// ```no_run /// let x = [0..200]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // If it was intended to include every element in the range... /// let x = (0..200).collect::<Vec<i32>>(); /// // ...Or if 200 was meant to be the len diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs index 89ac8cd8ca9..7de029b7b94 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// the reference. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// buffer: [u8], /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Foo { /// buffer: [u8], /// } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 2278e41be37..2244eab96ca 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// The `resize` call first allocates memory (since `Vec::new()` did not), and only *then* zero-initializes it. /// /// ### Example - /// ```rust + /// ```no_run /// # use core::iter::repeat; /// # let len = 4; /// let mut vec1 = Vec::new(); @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let len = 4; /// let mut vec1 = vec![0; len]; /// let mut vec2 = vec![0; len]; diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index b7396535eed..d07a44770cc 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -22,11 +22,11 @@ declare_clippy_lint! { /// migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// use std::hash::Hasher; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use core::hash::Hasher; /// ``` #[clippy::version = "1.64.0"] @@ -47,11 +47,11 @@ declare_clippy_lint! { /// for crates migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// use std::vec::Vec; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # extern crate alloc; /// use alloc::vec::Vec; /// ``` @@ -73,12 +73,12 @@ declare_clippy_lint! { /// is also useful for crates migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// # extern crate alloc; /// use alloc::slice::from_ref; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use core::slice::from_ref; /// ``` #[clippy::version = "1.64.0"] @@ -106,16 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { { let (lint, used_mod, replace_with) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { - sym::core => ( - STD_INSTEAD_OF_CORE, - "std", - "core", - ), - sym::alloc => ( - STD_INSTEAD_OF_ALLOC, - "std", - "alloc", - ), + sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), + sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { self.prev_span = path.span; return; @@ -123,11 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { }, sym::alloc => { if cx.tcx.crate_name(def_id.krate) == sym::core { - ( - ALLOC_INSTEAD_OF_CORE, - "alloc", - "core", - ) + (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { self.prev_span = path.span; return; @@ -143,7 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { &format!("used import from `{used_mod}` instead of `{replace_with}`"), &format!("consider importing the item from `{replace_with}`"), replace_with.to_string(), - Applicability::MachineApplicable); + Applicability::MachineApplicable, + ); self.prev_span = path.span; } } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 76f463fff7d..a44adc93855 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// `.push_str(_)` method is more readable. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = "Hello".to_owned(); /// x = x + ", World"; /// @@ -58,13 +58,13 @@ declare_clippy_lint! { /// particular lint `allow` by default. /// /// ### Example - /// ```rust + /// ```no_run /// let x = "Hello".to_owned(); /// x + ", World"; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut x = "Hello".to_owned(); /// x.push_str(", World"); /// ``` @@ -106,12 +106,12 @@ declare_clippy_lint! { /// more readable than a function call. /// /// ### Example - /// ```rust + /// ```no_run /// let bstr = "a byte string".as_bytes(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let bstr = b"a byte string"; /// ``` #[clippy::version = "pre 1.29.0"] @@ -231,12 +231,12 @@ declare_clippy_lint! { /// It's unnecessary, the string can be used directly. /// /// ### Example - /// ```rust + /// ```no_run /// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// &"Hello World!"[6..11]; /// ``` #[clippy::version = "1.50.0"] @@ -387,12 +387,12 @@ declare_clippy_lint! { /// expressed with `.to_owned()`. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let _ = "str".to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// let _ = "str".to_owned(); /// ``` @@ -435,13 +435,13 @@ declare_clippy_lint! { /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let msg = String::from("Hello World"); /// let _ = msg.to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// let msg = String::from("Hello World"); /// let _ = msg.clone(); @@ -483,11 +483,11 @@ declare_clippy_lint! { /// `split_whitespace` already ignores leading and trailing whitespace. /// /// ### Example - /// ```rust + /// ```no_run /// " A B C ".trim().split_whitespace(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// " A B C ".split_whitespace(); /// ``` #[clippy::version = "1.62.0"] diff --git a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs index 8be4ec3dc64..0abc199da16 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// /// ### Example /// In this example, the doc comment is attached to the *function*, rather than the *module*. - /// ```rust + /// ```no_run /// pub mod util { /// ///! This module contains utility functions. /// @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// pub mod util { /// //! This module contains utility functions. /// diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 7dff37a2b8f..bb8cde5b94d 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// unusual that happens to look like a typo. /// /// ### Example - /// ```rust + /// ```no_run /// struct Vec3 { /// x: f64, /// y: f64, @@ -45,7 +45,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct Vec3 { /// # x: f64, /// # y: f64, diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs index 39cd289b67a..4340c23f830 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -14,11 +14,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// It's most probably a typo and may lead to unexpected behaviours. /// ### Example - /// ```rust + /// ```no_run /// let x = 3_i32 ^ 4_i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 3_i32.pow(4); /// ``` #[clippy::version = "1.67.0"] @@ -38,21 +38,18 @@ impl LateLintPass<'_> for ConfusingXorAndPow { && let ExprKind::Lit(lit_right) = &right.kind && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..)) && matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..)) - && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal()) - { - span_lint_and_sugg( - cx, - SUSPICIOUS_XOR_USED_AS_POW, - expr.span, - "`^` is not the exponentiation operator", - "did you mean to write", - format!( - "{}.pow({})", - lit_left.node, - lit_right.node - ), - Applicability::MaybeIncorrect, - ); - } + && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node) + .is_some_and(|x| x.is_decimal()) + { + span_lint_and_sugg( + cx, + SUSPICIOUS_XOR_USED_AS_POW, + expr.span, + "`^` is not the exponentiation operator", + "did you mean to write", + format!("{}.pow({})", lit_left.node, lit_right.node), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 548fabb8b73..660e6835e46 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// without deinitializing or copying either variable. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 42; /// let mut b = 1337; /// @@ -34,7 +34,7 @@ declare_clippy_lint! { /// a = t; /// ``` /// Use std::mem::swap(): - /// ```rust + /// ```no_run /// let mut a = 1; /// let mut b = 2; /// std::mem::swap(&mut a, &mut b); @@ -53,14 +53,14 @@ declare_clippy_lint! { /// This looks like a failed attempt to swap. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut a = 1; /// # let mut b = 2; /// a = b; /// b = a; /// ``` /// If swapping is intended, use `swap()` instead: - /// ```rust + /// ```no_run /// # let mut a = 1; /// # let mut b = 2; /// std::mem::swap(&mut a, &mut b); @@ -232,7 +232,7 @@ fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool { } else { false } - } + }, } } diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs index 4bfbe3bf37e..6a6c94425d1 100644 --- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// other. This would then lead to undefined behavior. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { /// for (&x, &y) in x.iter().zip(y) { /// core::mem::swap(&mut *x, &mut *y); @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { /// for (&x, &y) in x.iter().zip(y) { /// core::ptr::swap(x, y); @@ -58,9 +58,14 @@ impl LateLintPass<'_> for SwapPtrToRef { let mut app = Applicability::MachineApplicable; let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0; let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0; - diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app); + diag.span_suggestion( + e.span, + "use ptr::swap", + format!("core::ptr::swap({snip1}, {snip2})"), + app, + ); } - } + }, ); } } @@ -73,7 +78,10 @@ fn is_ptr_to_ref(cx: &LateContext<'_>, e: &Expr<'_>, ctxt: SyntaxContext) -> (bo && let ExprKind::Unary(UnOp::Deref, derefed_expr) = borrowed_expr.kind && cx.typeck_results().expr_ty(derefed_expr).is_unsafe_ptr() { - (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span)) + ( + true, + (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span), + ) } else { (false, None) } diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs index e223aea297f..dcf1fac023a 100644 --- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs @@ -3,7 +3,7 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{BytePos, Span}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -16,7 +16,7 @@ declare_clippy_lint! { /// display settings of the author and reader differ. /// /// ### Example - /// ```rust + /// ```no_run /// /// /// /// Struct to hold two strings: /// /// - first one @@ -34,7 +34,7 @@ declare_clippy_lint! { /// ``` /// /// Will be converted to: - /// ```rust + /// ```no_run /// /// /// /// Struct to hold two strings: /// /// - first one diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index b6b653f6610..c717ccc35a6 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// updated, why not write the structure you want in the first place? /// /// ### Example - /// ```rust + /// ```no_run /// (0, 0).0 = 1 /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs index b356666d852..0cfb1c1253c 100644 --- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), /// having test functions outside of this module is confusing and may lead to them being "hidden". /// ### Example - /// ```rust + /// ```no_run /// #[test] /// fn my_cool_test() { /// // [...] @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(test)] /// mod tests { /// #[test] diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index f1b703fde0e..a171d225f1e 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -17,13 +17,13 @@ declare_clippy_lint! { /// more straight forward to use the dedicated `is_digit` method. /// /// ### Example - /// ```rust + /// ```no_run /// # let c = 'c'; /// # let radix = 10; /// let is_digit = c.to_digit(radix).is_some(); /// ``` /// can be written as: - /// ``` + /// ```no_run /// # let c = 'c'; /// # let radix = 10; /// let is_digit = c.is_digit(radix); diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index bb9da3a2047..87181adc24b 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed. /// /// ### Example - /// ```rust + /// ```no_run /// struct RarelyUseful { /// some_field: u32, /// last: [u32; 0], @@ -21,7 +21,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// struct MoreOftenUseful { /// some_field: usize, diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 6db330dfa61..f065d215e48 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; @@ -27,12 +27,12 @@ declare_clippy_lint! { /// less readable than combining the bounds /// /// ### Example - /// ```rust + /// ```no_run /// pub fn foo<T>(t: T) where T: Copy, T: Clone {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// pub fn foo<T>(t: T) where T: Copy + Clone {} /// ``` #[clippy::version = "1.38.0"] @@ -51,12 +51,12 @@ declare_clippy_lint! { /// less readable than specifying them only once. /// /// ### Example - /// ```rust + /// ```no_run /// fn func<T: Clone + Default>(arg: T) where T: Clone + Default {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # mod hidden { /// fn func<T: Clone + Default>(arg: T) {} /// # } @@ -66,19 +66,19 @@ declare_clippy_lint! { /// fn func<T>(arg: T) where T: Clone + Default {} /// ``` /// - /// ```rust + /// ```no_run /// fn foo<T: Default + Default>(bar: T) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo<T: Default>(bar: T) {} /// ``` /// - /// ```rust + /// ```no_run /// fn foo<T>(bar: T) where T: Default + Default {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo<T>(bar: T) where T: Default {} /// ``` #[clippy::version = "1.47.0"] diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 0dc30f7a935..6eec40cb529 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -17,8 +17,8 @@ mod useless_transmute; mod utils; mod wrong_transmute; +use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; -use clippy_utils::msrvs::Msrv; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -78,12 +78,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # let p: *const [i32] = &[]; /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let p: *const [i32] = &[]; /// p as *const [u16]; /// ``` @@ -159,7 +159,7 @@ declare_clippy_lint! { /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1_u32; /// unsafe { /// let _: char = std::mem::transmute(x); // where x: u32 @@ -193,7 +193,7 @@ declare_clippy_lint! { /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html /// /// ### Example - /// ```rust + /// ```no_run /// let b: &[u8] = &[1_u8, 2_u8]; /// unsafe { /// let _: &str = std::mem::transmute(b); // where b: &[u8] @@ -216,7 +216,7 @@ declare_clippy_lint! { /// This might result in an invalid in-memory representation of a `bool`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1_u8; /// unsafe { /// let _: bool = std::mem::transmute(x); // where x: u8 @@ -240,7 +240,7 @@ declare_clippy_lint! { /// and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let _: f32 = std::mem::transmute(1_u32); // where x: u32 /// } @@ -264,12 +264,12 @@ declare_clippy_lint! { /// elsewhere. `new_unchecked` only works for the appropriate types instead. /// /// ### Example - /// ```rust + /// ```no_run /// # use core::num::NonZeroU32; /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use core::num::NonZeroU32; /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) }; /// ``` @@ -288,7 +288,7 @@ declare_clippy_lint! { /// and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let _: u32 = std::mem::transmute(1f32); /// } @@ -311,7 +311,7 @@ declare_clippy_lint! { /// is intuitive and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let x: [u8; 8] = std::mem::transmute(1i64); /// } @@ -335,7 +335,7 @@ declare_clippy_lint! { /// written as casts. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr = &1u32 as *const u32; /// unsafe { /// // pointer-to-pointer transmute @@ -366,7 +366,7 @@ declare_clippy_lint! { /// collection, so we just lint the ones that come with `std`. /// /// ### Example - /// ```rust + /// ```no_run /// // different size, therefore likely out-of-bounds memory access /// // You absolutely do not want this in your code! /// unsafe { @@ -376,7 +376,7 @@ declare_clippy_lint! { /// /// You must always iterate, map and collect the values: /// - /// ```rust + /// ```no_run /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>(); /// ``` #[clippy::version = "1.40.0"] @@ -398,12 +398,12 @@ declare_clippy_lint! { /// [#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo<T>(u32, T); /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// struct Foo<T>(u32, T); /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) }; @@ -427,7 +427,7 @@ declare_clippy_lint! { /// call, aren't detectable yet. /// /// ### Example - /// ```rust + /// ```no_run /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; /// ``` #[clippy::version = "1.35.0"] @@ -451,11 +451,11 @@ declare_clippy_lint! { /// call, aren't detectable yet. /// /// ### Example - /// ```rust + /// ```no_run /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let null_fn: Option<fn()> = None; /// ``` #[clippy::version = "1.68.0"] diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 6bdb9aa5a26..4ab3afbe714 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_PTR_TO_REF; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index c61eb0a9311..7c2223ca3ab 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -98,17 +98,17 @@ pub(super) fn check<'tcx>( }, (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { - let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) - = (from_ty.kind(), to_ty.kind()) - && from_def == to_def - { - if same_except_params(from_subs, to_subs) { - return false; - } - Some(from_def.did()) - } else { - None - }; + let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) = + (from_ty.kind(), to_ty.kind()) + && from_def == to_def + { + if same_except_params(from_subs, to_subs) { + return false; + } + Some(from_def.did()) + } else { + None + }; span_lint_and_then( cx, TRANSMUTE_UNDEFINED_REPR, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs index 770914e99e1..471bd44b5d5 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs @@ -16,8 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) + if let ExprKind::Path(ref _qpath) = arg.kind + && let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; @@ -25,15 +25,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching: // `std::mem::transmute(0 as *const i32)` - if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) { + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind + && is_integer_literal(inner_expr, 0) + { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; } // Catching: // `std::mem::transmute(std::ptr::null::<i32>())` - if let ExprKind::Call(func1, []) = arg.kind && - is_path_diagnostic_item(cx, func1, sym::ptr_null) + if let ExprKind::Call(func1, []) = arg.kind + && is_path_diagnostic_item(cx, func1, sym::ptr_null) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index c12519d723c..642e39e8270 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{is_from_proc_macro, path_to_local}; use itertools::Itertools; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 788678a63b7..6a6160c4983 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -18,7 +18,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -64,7 +64,7 @@ declare_clippy_lint! { /// 1st comment). /// /// ### Example - /// ```rust + /// ```no_run /// struct X { /// values: Vec<Box<i32>>, /// } @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```no_run /// struct X { /// values: Vec<i32>, /// } @@ -97,7 +97,7 @@ declare_clippy_lint! { /// consider a custom `enum` instead, with clear names for each case. /// /// ### Example - /// ```rust + /// ```no_run /// fn get_data() -> Option<Option<u32>> { /// None /// } @@ -105,7 +105,7 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```no_run /// pub enum Contents { /// Data(Vec<u8>), // Was Some(Some(Vec<u8>)) /// NotYetFetched, // Was Some(None) @@ -152,7 +152,7 @@ declare_clippy_lint! { /// `LinkedList` makes sense are few and far between, but they can still happen. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::LinkedList; /// let x: LinkedList<usize> = LinkedList::new(); /// ``` @@ -197,14 +197,14 @@ declare_clippy_lint! { /// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// fn foo(bar: Rc<&usize>) {} /// ``` /// /// Better: /// - /// ```rust + /// ```no_run /// fn foo(bar: &usize) {} /// ``` #[clippy::version = "1.44.0"] @@ -258,7 +258,7 @@ declare_clippy_lint! { /// using a `type` definition to simplify them. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// struct Foo { /// inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>, diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs index a30748db88f..39469841bd4 100644 --- a/src/tools/clippy/clippy_lints/src/types/utils.rs +++ b/src/tools/clippy/clippy_lints/src/types/utils.rs @@ -2,7 +2,7 @@ use clippy_utils::last_path_segment; use if_chain::if_chain; use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::Span; pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> { let last = last_path_segment(qpath); 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 6193fdeb433..32aebdd8c0f 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -44,14 +44,14 @@ declare_clippy_lint! { /// and bugs. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// /// let ptr = unsafe { NonNull::new_unchecked(a) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -72,7 +72,7 @@ declare_clippy_lint! { /// describe safety invariants. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -80,7 +80,7 @@ declare_clippy_lint! { /// let ptr = NonNull::new(a).unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -638,7 +638,9 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> { fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { let source_map = cx.sess().source_map(); let ctxt = span.ctxt(); - if ctxt.is_root() && let Some(search_span) = get_body_search_span(cx) { + if ctxt.is_root() + && let Some(search_span) = get_body_search_span(cx) + { if let Ok(unsafe_line) = source_map.lookup_line(span.lo()) && let Some(body_span) = walk_span_to_context(search_span, SyntaxContext::root()) && let Ok(body_line) = source_map.lookup_line(body_span.lo()) @@ -648,11 +650,13 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { // Get the text from the start of function body to the unsafe block. // fn foo() { some_stuff; unsafe { stuff }; other_stuff; } // ^-------------^ - body_line.line < unsafe_line.line && text_has_safety_comment( - src, - &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ).is_some() + body_line.line < unsafe_line.line + && text_has_safety_comment( + src, + &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) + .is_some() } else { // Problem getting source text. Pretend a comment was found. true diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index e275bfd37b0..b824deac2c8 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; use unicode_normalization::UnicodeNormalization; declare_clippy_lint! { @@ -39,12 +39,12 @@ declare_clippy_lint! { /// requirements, activating this lint could be useful. /// /// ### Example - /// ```rust + /// ```no_run /// let x = String::from("€"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = String::from("\u{20ac}"); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index de4b8738e35..e76cc65fd46 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// way of specifying this without triggering needless_return lint /// /// ### Example - /// ```rust + /// ```no_run /// let mut twins = vec![(1, 1), (2, 2)]; /// twins.sort_by_key(|x| { x.1; }); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index e7915953d85..ef67f4b04b5 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { && expr_needs_inferred_result(cx, init) { if !matches!(local.pat.kind, PatKind::Wild) - && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) + && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) { span_lint_and_then( cx, @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { } } else { if let ExprKind::Match(_, _, MatchSource::AwaitDesugar) = init.kind { - return + return; } span_lint_and_then( @@ -55,12 +55,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { if let Some(expr) = &local.init { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; - diag.span_suggestion( - local.span, - "omit the `let` binding", - format!("{snip};"), - app, - ); + diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app); } }, ); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs index 546242ebd9a..884c6ca4d31 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// binding one is kind of pointless. /// /// ### Example - /// ```rust + /// ```no_run /// let x = { /// 1; /// }; @@ -38,7 +38,7 @@ declare_clippy_lint! { /// adds semicolons at the end of the operands. /// /// ### Example - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// # fn baz() {}; @@ -51,7 +51,7 @@ declare_clippy_lint! { /// } /// ``` /// is equal to - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// # fn baz() {}; @@ -63,7 +63,7 @@ declare_clippy_lint! { /// ``` /// /// For asserts: - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// assert_eq!({ foo(); }, { bar(); }); diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index 996e7edf557..e7355f92304 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// the same address after being merged together. /// /// ### Example - /// ```rust + /// ```no_run /// type F = fn(); /// fn a() {} /// let f: F = a; diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index ed2ef506381..ca159eb4d5f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -22,13 +22,13 @@ declare_clippy_lint! { /// `Box<T>` been dropped. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> Box<String> { /// Box::new(String::from("Hello, world!")) /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo() -> String { /// String::from("Hello, world!") /// } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs index 894de0d85c1..9107b2b99b8 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -9,18 +9,18 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Suggest removing the use of a may (or map_err) method when an Option or Result is being construted. + /// Suggest removing the use of a may (or map_err) method when an Option or Result is being constructed. /// /// ### Why is this bad? /// It introduces unnecessary complexity. In this case the function can be used directly and /// construct the Option or Result from the output. /// /// ### Example - /// ```rust + /// ```no_run /// Some(4).map(i32::swap_bytes); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(i32::swap_bytes(4)); /// ``` #[clippy::version = "1.73.0"] @@ -36,19 +36,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { return; } if let hir::ExprKind::MethodCall(path, recv, args, ..) = expr.kind - && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)){ - let (constructor_path, constructor_item) = - if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind - && let hir::ExprKind::Path(constructor_path) = constructor.kind - && let Some(arg) = constructor_args.first() - { - if constructor.span.from_expansion() || arg.span.from_expansion() { - return; - } - (constructor_path, arg) - } else { + && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)) + { + let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) = + recv.kind + && let hir::ExprKind::Path(constructor_path) = constructor.kind + && let Some(arg) = constructor_args.first() + { + if constructor.span.from_expansion() || arg.span.from_expansion() { return; - }; + } + (constructor_path, arg) + } else { + return; + }; let constructor_symbol = match constructor_path { hir::QPath::Resolved(_, path) => { if let Some(path_segment) = path.segments.last() { @@ -82,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { cx, UNNECESSARY_MAP_ON_CONSTRUCTOR, expr.span, - &format!("unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name), + &format!( + "unnecessary {} on constructor {constructor_snippet}(_)", + path.ident.name + ), "try", format!("{constructor_snippet}({fun_snippet}({constructor_arg_snippet}))"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs index 57a4a429e12..28ea02e4d9a 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// This results in longer and less readable code /// /// ### Example - /// ```rust + /// ```no_run /// vec!["1", "2", "3"].join(&String::new()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec!["1", "2", "3"].join(""); /// ``` #[clippy::version = "1.62.0"] diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs index 397633f533b..a1083a0a68e 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs @@ -19,11 +19,11 @@ declare_clippy_lint! { /// to detect this scenario and that is why it is a restriction lint. /// /// ### Example - /// ```rust + /// ```no_run /// use std::io::{self}; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::io; /// ``` #[clippy::version = "1.53.0"] diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs index f4111186c64..c35a2afab48 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// Readability suffers from unnecessary struct building. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { s: String } /// /// let a = S { s: String::from("Hello, world!") }; /// let b = S { ..a }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct S { s: String } /// /// let a = S { s: String::from("Hello, world!") }; @@ -42,9 +42,9 @@ declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); impl LateLintPass<'_> for UnnecessaryStruct { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { - if let Some(parent) = get_parent_expr(cx, expr) && - let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) && - parent_ty.is_any_ptr() + if let Some(parent) = get_parent_expr(cx, expr) + && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) + && parent_ty.is_any_ptr() { if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { // When the type implements `Copy`, a reference to the new struct works on the @@ -59,9 +59,9 @@ impl LateLintPass<'_> for UnnecessaryStruct { } // TODO: do not propose to replace *XX if XX is not Copy - if let ExprKind::Unary(UnOp::Deref, target) = base.kind && - matches!(target.kind, ExprKind::Path(..)) && - !is_copy(cx, cx.typeck_results().expr_ty(expr)) + if let ExprKind::Unary(UnOp::Deref, target) = base.kind + && matches!(target.kind, ExprKind::Path(..)) + && !is_copy(cx, cx.typeck_results().expr_ty(expr)) { // `*base` cannot be used instead of the struct in the general case if it is not Copy. return; @@ -81,8 +81,8 @@ impl LateLintPass<'_> for UnnecessaryStruct { } fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(hir_id) = path_to_local(expr) && - let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + if let Some(hir_id) = path_to_local(expr) + && let Node::Pat(pat) = cx.tcx.hir().get(hir_id) { matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) } else { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index f34f8d0e353..ab8de17b091 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// fit some external requirement. /// /// ### Example - /// ```rust + /// ```no_run /// fn get_cool_number(a: bool, b: bool) -> Option<i32> { /// if a && b { /// return Some(50); @@ -39,7 +39,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn get_cool_number(a: bool, b: bool) -> i32 { /// if a && b { /// return 50; diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 766a5481451..8ff088a208f 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -1,8 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::over; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; @@ -29,13 +29,13 @@ declare_clippy_lint! { /// In the example above, `Some` is repeated, which unnecessarily complicates the pattern. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// if let Some(0) | Some(2) = Some(0) {} /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// if let Some(0 | 2) = Some(0) {} /// } diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index 7ee785804f0..c43d5dc94b3 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::Span; use rustc_span::symbol::Ident; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 3649f8792ae..aea72c798be 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// causes runtime overhead and hassle for the caller. /// /// ### Example - /// ```rust + /// ```no_run /// async fn get_random_number() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } @@ -27,7 +27,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn get_random_number_improved() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index db91beec0ef..0473ecaabeb 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// or just a leftover after a refactor. /// /// ### Example - /// ```rust + /// ```no_run /// let collection = vec![1, 2, 3]; /// let iter = collection.iter().peekable(); /// @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let collection = vec![1, 2, 3]; /// let iter = collection.iter(); /// @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { ident.span, "`peek` never called on `Peekable` iterator", None, - "consider removing the call to `peekable`" - ); + "consider removing the call to `peekable`", + ); } } } @@ -131,11 +131,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { // If the Peekable is passed to a function, stop ExprKind::Call(_, args) => { if let Some(func_did) = fn_def_id(self.cx, expr) - && let Some(into_iter_did) = self - .cx - .tcx - .lang_items() - .into_iter_fn() + && let Some(into_iter_did) = self.cx.tcx.lang_items().into_iter_fn() && func_did == into_iter_did { // Probably a for loop desugar, stop searching diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs index 097568cd1f7..fbb36bea068 100644 --- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs +++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs @@ -16,11 +16,11 @@ declare_clippy_lint! { /// This is unnecessary and confusing to the reader. Doing this is probably a mistake. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1f32.ceil(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 1f32; /// ``` #[clippy::version = "1.63.0"] @@ -31,18 +31,21 @@ declare_clippy_lint! { declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> { - if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind + if let ExprKind::MethodCall(box MethodCall { + seg: name_ident, + receiver, + .. + }) = &expr.kind && let method_name = name_ident.ident.name.as_str() && (method_name == "ceil" || method_name == "round" || method_name == "floor") && let ExprKind::Lit(token_lit) = &receiver.kind && token_lit.is_semantic_float() - && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() { - (f.fract() == 0.0).then(|| - (method_name, snippet(cx, receiver.span, "..").to_string()) - ) - } else { - None - } + && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() + { + (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string())) + } else { + None + } } impl EarlyLintPass for UnusedRounding { diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 95e74718d80..adbf8281388 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -6,8 +6,7 @@ use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -19,13 +18,13 @@ declare_clippy_lint! { /// statement look like a function call. /// /// ### Example - /// ```rust + /// ```no_run /// fn return_unit() -> () { /// () /// } /// ``` /// is equivalent to - /// ```rust + /// ```no_run /// fn return_unit() {} /// ``` #[clippy::version = "1.31.0"] diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 9a0d83d83f1..cdfcb8500c4 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -15,8 +15,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -26,7 +25,7 @@ declare_clippy_lint! { /// Using `if let` or `match` is more idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if option.is_some() { @@ -36,7 +35,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if let Some(value) = option { @@ -61,7 +60,7 @@ declare_clippy_lint! { /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized. /// /// ### Example - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if option.is_none() { 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 3a1845425a2..21592abbf16 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// /// ### Example /// Before: - /// ```rust + /// ```no_run /// fn divisible_by_3(i_str: String) -> Result<(), String> { /// let i = i_str /// .parse::<i32>() @@ -37,7 +37,7 @@ declare_clippy_lint! { /// ``` /// /// After: - /// ```rust + /// ```no_run /// fn divisible_by_3(i_str: String) -> Result<(), String> { /// let i = i_str /// .parse::<i32>() diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 4df1e3299ed..de6a75b79fc 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -26,11 +26,11 @@ declare_clippy_lint! { /// the letters in the second acronym. /// /// ### Example - /// ```rust + /// ```no_run /// struct HTTPResponse; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct HttpResponse; /// ``` #[clippy::version = "1.51.0"] diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index f10ed4b3d41..c3fe16ad5c3 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::same_type_and_consts; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; @@ -31,7 +31,7 @@ declare_clippy_lint! { /// - Unaddressed false negative in fn bodies of trait implementations /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// impl Foo { /// fn new() -> Foo { @@ -40,7 +40,7 @@ declare_clippy_lint! { /// } /// ``` /// could be - /// ```rust + /// ```no_run /// struct Foo; /// impl Foo { /// fn new() -> Self { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 3cc91838c00..28f1d487eb5 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -26,13 +26,13 @@ declare_clippy_lint! { /// Redundant code. /// /// ### Example - /// ```rust + /// ```no_run /// // format!() returns a `String` /// let s: String = format!("hello").into(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let s: String = format!("hello"); /// ``` #[clippy::version = "1.45.0"] @@ -215,20 +215,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { did, args, cx.typeck_results().node_args(recv.hir_id), - MethodOrFunction::Function + MethodOrFunction::Function, )) - } + }, ExprKind::MethodCall(.., args, _) => { - cx.typeck_results().type_dependent_def_id(parent.hir_id) - .map(|did| { - return ( - did, - args, - cx.typeck_results().node_args(parent.hir_id), - MethodOrFunction::Method - ); - }) - } + cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| { + return ( + did, + args, + cx.typeck_results().node_args(parent.hir_id), + MethodOrFunction::Method, + ); + }) + }, _ => None, }; @@ -244,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { into_iter_did, cx.typeck_results().expr_ty(into_iter_recv), param.index, - node_args + node_args, ) && self.expn_depth == 0 { @@ -255,26 +254,38 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let plural = if depth == 0 { "" } else { "s" }; let mut applicability = Applicability::MachineApplicable; - let sugg = snippet_with_applicability(cx, into_iter_recv.span.source_callsite(), "<expr>", &mut applicability).into_owned(); - span_lint_and_then(cx, USELESS_CONVERSION, e.span, "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", |diag| { - diag.span_suggestion( - e.span, - format!("consider removing the `.into_iter()`{plural}"), - sugg, - applicability, - ); - diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); - }); + let sugg = snippet_with_applicability( + cx, + into_iter_recv.span.source_callsite(), + "<expr>", + &mut applicability, + ) + .into_owned(); + span_lint_and_then( + cx, + USELESS_CONVERSION, + e.span, + "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", + |diag| { + diag.span_suggestion( + e.span, + format!("consider removing the `.into_iter()`{plural}"), + sugg, + applicability, + ); + diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); + }, + ); // Early return to avoid linting again with contradicting suggestions return; } } - if let Some(id) = path_to_local(recv) && - let Node::Pat(pat) = cx.tcx.hir().get(id) && - let PatKind::Binding(ann, ..) = pat.kind && - ann != BindingAnnotation::MUT + if let Some(id) = path_to_local(recv) + && let Node::Pat(pat) = cx.tcx.hir().get(id) + && let PatKind::Binding(ann, ..) = pat.kind + && ann != BindingAnnotation::MUT { // Do not remove .into_iter() applied to a non-mutable local variable used in // a larger expression context as it would differ in mutability. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index aecb0c6dbfa..ce93aea2136 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -10,12 +10,12 @@ use rustc_hir::{ ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use std::cell::Cell; use std::fmt::{Display, Formatter, Write as _}; -declare_clippy_lint! { +declare_lint_pass!( /// ### What it does /// Generates clippy code that detects the offending pattern /// @@ -47,12 +47,8 @@ declare_clippy_lint! { /// // report your lint here /// } /// ``` - pub LINT_AUTHOR, - internal_warn, - "helper for writing lints" -} - -declare_lint_pass!(Author => [LINT_AUTHOR]); + Author => [] +); /// Writes a line of output with indentation added macro_rules! out { diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs index 092041aecf2..b108951978f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs +++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs @@ -2,9 +2,9 @@ use clippy_utils::get_attr; use hir::TraitItem; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; -declare_clippy_lint! { +declare_lint_pass!( /// ### What it does /// It formats the attached node with `{:#?}` and writes the result to the /// standard output. This is intended for debugging. @@ -19,12 +19,8 @@ declare_clippy_lint! { /// input as u64 /// } /// ``` - pub DUMP_HIR, - internal_warn, - "helper to dump info about code" -} - -declare_lint_pass!(DumpHir => [DUMP_HIR]); + DumpHir => [] +); impl<'tcx> LateLintPass<'tcx> for DumpHir { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index 94a9a7c241b..58e66c9f9b9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -5,27 +5,20 @@ use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{hygiene, Span}; use std::iter::once; use std::mem; use std::rc::Rc; -declare_clippy_lint! { - /// ### What it does - /// Collects [`rustc_ast::FormatArgs`] so that future late passes can call - /// [`clippy_utils::macros::find_format_args`] - pub FORMAT_ARGS_COLLECTOR, - internal_warn, - "collects `format_args` AST nodes for use in later lints" -} - +/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call +/// [`clippy_utils::macros::find_format_args`] #[derive(Default)] pub struct FormatArgsCollector { format_args: FxHashMap<Span, Rc<FormatArgs>>, } -impl_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); +impl_lint_pass!(FormatArgsCollector => []); impl EarlyLintPass for FormatArgsCollector { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index e222a5448c9..ddcb9f27c6c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,5 +1,4 @@ pub mod almost_standard_lint_formulation; -pub mod clippy_lints_internal; pub mod collapsible_calls; pub mod compiler_lint_functions; pub mod if_chain_style; @@ -11,3 +10,4 @@ pub mod msrv_attr_impl; pub mod outer_expn_data_pass; pub mod produce_ice; pub mod unnecessary_def_path; +pub mod unsorted_clippy_utils_paths; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 570a88a0ed2..d78f67c05f0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Checks if lint formulations have a standardized format. /// /// ### Why is this bad? - /// It's not neccessarily bad, but we try to enforce a standard in Clippy. + /// It's not necessarily bad, but we try to enforce a standard in Clippy. /// /// ### Example /// `Checks for use...` can be written as `Checks for usage...` . diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index bbb5ade8b9f..00e352961bd 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -153,8 +153,9 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { let fields; if is_lint_ref_ty { if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind - && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind { - fields = struct_fields; + && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind + { + fields = struct_fields; } else { return; } 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 c8600badf18..51abe0c1dc3 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 @@ -9,7 +9,7 @@ use crate::renamed_lints::RENAMED_LINTS; use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; -use crate::utils::{collect_configs, ClippyConfiguration}; +use clippy_config::{get_configuration_metadata, ClippyConfiguration}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -40,8 +40,6 @@ use std::process::Command; const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; /// This is the markdown output file of the lint collector. const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md"; -/// These lints are excluded from the export. -const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"]; /// These groups will be ignored by the lint group matcher. This is useful for collections like /// `clippy::all` const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"]; @@ -121,7 +119,7 @@ declare_clippy_lint! { /// ### Example output /// ```json,ignore /// { - /// "id": "internal_metadata_collector", + /// "id": "metadata_collector", /// "id_span": { /// "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs", /// "line": 1 @@ -131,12 +129,12 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.56.0"] - pub INTERNAL_METADATA_COLLECTOR, - internal_warn, + pub METADATA_COLLECTOR, + internal, "A busy bee collection metadata about lints" } -impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]); +impl_lint_pass!(MetadataCollector => [METADATA_COLLECTOR]); #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone)] @@ -155,7 +153,7 @@ impl MetadataCollector { Self { lints: BinaryHeap::<LintMetadata>::default(), applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), - config: collect_configs(), + config: get_configuration_metadata(), clippy_project_root: std::env::current_dir() .expect("failed to get current dir") .ancestors() @@ -528,16 +526,6 @@ impl Serialize for ApplicabilityInfo { } } -impl fmt::Display for ClippyConfiguration { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { - writeln!( - f, - "* `{}`: `{}`(defaults to `{}`): {}", - self.name, self.config_type, self.default, self.doc - ) - } -} - // ================================================================== // Lint pass // ================================================================== @@ -560,7 +548,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if is_lint_ref_type(cx, ty); // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); - if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // metadata extraction if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item); if let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item); @@ -585,7 +572,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if is_deprecated_lint(cx, ty); // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); - if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // Metadata the little we can get from a deprecated lint if let Some(raw_docs) = extract_attr_docs_or_lint(cx, item); then { @@ -841,7 +827,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) { fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) { span_lint( cx, - INTERNAL_METADATA_COLLECTOR, + METADATA_COLLECTOR, item.ident.span, &format!("metadata collection error for `{}`: {message}", item.ident.name), ); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index a3acb8f1762..81be04659b9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -270,7 +270,8 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { let alloc = alloc.inner(); str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) - .ok().map(ToOwned::to_owned) + .ok() + .map(ToOwned::to_owned) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs index da9514dd15e..fd51bca9e5b 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs @@ -5,21 +5,21 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does - /// Checks for various things we like to keep tidy in clippy. + /// Checks that [`clippy_utils::paths`] is sorted lexically /// /// ### Why is this bad? /// We like to pretend we're an example of tidy code. /// /// ### Example /// Wrong ordering of the util::paths constants. - pub CLIPPY_LINTS_INTERNAL, + pub UNSORTED_CLIPPY_UTILS_PATHS, internal, "various things that will negatively affect your clippy experience" } -declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); +declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]); -impl EarlyLintPass for ClippyLintsInternal { +impl EarlyLintPass for UnsortedClippyUtilsPaths { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") { if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind { @@ -32,7 +32,7 @@ impl EarlyLintPass for ClippyLintsInternal { if *last_name > *name { span_lint( cx, - CLIPPY_LINTS_INTERNAL, + UNSORTED_CLIPPY_UTILS_PATHS, item.span, "this constant should be before the previous constant due to lexical \ ordering", diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 4fef8c0717d..13e9ead9a57 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1,148 +1,5 @@ pub mod author; -pub mod conf; pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] pub mod internal_lints; -#[cfg(feature = "internal")] -use itertools::Itertools; - -/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` -fn to_kebab(config_name: &str) -> String { - config_name.replace('_', "-") -} - -#[cfg(feature = "internal")] -const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html"; - -// ================================================================== -// Configuration -// ================================================================== -#[derive(Debug, Clone, Default)] -pub struct ClippyConfiguration { - pub name: String, - #[allow(dead_code)] - config_type: &'static str, - pub default: String, - pub lints: Vec<String>, - pub doc: String, - #[allow(dead_code)] - deprecation_reason: Option<&'static str>, -} - -impl ClippyConfiguration { - pub fn new( - name: &'static str, - config_type: &'static str, - default: String, - doc_comment: &'static str, - deprecation_reason: Option<&'static str>, - ) -> Self { - let (lints, doc) = parse_config_field_doc(doc_comment) - .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); - - Self { - name: to_kebab(name), - lints, - doc, - config_type, - default, - deprecation_reason, - } - } - - #[cfg(feature = "internal")] - fn to_markdown_paragraph(&self) -> String { - format!( - "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n", - self.name, - self.doc - .lines() - .map(|line| line.strip_prefix(" ").unwrap_or(line)) - .join("\n"), - self.default, - self.config_type, - self.lints - .iter() - .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) - .join("\n"), - ) - } - #[cfg(feature = "internal")] - fn to_markdown_link(&self) -> String { - format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) - } -} - -#[cfg(feature = "internal")] -fn collect_configs() -> Vec<ClippyConfiguration> { - crate::utils::conf::metadata::get_configuration_metadata() -} - -/// This parses the field documentation of the config struct. -/// -/// ```rust, ignore -/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") -/// ``` -/// -/// Would yield: -/// ```rust, ignore -/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") -/// ``` -fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { - const DOC_START: &str = " Lint: "; - if_chain! { - if doc_comment.starts_with(DOC_START); - if let Some(split_pos) = doc_comment.find('.'); - then { - let mut doc_comment = doc_comment.to_string(); - let mut documentation = doc_comment.split_off(split_pos); - - // Extract lints - doc_comment.make_ascii_lowercase(); - let lints: Vec<String> = doc_comment - .split_off(DOC_START.len()) - .split(", ") - .map(str::to_string) - .collect(); - - // Format documentation correctly - // split off leading `.` from lint name list and indent for correct formatting - documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); - - Some((lints, documentation)) - } else { - None - } - } -} - -// Shamelessly stolen from find_all (https://github.com/nectariner/find_all) -pub trait FindAll: Iterator + Sized { - fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>> - where - P: FnMut(&Self::Item) -> bool; -} - -impl<I> FindAll for I -where - I: Iterator, -{ - fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>> - where - P: FnMut(&Self::Item) -> bool, - { - let mut occurences = Vec::<usize>::default(); - for (index, element) in self.enumerate() { - if predicate(&element) { - occurences.push(index); - } - } - - match occurences.len() { - 0 => None, - _ => Some(occurences), - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index fc17e7c6d5a..a9a3aaad366 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,8 +1,8 @@ use std::ops::ControlFlow; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; @@ -14,8 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; -use rustc_span::sym; +use rustc_span::{sym, Span}; #[expect(clippy::module_name_repetitions)] #[derive(Clone)] @@ -33,14 +32,14 @@ declare_clippy_lint! { /// This is less efficient. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(_x: &[u8]) {} /// /// foo(&vec![1, 2]); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn foo(_x: &[u8]) {} /// foo(&[1, 2]); /// ``` @@ -110,14 +109,15 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } else { ControlFlow::Break(()) } - }).is_continue(); + }) + .is_continue(); if only_slice_uses { self.check_vec_macro( cx, &vec_args, expr.span.ctxt().outer_expn_data().call_site, - SuggestedType::Array + SuggestedType::Array, ); } } diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 3fa51216c77..c8b9402f1ae 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -30,13 +30,15 @@ declare_clippy_lint! { /// multiple `push` calls. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = Vec::new(); /// v.push(0); + /// v.push(1); + /// v.push(2); /// ``` /// Use instead: - /// ```rust - /// let v = vec![0]; + /// ```no_run + /// let v = vec![0, 1, 2]; /// ``` #[clippy::version = "1.51.0"] pub VEC_INIT_THEN_PUSH, @@ -209,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { found: searcher.found + 1, err_span: searcher.err_span.to(stmt.span), last_push_expr: expr.hir_id, - .. searcher + ..searcher }); } else { searcher.display_err(cx); diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 49637652001..8abcc964b89 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -82,7 +82,9 @@ impl EarlyLintPass for Visibility { if !in_external_macro(cx.sess(), item.span) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { - if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) { + if **path == kw::SelfLower + && let Some(false) = is_from_proc_macro(cx, item.vis.span) + { span_lint_and_sugg( cx, NEEDLESS_PUB_SELF, diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 70b83149ce1..d88ede76398 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// still around. /// /// ### Example - /// ```rust + /// ```no_run /// use std::cmp::Ordering::*; /// /// # fn foo(_: std::cmp::Ordering) {} @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::cmp::Ordering; /// /// # fn foo(_: Ordering) {} diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 855aefa70cb..b6f942a90d3 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// You should use `println!()`, which is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// println!(""); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// println!(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -46,12 +46,12 @@ declare_clippy_lint! { /// newline. /// /// ### Example - /// ```rust + /// ```no_run /// # let name = "World"; /// print!("Hello {}!\n", name); /// ``` /// use println!() instead - /// ```rust + /// ```no_run /// # let name = "World"; /// println!("Hello {}!", name); /// ``` @@ -74,7 +74,7 @@ declare_clippy_lint! { /// Only catches `print!` and `println!` calls. /// /// ### Example - /// ```rust + /// ```no_run /// println!("Hello world!"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -96,7 +96,7 @@ declare_clippy_lint! { /// Only catches `eprint!` and `eprintln!` calls. /// /// ### Example - /// ```rust + /// ```no_run /// eprintln!("Hello world!"); /// ``` #[clippy::version = "1.50.0"] @@ -115,7 +115,7 @@ declare_clippy_lint! { /// debugging Rust code. It should not be used in user-facing output. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = "bar"; /// println!("{:?}", foo); /// ``` @@ -135,11 +135,11 @@ declare_clippy_lint! { /// (i.e., just put the literal in the format string) /// /// ### Example - /// ```rust + /// ```no_run /// println!("{}", "foo"); /// ``` /// use the literal without formatting: - /// ```rust + /// ```no_run /// println!("foo"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -157,14 +157,14 @@ declare_clippy_lint! { /// You should use `writeln!(buf)`, which is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, ""); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf); @@ -186,7 +186,7 @@ declare_clippy_lint! { /// newline. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; @@ -194,7 +194,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; @@ -216,14 +216,14 @@ declare_clippy_lint! { /// (i.e., just put the literal in the format string) /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, "{}", "foo"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, "foo"); @@ -342,7 +342,10 @@ impl<'tcx> LateLintPass<'tcx> for Write { } fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind + if let ItemKind::Impl(Impl { + of_trait: Some(trait_ref), + .. + }) = &item.kind && let Some(trait_id) = trait_ref.trait_def_id() { cx.tcx.is_diagnostic_item(sym::Debug, trait_id) @@ -508,7 +511,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue }; + let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { + continue; + }; let format_string_is_raw = format_string_snippet.starts_with('r'); let replacement = match (format_string_is_raw, replace_raw) { @@ -537,7 +542,8 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { if let Some(replacement) = replacement // `format!("{}", "a")`, `format!("{named}", named = "b") // ~~~~~ ~~~~~~~~~~~~~ - && let Some(removal_span) = format_arg_removal_span(format_args, index) { + && let Some(removal_span) = format_arg_removal_span(format_args, index) + { let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw); suggestion.push((*placeholder_span, replacement)); suggestion.push((removal_span, String::new())); @@ -549,7 +555,8 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { if !suggestion.is_empty() { for piece in &format_args.template { if let Some((span, index)) = positional_arg_piece_span(piece) - && suggestion.iter().all(|(s, _)| *s != span) { + && suggestion.iter().all(|(s, _)| *s != span) + { let decrement = replaced_position.iter().filter(|i| **i < index).count(); suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); } diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 9b3de35dbd3..f2f0699ef48 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -13,12 +13,12 @@ declare_clippy_lint! { /// It's less readable than `f32::NAN` or `f64::NAN`. /// /// ### Example - /// ```rust + /// ```no_run /// let nan = 0.0f32 / 0.0; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let nan = f32::NAN; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 002304f8840..fee100fe1ea 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -23,14 +23,14 @@ declare_clippy_lint! { /// * This lints the signature of public items /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// fn unique_words(text: &str) -> HashMap<&str, ()> { /// todo!(); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// fn unique_words(text: &str) -> HashSet<&str> { /// todo!(); diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 90091ca927a..c9b01a68f42 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -5,15 +5,14 @@ edition = "2021" publish = false [dependencies] +clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } if_chain = "1.0" itertools = "0.10.1" rustc-semver = "1.1" -serde = { version = "1.0" } [features] -deny-warnings = [] -internal = [] +deny-warnings = ["clippy_config/deny-warnings"] [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 6be8b8bb916..3bac0626f88 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -292,7 +292,9 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { (Pat::Str("#!["), Pat::Str("]")) }; - if let Some(ident) = attr.ident() && let Pat::Str(old_pat) = pat.0 { + if let Some(ident) = attr.ident() + && let Pat::Str(old_pat) = pat.0 + { // TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of // refactoring // NOTE: This will likely have false positives, like `allow = 1` diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 50a73745acb..b581a60de6e 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -405,8 +405,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field) { mir_to_const(self.lcx, desired_field) - } - else { + } else { result } }, @@ -462,11 +461,15 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { // Check if this constant is based on `cfg!(..)`, // which is NOT constant for our purposes. if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) - && let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. }) = node - && let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx - .tcx - .hir() - .get(body_id.hir_id) + && let Node::Item(Item { + kind: ItemKind::Const(.., body_id), + .. + }) = node + && let Node::Expr(Expr { + kind: ExprKind::Lit(_), + span, + .. + }) = self.lcx.tcx.hir().get(body_id.hir_id) && is_direct_expn_of(*span, "cfg").is_some() { return None; @@ -531,7 +534,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo) && let Some(src) = src.as_str() { - use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace}; + use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; if !tokenize(src) .map(|t| t.kind) .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) @@ -717,8 +720,7 @@ fn field_of_struct<'tcx>( && let Some(&(val, ty)) = dc.fields.get(field_idx) { Some(mir::Const::Val(val, ty)) - } - else { + } else { None } } diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index edd87546a5f..45c7e3a6e1d 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; -use rustc_span::source_map::Span; +use rustc_span::Span; use std::env; fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { @@ -193,7 +193,7 @@ pub fn span_lint_hir_and_then( /// | /// = note: `-D fold-any` implied by `-D warnings` /// ``` -#[cfg_attr(feature = "internal", allow(clippy::collapsible_span_lint_calls))] +#[expect(clippy::collapsible_span_lint_calls)] pub fn span_lint_and_sugg<T: LintContext>( cx: &T, lint: &'static Lint, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 52214e733f1..2a8b2ebd5fb 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1142,12 +1142,8 @@ fn eq_span_tokens( let pred = |t: &(_, _)| pred(t.0); let map = |(_, x)| x; - let ltok = tokenize_with_text(lsrc) - .filter(pred) - .map(map); - let rtok = tokenize_with_text(rsrc) - .filter(pred) - .map(map); + let ltok = tokenize_with_text(lsrc).filter(pred).map(map); + let rtok = tokenize_with_text(rsrc).filter(pred).map(map); ltok.eq(rtok) } else { // Unable to access the source. Conservatively assume the blocks aren't equal. diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 93b37022822..1181dfc0ef9 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -54,7 +54,6 @@ pub mod higher; mod hir_utils; pub mod macros; pub mod mir; -pub mod msrvs; pub mod numeric_literal; pub mod paths; pub mod ptr; @@ -144,7 +143,7 @@ macro_rules! extract_msrv_attr { /// instead. /// /// Examples: -/// ``` +/// ```no_run /// let abc = 1; /// // ^ output /// let def = abc; @@ -288,7 +287,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { match *qpath { QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)), - QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) }, + QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath), _ => false, } } @@ -699,7 +698,7 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> { /// /// Use this if you want to find the `TraitRef` of the `Add` trait in this example: /// -/// ```rust +/// ```no_run /// struct Point(isize, isize); /// /// impl std::ops::Add for Point { @@ -864,8 +863,8 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool { - if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind && - seg.ident.name == sym::from + if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind + && seg.ident.name == sym::from { match arg.kind { ExprKind::Lit(hir::Lit { @@ -874,12 +873,12 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: & }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String), ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec), ExprKind::Repeat(_, ArrayLen::Body(len)) => { - if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind && - let LitKind::Int(v, _) = const_lit.node + if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind + && let LitKind::Int(v, _) = const_lit.node { - return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec); + return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec); } - } + }, _ => (), } } @@ -895,7 +894,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: & /// /// For example, given the following function: /// -/// ``` +/// ```no_run /// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) { /// for item in iter { /// let s = item.1; @@ -1516,32 +1515,30 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti false } }); - let end_is_none_or_max = end.map_or(true, |end| { - match limits { - RangeLimits::Closed => { - if let rustc_ty::Adt(_, subst) = ty.kind() - && let bnd_ty = subst.type_at(0) - && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) - && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) - && let Some(end_const) = constant(cx, cx.typeck_results(), end) - { - end_const == max_const - } else { - false - } - }, - RangeLimits::HalfOpen => { - if let Some(container_path) = container_path - && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind - { - container_path.res == path.res - } else { - false - } - }, - } + let end_is_none_or_max = end.map_or(true, |end| match limits { + RangeLimits::Closed => { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) + && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) + && let Some(end_const) = constant(cx, cx.typeck_results(), end) + { + end_const == max_const + } else { + false + } + }, + RangeLimits::HalfOpen => { + if let Some(container_path) = container_path + && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }, }); return start_is_none_or_min && end_is_none_or_max; } @@ -1609,7 +1606,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { /// Returns the pre-expansion span if the span directly comes from an expansion /// of the macro `name`. /// The difference with [`is_expn_of`] is that in -/// ```rust +/// ```no_run /// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } } /// # macro_rules! bar { ($e:expr) => { $e } } /// foo!(bar!(42)); @@ -2032,17 +2029,26 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// * `|x| return x` /// * `|x| { return x }` /// * `|x| { return x; }` +/// * `|(x, y)| (x, y)` /// /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { - let id = if_chain! { - if let [param] = func.params; - if let PatKind::Binding(_, id, _, _) = param.pat.kind; - then { - id - } else { - return false; + fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool { + match (pat.kind, expr.kind) { + (PatKind::Binding(_, id, _, _), _) => { + path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty() + }, + (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup)) + if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() => + { + pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr)) + }, + _ => false, } + } + + let [param] = func.params else { + return false; }; let mut expr = func.value; @@ -2075,7 +2081,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { } } }, - _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(), + _ => return check_pat(cx, param.pat, expr), } } } @@ -2093,7 +2099,8 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) }, ExprKind::Path(QPath::Resolved(_, path)) if path.segments.iter().all(|seg| seg.infer_args) - && let Some(did) = path.res.opt_def_id() => { + && let Some(did) = path.res.opt_def_id() => + { cx.tcx.is_diagnostic_item(sym::convert_identity, did) }, _ => false, @@ -2195,7 +2202,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { /// Check if parent of a hir node is a trait implementation block. /// For example, `f` in -/// ```rust +/// ```no_run /// # struct S; /// # trait Trait { fn f(); } /// impl Trait for S { @@ -2447,7 +2454,8 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym for id in tcx.hir().module_items(module) { if matches!(tcx.def_kind(id.owner_id), DefKind::Const) && let item = tcx.hir().item(id) - && let ItemKind::Const(ty, _generics, _body) = item.kind { + && let ItemKind::Const(ty, _generics, _body) = item.kind + { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { // We could also check for the type name `test::TestDescAndFn` if let Res::Def(DefKind::Struct, _) = path.res { @@ -2711,7 +2719,9 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio let ctxt = e.span.ctxt(); walk_to_expr_usage(cx, e, &mut |parent, child_id| { // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead. - if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) { + if adjustments.is_empty() + && let Node::Expr(e) = cx.tcx.hir().get(child_id) + { adjustments = cx.typeck_results().expr_adjustments(e); } match parent { @@ -2908,13 +2918,13 @@ pub fn pat_and_expr_can_be_question_mark<'a, 'hir>( pat: &'a Pat<'hir>, else_body: &Expr<'_>, ) -> Option<&'a Pat<'hir>> { - if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind && - is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) && - !is_refutable(cx, inner_pat) && - let else_body = peel_blocks(else_body) && - let ExprKind::Ret(Some(ret_val)) = else_body.kind && - let ExprKind::Path(ret_path) = ret_val.kind && - is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone) + if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind + && is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) + && !is_refutable(cx, inner_pat) + && let else_body = peel_blocks(else_body) + && let ExprKind::Ret(Some(ret_val)) = else_body.kind + && let ExprKind::Path(ret_path) = ret_val.kind + && is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone) { Some(inner_pat) } else { @@ -2952,3 +2962,15 @@ op_utils! { Shl ShlAssign Shr ShrAssign } + +/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` +/// that is not locally used. +pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool { + match *pat { + PatKind::Wild => true, + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { + !visitors::is_local_used(cx, body, id) + }, + _ => false, + } +} diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 4a20399e364..5bca554378e 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -4,16 +4,13 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information. -#[cfg(feature = "internal")] pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"]; -#[cfg(feature = "internal")] pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "Unspecified"], ["rustc_lint_defs", "Applicability", "HasPlaceholders"], ["rustc_lint_defs", "Applicability", "MaybeIncorrect"], ["rustc_lint_defs", "Applicability", "MachineApplicable"], ]; -#[cfg(feature = "internal")] pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"]; pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "BinaryHeap", "iter"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; @@ -25,9 +22,7 @@ pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", " pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; -#[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; -#[cfg(feature = "internal")] pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"]; @@ -38,22 +33,15 @@ pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWri pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"]; pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"]; pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"]; -#[cfg(feature = "internal")] pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; -#[cfg(feature = "internal")] pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; -#[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; -#[cfg(feature = "internal")] pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; -#[cfg(feature = "internal")] pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; -#[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; -#[cfg(feature = "internal")] -pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; +pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; @@ -86,17 +74,11 @@ pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"]; pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"]; -#[cfg(feature = "internal")] pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"]; -#[cfg(feature = "internal")] pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"]; -#[cfg(feature = "internal")] pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"]; -#[cfg(feature = "internal")] pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; -#[cfg(feature = "internal")] pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; -#[cfg(feature = "internal")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"]; @@ -112,6 +94,7 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; +pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index ef0e2d3e1b3..668ea9fcf3b 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -3,7 +3,7 @@ // of terminologies might not be relevant in the context of Clippy. Note that its behavior might // differ from the time of `rustc` even if the name stays the same. -use crate::msrvs::Msrv; +use clippy_config::msrvs::Msrv; use hir::LangItem; use rustc_attr::StableSince; use rustc_const_eval::transform::check_consts::ConstCx; diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 31cb421095e..e72467edeeb 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -70,9 +70,9 @@ pub fn expr_block<T: LintContext>( app: &mut Applicability, ) -> String { let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app); - if !from_macro && - let ExprKind::Block(block, _) = expr.kind && - block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + if !from_macro + && let ExprKind::Block(block, _) = expr.kind + && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { format!("{code}") } else { @@ -108,7 +108,7 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo /// Extends the span to the beginning of the spans line, incl. whitespaces. /// -/// ```rust +/// ```no_run /// let x = (); /// // ^^ /// // will be converted to diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs index 69c25b427e1..421b25a77fe 100644 --- a/src/tools/clippy/clippy_utils/src/str_utils.rs +++ b/src/tools/clippy/clippy_utils/src/str_utils.rs @@ -14,7 +14,7 @@ impl StrIndex { /// Returns the index of the character after the first camel-case component of `s`. /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_until, StrIndex}; /// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6)); /// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); @@ -58,7 +58,7 @@ pub fn camel_case_until(s: &str) -> StrIndex { /// Returns index of the first camel-case component of `s`. /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_start, StrIndex}; /// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); /// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); @@ -73,7 +73,7 @@ pub fn camel_case_start(s: &str) -> StrIndex { /// Returns `StrIndex` of the last camel-case component of `s[idx..]`. /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex}; /// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0)); /// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3)); @@ -122,7 +122,7 @@ pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> StrIndex { /// Get the indexes of camel case components of a string `s` /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_indices, StrIndex}; /// assert_eq!( /// camel_case_indices("AbcDef"), @@ -149,7 +149,7 @@ pub fn camel_case_indices(s: &str) -> Vec<StrIndex> { /// Split camel case string into a vector of its components /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_split, StrIndex}; /// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); /// ``` @@ -181,7 +181,7 @@ impl StrCount { /// Returns the number of chars that match from the start /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{count_match_start, StrCount}; /// 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)); @@ -207,7 +207,7 @@ pub fn count_match_start(str1: &str, str2: &str) -> StrCount { /// Returns the number of chars and bytes that match from the end /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{count_match_end, StrCount}; /// 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)); @@ -237,7 +237,7 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount { } /// Returns a `snake_case` version of the input -/// ``` +/// ```no_run /// use clippy_utils::str_utils::to_snake_case; /// assert_eq!(to_snake_case("AbcDef"), "abc_def"); /// assert_eq!(to_snake_case("ABCD"), "a_b_c_d"); @@ -260,7 +260,7 @@ pub fn to_snake_case(name: &str) -> String { s } /// Returns a `CamelCase` version of the input -/// ``` +/// ```no_run /// use clippy_utils::str_utils::to_camel_case; /// assert_eq!(to_camel_case("abc_def"), "AbcDef"); /// assert_eq!(to_camel_case("a_b_c_d"), "ABCD"); diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 836f8cc1916..db79dd78801 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -16,7 +16,7 @@ use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty; -use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext}; +use rustc_span::{BytePos, CharPos, Pos, Span, SyntaxContext}; use std::borrow::Cow; use std::fmt::{self, Display, Write as _}; use std::ops::{Add, Neg, Not, Sub}; @@ -465,7 +465,10 @@ forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'stat impl Neg for Sugg<'_> { type Output = Sugg<'static>; fn neg(self) -> Sugg<'static> { - make_unop("-", self) + match &self { + Self::BinOp(AssocOp::As, ..) => Sugg::MaybeParen(format!("-({self})").into()), + _ => make_unop("-", self), + } } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 673b259523e..7eff93881b2 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -890,7 +890,9 @@ pub fn for_each_top_level_late_bound_region<B>( impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<TyCtxt<'tcx>> for V<F> { type BreakTy = B; fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { - if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index { + if let RegionKind::ReLateBound(idx, bound) = r.kind() + && idx.as_u32() == self.index + { (self.f)(bound) } else { ControlFlow::Continue(()) @@ -984,16 +986,16 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc .iter() .try_fold(false, |found, p| { if let ty::ClauseKind::Trait(p) = p.kind().skip_binder() - && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() - && ty.index == self_ty.index - { - // This should use `super_traits_of`, but that's a private function. - if p.trait_ref.def_id == fn_once_id { - return Some(true); - } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id { - return None; + && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() + && ty.index == self_ty.index + { + // This should use `super_traits_of`, but that's a private function. + if p.trait_ref.def_id == fn_once_id { + return Some(true); + } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id { + return None; + } } - } Some(found) }) .unwrap_or(false) diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 75064672326..76fa15e1588 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -267,7 +267,9 @@ fn path_segment_certainty( /// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`. /// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`. fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option<Res> { - if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() { + if path_segment.res == Res::Err + && let Some(def_id) = parent_certainty.to_def_id() + { let mut def_path = cx.get_def_path(def_id); def_path.push(path_segment.ident.name); let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::<Vec<_>>()); diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs index 0057256f659..dc3037f6669 100644 --- a/src/tools/clippy/declare_clippy_lint/src/lib.rs +++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs @@ -94,7 +94,7 @@ impl Parse for ClippyLint { /// /// # Example /// -/// ``` +/// ```ignore /// use rustc_session::declare_tool_lint; /// /// declare_clippy_lint! { @@ -136,28 +136,16 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { "{}", match category.as_str() { "correctness" => "Deny", - "style" | "suspicious" | "complexity" | "perf" | "internal_warn" => "Warn", + "style" | "suspicious" | "complexity" | "perf" => "Warn", "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", _ => panic!("unknown category {category}"), }, ); - let info = if category == "internal_warn" { - None - } else { - let info_name = format_ident!("{name}_INFO"); - - (&mut category[0..1]).make_ascii_uppercase(); - let category_variant = format_ident!("{category}"); + let info_name = format_ident!("{name}_INFO"); - Some(quote! { - pub(crate) static #info_name: &'static crate::LintInfo = &crate::LintInfo { - lint: &#name, - category: crate::LintCategory::#category_variant, - explanation: #explanation, - }; - }) - }; + (&mut category[0..1]).make_ascii_uppercase(); + let category_variant = format_ident!("{category}"); let output = quote! { declare_tool_lint! { @@ -168,7 +156,11 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { report_in_external_macro: true } - #info + pub(crate) static #info_name: &'static crate::LintInfo = &crate::LintInfo { + lint: &#name, + category: crate::LintCategory::#category_variant, + explanation: #explanation, + }; }; TokenStream::from(output) diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index 3a022b343a4..58cb42316fd 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -523,7 +523,7 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1); // collect into a tupled list for sorting - let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect(); + let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); // sort by "000{count} {clippy::lintname}" // to not have a lint with 200 and 2 warnings take the same spot stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 7c5b5e97a5c..293fcbf3992 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-21" +channel = "nightly-2023-11-02" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 11290f88a49..7bb49d08da6 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -126,7 +126,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // JUSTIFICATION: necessary in clippy driver to set `mir_opt_level` #[allow(rustc::bad_opt_access)] fn config(&mut self, config: &mut interface::Config) { - let conf_path = clippy_lints::lookup_conf_file(); + let conf_path = clippy_config::lookup_conf_file(); let previous = config.register_lints.take(); let clippy_args_var = self.clippy_args_var.take(); config.parse_sess_created = Some(Box::new(move |parse_sess| { @@ -147,7 +147,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { (previous)(sess, lint_store); } - let conf = clippy_lints::Conf::read(sess, &conf_path); + let conf = clippy_config::Conf::read(sess, &conf_path); clippy_lints::register_plugins(lint_store, sess, conf); clippy_lints::register_pre_expansion_lints(lint_store, conf); clippy_lints::register_renamed(lint_store); @@ -266,10 +266,12 @@ pub fn main() { if clippy_enabled { args.extend(clippy_args); rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }) - .set_using_internal_features(using_internal_features).run() + .set_using_internal_features(using_internal_features) + .run() } else { rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }) - .set_using_internal_features(using_internal_features).run() + .set_using_internal_features(using_internal_features) + .run() } })) } diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 1494c7d3179..3b7c974b65b 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -30,6 +30,7 @@ mod test_utils; /// All crates used in UI tests are listed here static TEST_DEPENDENCIES: &[&str] = &[ + "clippy_config", "clippy_lints", "clippy_utils", "futures", diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs index afde31face1..3f16c180ea7 100644 --- a/src/tools/clippy/tests/dogfood.rs +++ b/src/tools/clippy/tests/dogfood.rs @@ -28,6 +28,7 @@ fn dogfood_clippy() { "clippy_dev", "clippy_lints", "clippy_utils", + "clippy_config", "lintcheck", "rustc_tools_util", ] { @@ -56,7 +57,10 @@ fn run_metadata_collection_lint() { // Run collection as is std::env::set_var("ENABLE_METADATA_COLLECTION", "1"); - run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]); + assert!(run_clippy_for_package( + "clippy_lints", + &["-A", "unfulfilled_lint_expectations"] + )); // Check if cargo caching got in the way if let Ok(file) = File::open(metadata_output_path) { @@ -79,9 +83,13 @@ fn run_metadata_collection_lint() { .unwrap(); // Running the collection again - run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]); + assert!(run_clippy_for_package( + "clippy_lints", + &["-A", "unfulfilled_lint_expectations"] + )); } +#[must_use] fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed index 928596d0809..9b5bf736f13 100644 --- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -8,8 +8,8 @@ extern crate rustc_lint; extern crate rustc_middle; #[macro_use] extern crate rustc_session; +use clippy_config::msrvs::Msrv; use clippy_utils::extract_msrv_attr; -use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs index 50b28648ccc..c5bde47e4ce 100644 --- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -8,8 +8,8 @@ extern crate rustc_lint; extern crate rustc_middle; #[macro_use] extern crate rustc_session; +use clippy_config::msrvs::Msrv; use clippy_utils::extract_msrv_attr; -use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs index 43df654389b..3303eb14567 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs @@ -379,7 +379,8 @@ impl MacroArm { p.span(), )?; self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out); - self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) + self.args + .push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) } else { self.add_multi_arg_def(dollar_span, g.span(), out); self.args.push(TT::Group(g)); @@ -436,7 +437,12 @@ impl Expander { && p.as_char() == ESCAPE_CHAR && let Some(arm) = self.arm.as_mut() { - arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?; + arm.add_arg( + p.span(), + mem::replace(&mut input.tt, tt), + &mut input.iter, + &mut self.expn, + )?; if input.next().is_none() { return Ok(()); } diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed index 44d7f6e6d79..167263d31df 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed @@ -80,9 +80,7 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/10452 let should_not_lint = [(); if true { 1 } else { 0 }]; - let should_not_lint = const { - if true { 1 } else { 0 } - }; + let should_not_lint = const { if true { 1 } else { 0 } }; some_fn(a); } @@ -110,7 +108,9 @@ fn if_let(a: Enum, b: Enum) { 0 }; - if let Enum::A = a && let Enum::B = b { + if let Enum::A = a + && let Enum::B = b + { 1 } else { 0 diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs index 7d989ae4bb3..f3f055eb7f0 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs @@ -112,9 +112,7 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/10452 let should_not_lint = [(); if true { 1 } else { 0 }]; - let should_not_lint = const { - if true { 1 } else { 0 } - }; + let should_not_lint = const { if true { 1 } else { 0 } }; some_fn(a); } @@ -142,7 +140,9 @@ fn if_let(a: Enum, b: Enum) { 0 }; - if let Enum::A = a && let Enum::B = b { + if let Enum::A = a + && let Enum::B = b + { 1 } else { 0 diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr index 837ed05d3a6..714da8a4169 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr @@ -99,7 +99,7 @@ LL | | }; = note: `!b as i32` or `(!b).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:124:5 + --> $DIR/bool_to_int_with_if.rs:122:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed index 90eb50715a2..e102b13a761 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed +++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed @@ -15,7 +15,9 @@ fn main() { let s = [0].as_slice(); if s.is_empty() {} if s.is_empty() {} - if s.is_empty() && s.is_empty() {} + if s.is_empty() + && s.is_empty() + {} // Allow comparisons to non-empty let s = String::new(); @@ -28,5 +30,7 @@ fn main() { if let [0] = &*v {} let s = [0].as_slice(); if let [0] = s {} - if let [0] = &*s && s == [0] {} + if let [0] = &*s + && s == [0] + {} } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs index 0964c4a20a9..69a6c967d38 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.rs +++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs @@ -15,7 +15,9 @@ fn main() { let s = [0].as_slice(); if let [] = s {} if let [] = &*s {} - if let [] = &*s && s == [] {} + if let [] = &*s + && s == [] + {} // Allow comparisons to non-empty let s = String::new(); @@ -28,5 +30,7 @@ fn main() { if let [0] = &*v {} let s = [0].as_slice(); if let [0] = s {} - if let [0] = &*s && s == [0] {} + if let [0] = &*s + && s == [0] + {} } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr index b97ab4c3c93..83d431fd52b 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr +++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr @@ -46,14 +46,14 @@ LL | if let [] = &*s {} error: comparison to empty slice using `if let` --> $DIR/comparison_to_empty.rs:18:8 | -LL | if let [] = &*s && s == [] {} +LL | if let [] = &*s | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> $DIR/comparison_to_empty.rs:18:24 + --> $DIR/comparison_to_empty.rs:19:12 | -LL | if let [] = &*s && s == [] {} - | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` +LL | && s == [] + | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index 47b56960a00..aee89719728 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -224,3 +224,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: { } } } + +/// this checks if the lowerCamelCase issue is fixed +fn issue_11568() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 4d9a4eafa5f..b6346b881ad 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -224,3 +224,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: { } } } + +/// this checks if the lowerCamelCase issue is fixed +fn issue_11568() {} diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index 85df852f729..ddf2dfdaea9 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -204,4 +204,21 @@ mod allow_attributes_on_variants { } } +mod issue11494 { + // variant order should not affect lint + enum Data { + Valid, + Invalid, + DataDependent, + //~^ ERROR: variant name starts with the enum's name + } + + enum Datas { + DatasDependent, + //~^ ERROR: variant name starts with the enum's name + Valid, + Invalid, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index 9ea80b635f4..b1e88de0fcf 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -158,5 +158,17 @@ LL | | } | = help: remove the postfixes and use full paths to the variants instead of glob imports -error: aborting due to 14 previous errors +error: variant name starts with the enum's name + --> $DIR/enum_variants.rs:212:9 + | +LL | DataDependent, + | ^^^^^^^^^^^^^ + +error: variant name starts with the enum's name + --> $DIR/enum_variants.rs:217:9 + | +LL | DatasDependent, + | ^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed index c23f4d7c4d3..a4d6d49e57c 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -33,6 +33,9 @@ fn main() { let _ = a.mul_add(a, b).sqrt(); + let u = 1usize; + let _ = b.mul_add(-(u as f64), a); + // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs index 431badc8db4..262a20f0f55 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -33,6 +33,9 @@ fn main() { let _ = (a * a + b).sqrt(); + let u = 1usize; + let _ = a - (b * u as f64); + // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr index 81b7126db54..38dbefbe14c 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr @@ -73,5 +73,11 @@ error: multiply and add expressions can be calculated more efficiently and accur LL | let _ = (a * a + b).sqrt(); | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` -error: aborting due to 12 previous errors +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_mul_add.rs:37:13 + | +LL | let _ = a - (b * u as f64); + | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/get_first.fixed b/src/tools/clippy/tests/ui/get_first.fixed index a7cdd2a93ba..710ebab1ef2 100644 --- a/src/tools/clippy/tests/ui/get_first.fixed +++ b/src/tools/clippy/tests/ui/get_first.fixed @@ -32,9 +32,12 @@ fn main() { let _ = z[0]; let vecdeque: VecDeque<_> = x.iter().cloned().collect(); + let _ = vecdeque.front(); + //~^ ERROR: accessing first element with `vecdeque.get(0)` + let _ = vecdeque.get(1); + let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]); - let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice. let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice. let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice. diff --git a/src/tools/clippy/tests/ui/get_first.rs b/src/tools/clippy/tests/ui/get_first.rs index cca743c4bf5..ad2ba6ce2c3 100644 --- a/src/tools/clippy/tests/ui/get_first.rs +++ b/src/tools/clippy/tests/ui/get_first.rs @@ -32,9 +32,12 @@ fn main() { let _ = z[0]; let vecdeque: VecDeque<_> = x.iter().cloned().collect(); + let _ = vecdeque.get(0); + //~^ ERROR: accessing first element with `vecdeque.get(0)` + let _ = vecdeque.get(1); + let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]); - let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice. let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice. let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice. diff --git a/src/tools/clippy/tests/ui/get_first.stderr b/src/tools/clippy/tests/ui/get_first.stderr index 8ee66e33cc8..7474a2ada66 100644 --- a/src/tools/clippy/tests/ui/get_first.stderr +++ b/src/tools/clippy/tests/ui/get_first.stderr @@ -19,11 +19,17 @@ error: accessing first element with `z.get(0)` LL | let _ = z.get(0); | ^^^^^^^^ help: try: `z.first()` +error: accessing first element with `vecdeque.get(0)` + --> $DIR/get_first.rs:35:13 + | +LL | let _ = vecdeque.get(0); + | ^^^^^^^^^^^^^^^ help: try: `vecdeque.front()` + error: accessing first element with `non_primitives.get(0)` - --> $DIR/get_first.rs:45:13 + --> $DIR/get_first.rs:48:13 | LL | let _ = non_primitives.get(0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/if_not_else_bittest.rs b/src/tools/clippy/tests/ui/if_not_else_bittest.rs new file mode 100644 index 00000000000..586ce6ce1bc --- /dev/null +++ b/src/tools/clippy/tests/ui/if_not_else_bittest.rs @@ -0,0 +1,11 @@ +#![deny(clippy::if_not_else)] + +fn show_permissions(flags: u32) { + if flags & 0x0F00 != 0 { + println!("Has the 0x0F00 permission."); + } else { + println!("The 0x0F00 permission is missing."); + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed index 15eaf1f659a..707a0e76e4e 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed @@ -38,3 +38,19 @@ pub fn moo(_: ()) { let _: () = foo().unwrap(); let _: () = (); } + +fn test_unit_ref_1() { + let x: (usize, &&&&&()) = (1, &&&&&&()); + match x { + (1, ()) => unimplemented!(), + //~^ ERROR: matching over `()` is more explicit + _ => unimplemented!(), + }; +} + +fn test_unit_ref_2(v: &[(usize, ())]) { + for (x, ()) in v { + //~^ ERROR: matching over `()` is more explicit + let _ = x; + } +} diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs index 9cac3a440ab..544f2b8f692 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs @@ -38,3 +38,19 @@ pub fn moo(_: ()) { let _: () = foo().unwrap(); let _: () = (); } + +fn test_unit_ref_1() { + let x: (usize, &&&&&()) = (1, &&&&&&()); + match x { + (1, _) => unimplemented!(), + //~^ ERROR: matching over `()` is more explicit + _ => unimplemented!(), + }; +} + +fn test_unit_ref_2(v: &[(usize, ())]) { + for (x, _) in v { + //~^ ERROR: matching over `()` is more explicit + let _ = x; + } +} diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr index cac01a87dba..05c8f281e55 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr @@ -43,5 +43,17 @@ error: matching over `()` is more explicit LL | let _ = foo().unwrap(); | ^ help: use `()` instead of `_`: `()` -error: aborting due to 7 previous errors +error: matching over `()` is more explicit + --> $DIR/ignored_unit_patterns.rs:45:13 + | +LL | (1, _) => unimplemented!(), + | ^ help: use `()` instead of `_`: `()` + +error: matching over `()` is more explicit + --> $DIR/ignored_unit_patterns.rs:52:13 + | +LL | for (x, _) in v { + | ^ help: use `()` instead of `_`: `()` + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs index e6ff821a8ad..448d0114dff 100644 --- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs +++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs @@ -3,127 +3,117 @@ use std::iter::IntoIterator; -fn main() { - { - struct S; - - impl<'a> IntoIterator for &'a S { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method - type IntoIter = std::slice::Iter<'a, u8>; - type Item = &'a u8; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } - impl<'a> IntoIterator for &'a mut S { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method - type IntoIter = std::slice::IterMut<'a, u8>; - type Item = &'a mut u8; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +pub struct S1; +impl<'a> IntoIterator for &'a S1 { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + type IntoIter = std::slice::Iter<'a, u8>; + type Item = &'a u8; + fn into_iter(self) -> Self::IntoIter { + todo!() } - { - struct S<T>(T); - impl<'a, T> IntoIterator for &'a S<T> { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method - type IntoIter = std::slice::Iter<'a, T>; - type Item = &'a T; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } - impl<'a, T> IntoIterator for &'a mut S<T> { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method - type IntoIter = std::slice::IterMut<'a, T>; - type Item = &'a mut T; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +} +impl<'a> IntoIterator for &'a mut S1 { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, u8>; + type Item = &'a mut u8; + fn into_iter(self) -> Self::IntoIter { + todo!() } - { - // Both iter and iter_mut methods exist, don't lint - struct S<'a, T>(&'a T); - - impl<'a, T> S<'a, T> { - fn iter(&self) -> std::slice::Iter<'a, T> { - todo!() - } - fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { - todo!() - } - } +} - impl<'a, T> IntoIterator for &S<'a, T> { - type IntoIter = std::slice::Iter<'a, T>; - type Item = &'a T; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +pub struct S2<T>(T); +impl<'a, T> IntoIterator for &'a S2<T> { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +impl<'a, T> IntoIterator for &'a mut S2<T> { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} - impl<'a, T> IntoIterator for &mut S<'a, T> { - type IntoIter = std::slice::IterMut<'a, T>; - type Item = &'a mut T; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +// Both iter and iter_mut methods exist, don't lint +pub struct S3<'a, T>(&'a T); +impl<'a, T> S3<'a, T> { + fn iter(&self) -> std::slice::Iter<'a, T> { + todo!() + } + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { + todo!() + } +} +impl<'a, T> IntoIterator for &S3<'a, T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} +impl<'a, T> IntoIterator for &mut S3<'a, T> { + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() } - { - // Only `iter` exists, no `iter_mut` - struct S<'a, T>(&'a T); +} - impl<'a, T> S<'a, T> { - fn iter(&self) -> std::slice::Iter<'a, T> { - todo!() - } - } +// Only `iter` exists, no `iter_mut` +pub struct S4<'a, T>(&'a T); - impl<'a, T> IntoIterator for &S<'a, T> { - type IntoIter = std::slice::Iter<'a, T>; - type Item = &'a T; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +impl<'a, T> S4<'a, T> { + fn iter(&self) -> std::slice::Iter<'a, T> { + todo!() + } +} - impl<'a, T> IntoIterator for &mut S<'a, T> { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method - type IntoIter = std::slice::IterMut<'a, T>; - type Item = &'a mut T; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +impl<'a, T> IntoIterator for &S4<'a, T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() } - { - // `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize" - // aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead - // to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias). - struct S; +} - impl S { - fn iter(&self) -> std::slice::Iter<'static, u8> { - todo!() - } - } +impl<'a, T> IntoIterator for &mut S4<'a, T> { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} - type Alias = S; +// `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize" +// aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead +// to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias). +pub struct S5; - impl IntoIterator for &Alias { - type IntoIter = std::slice::Iter<'static, u8>; - type Item = &'static u8; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +impl S5 { + fn iter(&self) -> std::slice::Iter<'static, u8> { + todo!() + } +} + +pub type Alias = S5; + +impl IntoIterator for &Alias { + type IntoIter = std::slice::Iter<'static, u8>; + type Item = &'static u8; + fn into_iter(self) -> Self::IntoIter { + todo!() } } -fn issue11635() { +fn main() {} + +pub mod issue11635 { // A little more involved than the original repro in the issue, but this tests that it correctly // works for more than one deref step diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr index f543d1d8e86..70f3f82a936 100644 --- a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr +++ b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr @@ -1,21 +1,21 @@ error: `IntoIterator` implemented for a reference type without an `iter` method - --> $DIR/into_iter_without_iter.rs:10:9 + --> $DIR/into_iter_without_iter.rs:7:1 | -LL | / impl<'a> IntoIterator for &'a S { +LL | / impl<'a> IntoIterator for &'a S1 { LL | | -LL | | type IntoIter = std::slice::Iter<'a, u8>; -LL | | type Item = &'a u8; +LL | | type IntoIter = std::slice::Iter<'a, u8>; +LL | | type Item = &'a u8; ... | -LL | | } -LL | | } - | |_________^ +LL | | } +LL | | } + | |_^ | = note: `-D clippy::into-iter-without-iter` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::into_iter_without_iter)]` help: consider implementing `iter` | -LL ~ -LL + impl S { +LL + +LL + impl S1 { LL + fn iter(&self) -> std::slice::Iter<'a, u8> { LL + <&Self as IntoIterator>::into_iter(self) LL + } @@ -23,21 +23,21 @@ LL + } | error: `IntoIterator` implemented for a reference type without an `iter_mut` method - --> $DIR/into_iter_without_iter.rs:18:9 + --> $DIR/into_iter_without_iter.rs:15:1 | -LL | / impl<'a> IntoIterator for &'a mut S { +LL | / impl<'a> IntoIterator for &'a mut S1 { LL | | -LL | | type IntoIter = std::slice::IterMut<'a, u8>; -LL | | type Item = &'a mut u8; +LL | | type IntoIter = std::slice::IterMut<'a, u8>; +LL | | type Item = &'a mut u8; ... | -LL | | } -LL | | } - | |_________^ +LL | | } +LL | | } + | |_^ | help: consider implementing `iter_mut` | -LL ~ -LL + impl S { +LL + +LL + impl S1 { LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, u8> { LL + <&mut Self as IntoIterator>::into_iter(self) LL + } @@ -45,21 +45,21 @@ LL + } | error: `IntoIterator` implemented for a reference type without an `iter` method - --> $DIR/into_iter_without_iter.rs:29:9 + --> $DIR/into_iter_without_iter.rs:25:1 | -LL | / impl<'a, T> IntoIterator for &'a S<T> { +LL | / impl<'a, T> IntoIterator for &'a S2<T> { LL | | -LL | | type IntoIter = std::slice::Iter<'a, T>; -LL | | type Item = &'a T; +LL | | type IntoIter = std::slice::Iter<'a, T>; +LL | | type Item = &'a T; ... | -LL | | } -LL | | } - | |_________^ +LL | | } +LL | | } + | |_^ | help: consider implementing `iter` | -LL ~ -LL + impl S<T> { +LL + +LL + impl S2<T> { LL + fn iter(&self) -> std::slice::Iter<'a, T> { LL + <&Self as IntoIterator>::into_iter(self) LL + } @@ -67,21 +67,21 @@ LL + } | error: `IntoIterator` implemented for a reference type without an `iter_mut` method - --> $DIR/into_iter_without_iter.rs:37:9 + --> $DIR/into_iter_without_iter.rs:33:1 | -LL | / impl<'a, T> IntoIterator for &'a mut S<T> { +LL | / impl<'a, T> IntoIterator for &'a mut S2<T> { LL | | -LL | | type IntoIter = std::slice::IterMut<'a, T>; -LL | | type Item = &'a mut T; +LL | | type IntoIter = std::slice::IterMut<'a, T>; +LL | | type Item = &'a mut T; ... | -LL | | } -LL | | } - | |_________^ +LL | | } +LL | | } + | |_^ | help: consider implementing `iter_mut` | -LL ~ -LL + impl S<T> { +LL + +LL + impl S2<T> { LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { LL + <&mut Self as IntoIterator>::into_iter(self) LL + } @@ -89,21 +89,21 @@ LL + } | error: `IntoIterator` implemented for a reference type without an `iter_mut` method - --> $DIR/into_iter_without_iter.rs:93:9 + --> $DIR/into_iter_without_iter.rs:84:1 | -LL | / impl<'a, T> IntoIterator for &mut S<'a, T> { +LL | / impl<'a, T> IntoIterator for &mut S4<'a, T> { LL | | -LL | | type IntoIter = std::slice::IterMut<'a, T>; -LL | | type Item = &'a mut T; +LL | | type IntoIter = std::slice::IterMut<'a, T>; +LL | | type Item = &'a mut T; ... | -LL | | } -LL | | } - | |_________^ +LL | | } +LL | | } + | |_^ | help: consider implementing `iter_mut` | -LL ~ -LL + impl S<'a, T> { +LL + +LL + impl S4<'a, T> { LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { LL + <&mut Self as IntoIterator>::into_iter(self) LL + } diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.rs b/src/tools/clippy/tests/ui/iter_without_into_iter.rs index cedb756c79d..29f526b455c 100644 --- a/src/tools/clippy/tests/ui/iter_without_into_iter.rs +++ b/src/tools/clippy/tests/ui/iter_without_into_iter.rs @@ -1,120 +1,124 @@ //@no-rustfix #![warn(clippy::iter_without_into_iter)] -fn main() { - { - struct S; - impl S { - pub fn iter(&self) -> std::slice::Iter<'_, u8> { - //~^ ERROR: `iter` method without an `IntoIterator` impl - [].iter() - } - pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { - //~^ ERROR: `iter_mut` method without an `IntoIterator` impl - [].iter_mut() - } - } - } - { - struct S; - impl S { - pub fn iter(&self) -> impl Iterator<Item = &u8> { - // RPITIT is not stable, so we can't generally suggest it here yet - [].iter() - } - } - } - { - struct S<'a>(&'a mut [u8]); - impl<'a> S<'a> { - pub fn iter(&self) -> std::slice::Iter<'_, u8> { - //~^ ERROR: `iter` method without an `IntoIterator` impl - self.0.iter() - } - pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { - //~^ ERROR: `iter_mut` method without an `IntoIterator` impl - self.0.iter_mut() - } - } - } - { - // Incompatible signatures - struct S; - impl S { - pub fn iter(self) -> std::slice::Iter<'static, u8> { - todo!() - } - } - struct S2; - impl S2 { - pub async fn iter(&self) -> std::slice::Iter<'static, u8> { - todo!() - } - } - struct S3; - impl S3 { - pub fn iter(&self, _additional_param: ()) -> std::slice::Iter<'static, u8> { - todo!() - } - } - struct S4<T>(T); - impl<T> S4<T> { - pub fn iter<U>(&self) -> std::slice::Iter<'static, (T, U)> { - todo!() - } - } - struct S5<T>(T); - impl<T> S5<T> { - pub fn iter(&self) -> std::slice::Iter<'static, T> { - todo!() - } - } - } - { - struct S<T>(T); - impl<T> S<T> { - pub fn iter(&self) -> std::slice::Iter<'_, T> { - //~^ ERROR: `iter` method without an `IntoIterator` impl - todo!() - } - pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { - //~^ ERROR: `iter_mut` method without an `IntoIterator` impl - todo!() - } - } - } - { - struct S<T>(T); - impl<T> S<T> { - pub fn iter(&self) -> std::slice::Iter<'_, T> { - // Don't lint, there's an existing (wrong) IntoIterator impl - todo!() - } - } +pub struct S1; +impl S1 { + pub fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + [].iter() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + [].iter_mut() + } +} + +pub struct S2; +impl S2 { + pub fn iter(&self) -> impl Iterator<Item = &u8> { + // RPITIT is not stable, so we can't generally suggest it here yet + [].iter() + } +} + +pub struct S3<'a>(&'a mut [u8]); +impl<'a> S3<'a> { + pub fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + self.0.iter() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + self.0.iter_mut() + } +} + +// Incompatible signatures +pub struct S4; +impl S4 { + pub fn iter(self) -> std::slice::Iter<'static, u8> { + todo!() + } +} + +pub struct S5; +impl S5 { + pub async fn iter(&self) -> std::slice::Iter<'static, u8> { + todo!() + } +} + +pub struct S6; +impl S6 { + pub fn iter(&self, _additional_param: ()) -> std::slice::Iter<'static, u8> { + todo!() + } +} + +pub struct S7<T>(T); +impl<T> S7<T> { + pub fn iter<U>(&self) -> std::slice::Iter<'static, (T, U)> { + todo!() + } +} + +pub struct S8<T>(T); +impl<T> S8<T> { + pub fn iter(&self) -> std::slice::Iter<'static, T> { + todo!() + } +} + +// =========================== +pub struct S9<T>(T); +impl<T> S9<T> { + pub fn iter(&self) -> std::slice::Iter<'_, T> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + todo!() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + todo!() + } +} + +pub struct S10<T>(T); +impl<T> S10<T> { + pub fn iter(&self) -> std::slice::Iter<'_, T> { + // Don't lint, there's an existing (wrong) IntoIterator impl + todo!() + } +} + +impl<'a, T> IntoIterator for &'a S10<T> { + type Item = &'a String; + type IntoIter = std::slice::Iter<'a, String>; + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} - impl<'a, T> IntoIterator for &'a S<T> { - type Item = &'a String; - type IntoIter = std::slice::Iter<'a, String>; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } - } - { - struct S<T>(T); - impl<T> S<T> { - pub fn iter_mut(&self) -> std::slice::IterMut<'_, T> { - // Don't lint, there's an existing (wrong) IntoIterator impl - todo!() - } - } +pub struct S11<T>(T); +impl<T> S11<T> { + pub fn iter_mut(&self) -> std::slice::IterMut<'_, T> { + // Don't lint, there's an existing (wrong) IntoIterator impl + todo!() + } +} +impl<'a, T> IntoIterator for &'a mut S11<T> { + type Item = &'a mut String; + type IntoIter = std::slice::IterMut<'a, String>; + fn into_iter(self) -> Self::IntoIter { + todo!() + } +} - impl<'a, T> IntoIterator for &'a mut S<T> { - type Item = &'a mut String; - type IntoIter = std::slice::IterMut<'a, String>; - fn into_iter(self) -> Self::IntoIter { - todo!() - } - } +// Private type not exported: don't lint +struct S12; +impl S12 { + fn iter(&self) -> std::slice::Iter<'_, u8> { + todo!() } } + +fn main() {} diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr index 9d0b99415a5..af5afd47bfc 100644 --- a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr +++ b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr @@ -1,146 +1,146 @@ -error: `iter` method without an `IntoIterator` impl for `&S` - --> $DIR/iter_without_into_iter.rs:8:13 +error: `iter` method without an `IntoIterator` impl for `&S1` + --> $DIR/iter_without_into_iter.rs:6:5 | -LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { LL | | -LL | | [].iter() -LL | | } - | |_____________^ +LL | | [].iter() +LL | | } + | |_____^ | = note: `-D clippy::iter-without-into-iter` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::iter_without_into_iter)]` -help: consider implementing `IntoIterator` for `&S` +help: consider implementing `IntoIterator` for `&S1` | -LL ~ -LL + impl IntoIterator for &S { +LL + +LL + impl IntoIterator for &S1 { LL + type IntoIter = std::slice::Iter<'_, u8>; -LL + type Iter = &u8; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &u8; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } | -error: `iter_mut` method without an `IntoIterator` impl for `&mut S` - --> $DIR/iter_without_into_iter.rs:12:13 +error: `iter_mut` method without an `IntoIterator` impl for `&mut S1` + --> $DIR/iter_without_into_iter.rs:10:5 | -LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { LL | | -LL | | [].iter_mut() -LL | | } - | |_____________^ +LL | | [].iter_mut() +LL | | } + | |_____^ | -help: consider implementing `IntoIterator` for `&mut S` +help: consider implementing `IntoIterator` for `&mut S1` | -LL ~ -LL + impl IntoIterator for &mut S { +LL + +LL + impl IntoIterator for &mut S1 { LL + type IntoIter = std::slice::IterMut<'_, u8>; -LL + type Iter = &mut u8; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &mut u8; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } | -error: `iter` method without an `IntoIterator` impl for `&S<'a>` - --> $DIR/iter_without_into_iter.rs:30:13 +error: `iter` method without an `IntoIterator` impl for `&S3<'a>` + --> $DIR/iter_without_into_iter.rs:26:5 | -LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { LL | | -LL | | self.0.iter() -LL | | } - | |_____________^ +LL | | self.0.iter() +LL | | } + | |_____^ | -help: consider implementing `IntoIterator` for `&S<'a>` +help: consider implementing `IntoIterator` for `&S3<'a>` | -LL ~ -LL + impl IntoIterator for &S<'a> { +LL + +LL + impl IntoIterator for &S3<'a> { LL + type IntoIter = std::slice::Iter<'_, u8>; -LL + type Iter = &u8; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &u8; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } | -error: `iter_mut` method without an `IntoIterator` impl for `&mut S<'a>` - --> $DIR/iter_without_into_iter.rs:34:13 +error: `iter_mut` method without an `IntoIterator` impl for `&mut S3<'a>` + --> $DIR/iter_without_into_iter.rs:30:5 | -LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { LL | | -LL | | self.0.iter_mut() -LL | | } - | |_____________^ +LL | | self.0.iter_mut() +LL | | } + | |_____^ | -help: consider implementing `IntoIterator` for `&mut S<'a>` +help: consider implementing `IntoIterator` for `&mut S3<'a>` | -LL ~ -LL + impl IntoIterator for &mut S<'a> { +LL + +LL + impl IntoIterator for &mut S3<'a> { LL + type IntoIter = std::slice::IterMut<'_, u8>; -LL + type Iter = &mut u8; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &mut u8; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } | -error: `iter` method without an `IntoIterator` impl for `&S5<T>` - --> $DIR/iter_without_into_iter.rs:68:13 +error: `iter` method without an `IntoIterator` impl for `&S8<T>` + --> $DIR/iter_without_into_iter.rs:67:5 | -LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> { -LL | | todo!() -LL | | } - | |_____________^ +LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> { +LL | | todo!() +LL | | } + | |_____^ | -help: consider implementing `IntoIterator` for `&S5<T>` +help: consider implementing `IntoIterator` for `&S8<T>` | -LL ~ -LL + impl IntoIterator for &S5<T> { +LL + +LL + impl IntoIterator for &S8<T> { LL + type IntoIter = std::slice::Iter<'static, T>; -LL + type Iter = &T; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &T; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } | -error: `iter` method without an `IntoIterator` impl for `&S<T>` - --> $DIR/iter_without_into_iter.rs:76:13 +error: `iter` method without an `IntoIterator` impl for `&S9<T>` + --> $DIR/iter_without_into_iter.rs:75:5 | -LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> { +LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> { LL | | -LL | | todo!() -LL | | } - | |_____________^ +LL | | todo!() +LL | | } + | |_____^ | -help: consider implementing `IntoIterator` for `&S<T>` +help: consider implementing `IntoIterator` for `&S9<T>` | -LL ~ -LL + impl IntoIterator for &S<T> { +LL + +LL + impl IntoIterator for &S9<T> { LL + type IntoIter = std::slice::Iter<'_, T>; -LL + type Iter = &T; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &T; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } | -error: `iter_mut` method without an `IntoIterator` impl for `&mut S<T>` - --> $DIR/iter_without_into_iter.rs:80:13 +error: `iter_mut` method without an `IntoIterator` impl for `&mut S9<T>` + --> $DIR/iter_without_into_iter.rs:79:5 | -LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { LL | | -LL | | todo!() -LL | | } - | |_____________^ +LL | | todo!() +LL | | } + | |_____^ | -help: consider implementing `IntoIterator` for `&mut S<T>` +help: consider implementing `IntoIterator` for `&mut S9<T>` | -LL ~ -LL + impl IntoIterator for &mut S<T> { +LL + +LL + impl IntoIterator for &mut S9<T> { LL + type IntoIter = std::slice::IterMut<'_, T>; -LL + type Iter = &mut T; -LL + fn into_iter() -> Self::IntoIter { +LL + type Item = &mut T; +LL + fn into_iter(self) -> Self::IntoIter { LL + self.iter() LL + } LL + } diff --git a/src/tools/clippy/tests/ui/let_and_return.fixed b/src/tools/clippy/tests/ui/let_and_return.fixed index 88b8ae67375..b5584fcde8c 100644 --- a/src/tools/clippy/tests/ui/let_and_return.fixed +++ b/src/tools/clippy/tests/ui/let_and_return.fixed @@ -168,7 +168,26 @@ mod issue_5729 { impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> { fn foo_cloned(&self) -> Arc<dyn Foo> { - Arc::clone(&self.foo) as _ + (Arc::clone(&self.foo)) as _ + //~^ ERROR: returning the result of a `let` binding from a block + } + } +} + +mod issue_11335 { + pub enum E<T> { + A(T), + B(T), + } + + impl<T> E<T> { + pub fn inner(&self) -> &T { + + + (match self { + E::A(x) => x, + E::B(x) => x, + }) as _ //~^ ERROR: returning the result of a `let` binding from a block } } diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs index f366842c5d7..f13c7c4e203 100644 --- a/src/tools/clippy/tests/ui/let_and_return.rs +++ b/src/tools/clippy/tests/ui/let_and_return.rs @@ -174,6 +174,25 @@ mod issue_5729 { } } +mod issue_11335 { + pub enum E<T> { + A(T), + B(T), + } + + impl<T> E<T> { + pub fn inner(&self) -> &T { + let result = match self { + E::A(x) => x, + E::B(x) => x, + }; + + result + //~^ ERROR: returning the result of a `let` binding from a block + } + } +} + // https://github.com/rust-lang/rust-clippy/issues/11167 macro_rules! fn_in_macro { ($b:block) => { diff --git a/src/tools/clippy/tests/ui/let_and_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr index c09c2b32aad..fe60072d13f 100644 --- a/src/tools/clippy/tests/ui/let_and_return.stderr +++ b/src/tools/clippy/tests/ui/let_and_return.stderr @@ -53,8 +53,30 @@ LL | clone help: return the expression directly | LL ~ -LL ~ Arc::clone(&self.foo) as _ +LL ~ (Arc::clone(&self.foo)) as _ | -error: aborting due to 4 previous errors +error: returning the result of a `let` binding from a block + --> $DIR/let_and_return.rs:190:13 + | +LL | / let result = match self { +LL | | E::A(x) => x, +LL | | E::B(x) => x, +LL | | }; + | |______________- unnecessary `let` binding +LL | +LL | result + | ^^^^^^ + | +help: return the expression directly + | +LL ~ +LL | +LL ~ (match self { +LL + E::A(x) => x, +LL + E::B(x) => x, +LL + }) as _ + | + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs index 06968f8bae4..ee44909f37e 100644 --- a/src/tools/clippy/tests/ui/manual_filter.rs +++ b/src/tools/clippy/tests/ui/manual_filter.rs @@ -191,9 +191,7 @@ fn main() { None => None, }; let _ = match Some(15) { - Some(x) => unsafe { - if f(x) { Some(x) } else { None } - }, + Some(x) => unsafe { if f(x) { Some(x) } else { None } }, None => None, }; diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr index 1490f209735..b23ad887eb2 100644 --- a/src/tools/clippy/tests/ui/manual_filter.stderr +++ b/src/tools/clippy/tests/ui/manual_filter.stderr @@ -169,15 +169,13 @@ error: manual implementation of `Option::filter` | LL | let _ = match Some(15) { | _____________^ -LL | | Some(x) => unsafe { -LL | | if f(x) { Some(x) } else { None } -LL | | }, +LL | | Some(x) => unsafe { if f(x) { Some(x) } else { None } }, LL | | None => None, LL | | }; | |_____^ help: try: `Some(15).filter(|&x| unsafe { f(x) })` error: manual implementation of `Option::filter` - --> $DIR/manual_filter.rs:203:12 + --> $DIR/manual_filter.rs:201:12 | LL | } else if let Some(x) = Some(16) { | ____________^ diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs index 6775fdc921f..27717ab3a73 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.rs +++ b/src/tools/clippy/tests/ui/manual_let_else.rs @@ -35,9 +35,7 @@ fn fire() { let v = if let Some(v) = g() { //~^ ERROR: this could be rewritten as `let...else` // Blocks around the identity should have no impact - { - { v } - } + { { v } } } else { // Some computation should still make it fire g(); diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index 49dbd7615e0..2b6504a1827 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -31,7 +31,7 @@ error: this could be rewritten as `let...else` LL | / let v = if let Some(v) = g() { LL | | LL | | // Blocks around the identity should have no impact -LL | | { +LL | | { { v } } ... | LL | | return; LL | | }; @@ -47,25 +47,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:49:9 + --> $DIR/manual_let_else.rs:47:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:51:9 + --> $DIR/manual_let_else.rs:49:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:56:5 + --> $DIR/manual_let_else.rs:54:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:60:5 + --> $DIR/manual_let_else.rs:58:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -83,7 +83,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:68:5 + --> $DIR/manual_let_else.rs:66:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -101,7 +101,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:76:5 + --> $DIR/manual_let_else.rs:74:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -121,7 +121,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:87:5 + --> $DIR/manual_let_else.rs:85:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -143,13 +143,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:98:5 + --> $DIR/manual_let_else.rs:96:5 | LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:102:5 + --> $DIR/manual_let_else.rs:100:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -170,7 +170,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:112:5 + --> $DIR/manual_let_else.rs:110:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -191,7 +191,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:122:5 + --> $DIR/manual_let_else.rs:120:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -220,7 +220,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:140:5 + --> $DIR/manual_let_else.rs:138:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | @@ -238,7 +238,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:148:5 + --> $DIR/manual_let_else.rs:146:5 | LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { LL | | @@ -256,7 +256,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:158:13 + --> $DIR/manual_let_else.rs:156:13 | LL | let $n = if let Some(v) = $e { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` @@ -267,19 +267,19 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:167:5 + --> $DIR/manual_let_else.rs:165:5 | LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:171:5 + --> $DIR/manual_let_else.rs:169:5 | LL | let mut v = if let Variant::B(b) = e() { b } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:176:5 + --> $DIR/manual_let_else.rs:174:5 | LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { LL | | @@ -297,19 +297,19 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:183:5 + --> $DIR/manual_let_else.rs:181:5 | LL | let v = if let Variant::A(.., a) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:187:5 + --> $DIR/manual_let_else.rs:185:5 | LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:191:5 + --> $DIR/manual_let_else.rs:189:5 | LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -327,7 +327,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:199:5 + --> $DIR/manual_let_else.rs:197:5 | LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -345,7 +345,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:207:5 + --> $DIR/manual_let_else.rs:205:5 | LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> { LL | | @@ -363,7 +363,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:324:5 + --> $DIR/manual_let_else.rs:322:5 | LL | / let _ = match ff { LL | | diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.fixed b/src/tools/clippy/tests/ui/manual_map_option_2.fixed index 513f6e32340..f5bb4e0af1b 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option_2.fixed @@ -42,9 +42,7 @@ fn main() { // Lint. `s` is captured by reference, so no lifetime issues. let s = Some(String::new()); - let _ = s.as_ref().map(|x| { - if let Some(ref s) = s { (x.clone(), s) } else { panic!() } - }); + let _ = s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }); // Issue #7820 unsafe fn f(x: u32) -> u32 { diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.rs b/src/tools/clippy/tests/ui/manual_map_option_2.rs index fd186743fe2..cbc2356e0a2 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.rs +++ b/src/tools/clippy/tests/ui/manual_map_option_2.rs @@ -46,9 +46,7 @@ fn main() { // Lint. `s` is captured by reference, so no lifetime issues. let s = Some(String::new()); let _ = match &s { - Some(x) => Some({ - if let Some(ref s) = s { (x.clone(), s) } else { panic!() } - }), + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), None => None, }; diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.stderr b/src/tools/clippy/tests/ui/manual_map_option_2.stderr index bf242c0416c..d3754f22d89 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option_2.stderr @@ -26,22 +26,13 @@ error: manual implementation of `Option::map` | LL | let _ = match &s { | _____________^ -LL | | Some(x) => Some({ -LL | | if let Some(ref s) = s { (x.clone(), s) } else { panic!() } -LL | | }), +LL | | Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), LL | | None => None, LL | | }; - | |_____^ - | -help: try - | -LL ~ let _ = s.as_ref().map(|x| { -LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() } -LL ~ }); - | + | |_____^ help: try: `s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } })` error: manual implementation of `Option::map` - --> $DIR/manual_map_option_2.rs:60:17 + --> $DIR/manual_map_option_2.rs:58:17 | LL | let _ = match Some(0) { | _________________^ @@ -51,7 +42,7 @@ LL | | }; | |_________^ help: try: `Some(0).map(|x| f(x))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option_2.rs:65:13 + --> $DIR/manual_map_option_2.rs:63:13 | LL | let _ = match Some(0) { | _____________^ @@ -61,7 +52,7 @@ LL | | }; | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })` error: manual implementation of `Option::map` - --> $DIR/manual_map_option_2.rs:69:13 + --> $DIR/manual_map_option_2.rs:67:13 | LL | let _ = match Some(0) { | _____________^ diff --git a/src/tools/clippy/tests/ui/manual_string_new.fixed b/src/tools/clippy/tests/ui/manual_string_new.fixed index 273be4e0fd2..2d4c5a02915 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.fixed +++ b/src/tools/clippy/tests/ui/manual_string_new.fixed @@ -1,4 +1,5 @@ #![warn(clippy::manual_string_new)] +#![allow(clippy::unnecessary_fallible_conversions)] macro_rules! create_strings_from_macro { // When inside a macro, nothing should warn to prevent false positives. diff --git a/src/tools/clippy/tests/ui/manual_string_new.rs b/src/tools/clippy/tests/ui/manual_string_new.rs index 0d5514fc893..20f0be6aaf9 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.rs +++ b/src/tools/clippy/tests/ui/manual_string_new.rs @@ -1,4 +1,5 @@ #![warn(clippy::manual_string_new)] +#![allow(clippy::unnecessary_fallible_conversions)] macro_rules! create_strings_from_macro { // When inside a macro, nothing should warn to prevent false positives. diff --git a/src/tools/clippy/tests/ui/manual_string_new.stderr b/src/tools/clippy/tests/ui/manual_string_new.stderr index 399652d3fec..cb2d78c39ed 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.stderr +++ b/src/tools/clippy/tests/ui/manual_string_new.stderr @@ -1,5 +1,5 @@ error: empty String is being created manually - --> $DIR/manual_string_new.rs:13:13 + --> $DIR/manual_string_new.rs:14:13 | LL | let _ = "".to_string(); | ^^^^^^^^^^^^^^ help: consider using: `String::new()` @@ -8,49 +8,49 @@ LL | let _ = "".to_string(); = help: to override `-D warnings` add `#[allow(clippy::manual_string_new)]` error: empty String is being created manually - --> $DIR/manual_string_new.rs:16:13 + --> $DIR/manual_string_new.rs:17:13 | LL | let _ = "".to_owned(); | ^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:19:21 + --> $DIR/manual_string_new.rs:20:21 | LL | let _: String = "".into(); | ^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:26:13 + --> $DIR/manual_string_new.rs:27:13 | LL | let _ = String::from(""); | ^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:27:13 + --> $DIR/manual_string_new.rs:28:13 | LL | let _ = <String>::from(""); | ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:32:13 + --> $DIR/manual_string_new.rs:33:13 | LL | let _ = String::try_from("").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:38:21 + --> $DIR/manual_string_new.rs:39:21 | LL | let _: String = From::from(""); | ^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:43:21 + --> $DIR/manual_string_new.rs:44:21 | LL | let _: String = TryFrom::try_from("").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:46:21 + --> $DIR/manual_string_new.rs:47:21 | LL | let _: String = TryFrom::try_from("").expect("this should warn"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed index e756d9b5935..62b0ba01860 100644 --- a/src/tools/clippy/tests/ui/map_identity.fixed +++ b/src/tools/clippy/tests/ui/map_identity.fixed @@ -22,6 +22,30 @@ fn main() { let _ = Ok(1).map_err(std::convert::identity::<u32>); } +fn issue7189() { + // should lint + let x = [(1, 2), (3, 4)]; + let _ = x.iter(); + let _ = x.iter(); + let _ = x.iter(); + + let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))]; + let _ = y.iter(); + + // should not lint + let _ = x.iter().map(|(x, y)| (x, y, y)); + let _ = x.iter().map(|(x, _y)| (x,)); + let _ = x.iter().map(|(x, _)| (x,)); + let _ = x.iter().map(|(x, ..)| (x,)); + let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z))); + let _ = y + .iter() + .map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z))); + let _ = y + .iter() + .map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,)))); +} + fn not_identity(x: &u16) -> u16 { *x } diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs index 74cbaade405..b7f4c99f273 100644 --- a/src/tools/clippy/tests/ui/map_identity.rs +++ b/src/tools/clippy/tests/ui/map_identity.rs @@ -24,6 +24,32 @@ fn main() { let _ = Ok(1).map_err(std::convert::identity::<u32>); } +fn issue7189() { + // should lint + let x = [(1, 2), (3, 4)]; + let _ = x.iter().map(|(x, y)| (x, y)); + let _ = x.iter().map(|(x, y)| { + return (x, y); + }); + let _ = x.iter().map(|(x, y)| return (x, y)); + + let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))]; + let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); + + // should not lint + let _ = x.iter().map(|(x, y)| (x, y, y)); + let _ = x.iter().map(|(x, _y)| (x,)); + let _ = x.iter().map(|(x, _)| (x,)); + let _ = x.iter().map(|(x, ..)| (x,)); + let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z))); + let _ = y + .iter() + .map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z))); + let _ = y + .iter() + .map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,)))); +} + fn not_identity(x: &u16) -> u16 { *x } diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr index 8942fd7c0d2..4ca24b0b04c 100644 --- a/src/tools/clippy/tests/ui/map_identity.stderr +++ b/src/tools/clippy/tests/ui/map_identity.stderr @@ -40,5 +40,32 @@ error: unnecessary map of the identity function LL | let _: Result<u32, u32> = Ok(1).map_err(|a| a); | ^^^^^^^^^^^^^^^ help: remove the call to `map_err` -error: aborting due to 6 previous errors +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:30:21 + | +LL | let _ = x.iter().map(|(x, y)| (x, y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:31:21 + | +LL | let _ = x.iter().map(|(x, y)| { + | _____________________^ +LL | | return (x, y); +LL | | }); + | |______^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:34:21 + | +LL | let _ = x.iter().map(|(x, y)| return (x, y)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:37:21 + | +LL | let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs index e1b95aa5776..5c277f925a8 100644 --- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs @@ -9,12 +9,12 @@ fn repeat() -> ! { } pub fn f(x: Ordering) { + #[deny(non_exhaustive_omitted_patterns)] match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - #[deny(non_exhaustive_omitted_patterns)] _ => repeat(), } } diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs index c8a0d664167..3917bb9e03d 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs +++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs @@ -11,13 +11,12 @@ fn outer_attr() {} mod multiple { #![clippy::msrv = "1.40"] #![clippy::msrv = "=1.35.0"] - //~^ ERROR: `msrv` is defined multiple times #![clippy::msrv = "1.10.1"] - //~^ ERROR: `msrv` is defined multiple times + //~^ ERROR: `clippy::msrv` is defined multiple times mod foo { #![clippy::msrv = "1"] #![clippy::msrv = "1.0.0"] - //~^ ERROR: `msrv` is defined multiple times + //~^ ERROR: `clippy::msrv` is defined multiple times } } diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr index 8d4071e258e..cf8392f0316 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr +++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr @@ -10,20 +10,8 @@ error: `invalid.version` is not a valid Rust version LL | #[clippy::msrv = "invalid.version"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `msrv` is defined multiple times - --> $DIR/min_rust_version_invalid_attr.rs:13:5 - | -LL | #![clippy::msrv = "=1.35.0"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: first definition found here - --> $DIR/min_rust_version_invalid_attr.rs:12:5 - | -LL | #![clippy::msrv = "1.40"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `msrv` is defined multiple times - --> $DIR/min_rust_version_invalid_attr.rs:15:5 +error: `clippy::msrv` is defined multiple times + --> $DIR/min_rust_version_invalid_attr.rs:14:5 | LL | #![clippy::msrv = "1.10.1"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,17 +22,17 @@ note: first definition found here LL | #![clippy::msrv = "1.40"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `msrv` is defined multiple times - --> $DIR/min_rust_version_invalid_attr.rs:20:9 +error: `clippy::msrv` is defined multiple times + --> $DIR/min_rust_version_invalid_attr.rs:19:9 | LL | #![clippy::msrv = "1.0.0"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first definition found here - --> $DIR/min_rust_version_invalid_attr.rs:19:9 + --> $DIR/min_rust_version_invalid_attr.rs:18:9 | LL | #![clippy::msrv = "1"] | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed index b84182c5756..be35dcddbe6 100644 --- a/src/tools/clippy/tests/ui/needless_if.fixed +++ b/src/tools/clippy/tests/ui/needless_if.fixed @@ -39,11 +39,21 @@ fn main() { } // Do not lint `if let` or let chains if let true = true {} - if let true = true && true {} - if true && let true = true {} + if let true = true + && true + {} + if true + && let true = true + {} // Can lint nested `if let`s ({ - if let true = true && true { true } else { false } + if let true = true + && true + { + true + } else { + false + } } && true); external! { if (true) {} } with_span! { diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs index 6c6023c72dc..e2ad17e69a8 100644 --- a/src/tools/clippy/tests/ui/needless_if.rs +++ b/src/tools/clippy/tests/ui/needless_if.rs @@ -39,11 +39,21 @@ fn main() { } // Do not lint `if let` or let chains if let true = true {} - if let true = true && true {} - if true && let true = true {} + if let true = true + && true + {} + if true + && let true = true + {} // Can lint nested `if let`s if { - if let true = true && true { true } else { false } + if let true = true + && true + { + true + } else { + false + } } && true {} external! { if (true) {} } diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr index ed5b9452b86..c3e83c0f1f5 100644 --- a/src/tools/clippy/tests/ui/needless_if.stderr +++ b/src/tools/clippy/tests/ui/needless_if.stderr @@ -29,10 +29,13 @@ LL + }); | error: this `if` branch is empty - --> $DIR/needless_if.rs:45:5 + --> $DIR/needless_if.rs:49:5 | LL | / if { -LL | | if let true = true && true { true } else { false } +LL | | if let true = true +LL | | && true +LL | | { +... | LL | | } && true LL | | {} | |______^ @@ -40,24 +43,30 @@ LL | | {} help: you can remove it | LL ~ ({ -LL + if let true = true && true { true } else { false } +LL + if let true = true +LL + && true +LL + { +LL + true +LL + } else { +LL + false +LL + } LL + } && true); | error: this `if` branch is empty - --> $DIR/needless_if.rs:83:5 + --> $DIR/needless_if.rs:93:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> $DIR/needless_if.rs:85:5 + --> $DIR/needless_if.rs:95:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> $DIR/needless_if.rs:89:5 + --> $DIR/needless_if.rs:99:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 9f45da04862..891b2b01437 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -230,7 +230,9 @@ fn does_not_lint() { } let x; - if true && let Some(n) = Some("let chains too") { + if true + && let Some(n) = Some("let chains too") + { x = 1; } else { x = 2; diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index 0dab0faad56..55399511639 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -230,7 +230,9 @@ fn does_not_lint() { } let x; - if true && let Some(n) = Some("let chains too") { + if true + && let Some(n) = Some("let chains too") + { x = 1; } else { x = 2; 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 c3415a7df9e..f0113ca696e 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -1,7 +1,6 @@ #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, - clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let, clippy::let_unit_value, @@ -52,7 +51,7 @@ fn impure_else(arg: Option<i32>) { println!("return 1"); 1 }; - let _ = arg.map_or_else(|| side_effect(), |x| x); + let _ = arg.map_or_else(side_effect, |x| x); } fn test_map_or_else(arg: Option<u32>) { @@ -224,3 +223,17 @@ mod issue10729 { fn do_something(_value: &str) {} fn do_something2(_value: &mut str) {} } + +fn issue11429() { + use std::collections::HashMap; + + macro_rules! new_map { + () => {{ HashMap::new() }}; + } + + let opt: Option<HashMap<u8, u8>> = None; + + let mut _hashmap = opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone()); + + let mut _hm = opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone()); +} 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 86537f62057..18b7af44392 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -1,7 +1,6 @@ #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, - clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let, clippy::let_unit_value, @@ -271,3 +270,21 @@ mod issue10729 { fn do_something(_value: &str) {} fn do_something2(_value: &mut str) {} } + +fn issue11429() { + use std::collections::HashMap; + + macro_rules! new_map { + () => {{ HashMap::new() }}; + } + + let opt: Option<HashMap<u8, u8>> = None; + + let mut _hashmap = if let Some(hm) = &opt { + hm.clone() + } else { + HashMap::new() + }; + + let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; +} 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 6d7d02f8c25..e36357bcb38 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:12:5 + --> $DIR/option_if_let_else.rs:11:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -12,19 +12,19 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:30:13 + --> $DIR/option_if_let_else.rs:29: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:31:13 + --> $DIR/option_if_let_else.rs:30: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:32:13 + --> $DIR/option_if_let_else.rs:31:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -44,13 +44,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:38:13 + --> $DIR/option_if_let_else.rs:37: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:39:13 + --> $DIR/option_if_let_else.rs:38:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -70,7 +70,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:45:13 + --> $DIR/option_if_let_else.rs:44:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -90,7 +90,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:54:5 + --> $DIR/option_if_let_else.rs:53:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -109,7 +109,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:67:13 + --> $DIR/option_if_let_else.rs:66:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -118,10 +118,10 @@ LL | | } else { LL | | // map_or_else must be suggested LL | | side_effect() LL | | }; - | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` + | |_____^ 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:76:13 + --> $DIR/option_if_let_else.rs:75:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -144,7 +144,7 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:109:13 + --> $DIR/option_if_let_else.rs:108:13 | LL | / if let Some(idx) = s.find('.') { LL | | vec![s[..idx].to_string(), s[idx..].to_string()] @@ -154,7 +154,7 @@ LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:120:5 + --> $DIR/option_if_let_else.rs:119:5 | LL | / if let Ok(binding) = variable { LL | | println!("Ok {binding}"); @@ -173,13 +173,13 @@ LL + }) | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:142:13 + --> $DIR/option_if_let_else.rs:141: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:152:13 + --> $DIR/option_if_let_else.rs:151:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -201,13 +201,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:180:13 + --> $DIR/option_if_let_else.rs:179:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:184:13 + --> $DIR/option_if_let_else.rs:183:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -227,7 +227,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:223:13 + --> $DIR/option_if_let_else.rs:222:13 | LL | let _ = match s { | _____________^ @@ -237,7 +237,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:227:13 + --> $DIR/option_if_let_else.rs:226:13 | LL | let _ = match Some(10) { | _____________^ @@ -247,7 +247,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:233:13 + --> $DIR/option_if_let_else.rs:232:13 | LL | let _ = match res { | _____________^ @@ -257,7 +257,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:237:13 + --> $DIR/option_if_let_else.rs:236:13 | LL | let _ = match res { | _____________^ @@ -267,13 +267,13 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:241:13 + --> $DIR/option_if_let_else.rs:240:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:258:9 + --> $DIR/option_if_let_else.rs:257:9 | LL | / match initial { LL | | Some(value) => do_something(value), @@ -282,7 +282,7 @@ LL | | } | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:265:9 + --> $DIR/option_if_let_else.rs:264:9 | LL | / match initial { LL | | Some(value) => do_something2(value), @@ -290,5 +290,22 @@ LL | | None => {}, LL | | } | |_________^ help: try: `initial.as_mut().map_or({}, |value| do_something2(value))` -error: aborting due to 23 previous errors +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:283:24 + | +LL | let mut _hashmap = if let Some(hm) = &opt { + | ________________________^ +LL | | hm.clone() +LL | | } else { +LL | | HashMap::new() +LL | | }; + | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` + +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:289:19 + | +LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` + +error: aborting due to 25 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed index f23116a7e1c..f8af9092725 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.fixed +++ b/src/tools/clippy/tests/ui/redundant_guards.fixed @@ -48,7 +48,7 @@ fn main() { Some(x) if let Some(1) = x => { x; .. - } + }, _ => todo!(), }; let y = 1; diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs index c0206b4cec7..b46f8a6207e 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.rs +++ b/src/tools/clippy/tests/ui/redundant_guards.rs @@ -48,7 +48,7 @@ fn main() { Some(x) if let Some(1) = x => { x; .. - } + }, _ => todo!(), }; let y = 1; diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed index 60f9fb6d493..c9b76262d70 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -16,10 +16,15 @@ fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool { fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) { let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses - let _ = match maybe_some { // can't use `matches!` here - // because `expr` metavars in macros don't allow let exprs - None if let Some(x) = Some(0) && x > 5 => true, - _ => false + let _ = match maybe_some { + // can't use `matches!` here + // because `expr` metavars in macros don't allow let exprs + None if let Some(x) = Some(0) + && x > 5 => + { + true + }, + _ => false, }; } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs index 94bbb569c2a..a5f9caf659c 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -16,10 +16,15 @@ fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool { fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) { let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses - let _ = match maybe_some { // can't use `matches!` here - // because `expr` metavars in macros don't allow let exprs - None if let Some(x) = Some(0) && x > 5 => true, - _ => false + let _ = match maybe_some { + // can't use `matches!` here + // because `expr` metavars in macros don't allow let exprs + None if let Some(x) = Some(0) + && x > 5 => + { + true + }, + _ => false, }; } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr index fdf395d8286..a75551c56f2 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -14,49 +14,49 @@ LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard nee | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:27:12 + --> $DIR/redundant_pattern_matching_option.rs:32:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:29:12 + --> $DIR/redundant_pattern_matching_option.rs:34:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:31:12 + --> $DIR/redundant_pattern_matching_option.rs:36:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:37:15 + --> $DIR/redundant_pattern_matching_option.rs:42:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:39:15 + --> $DIR/redundant_pattern_matching_option.rs:44:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:41:15 + --> $DIR/redundant_pattern_matching_option.rs:46:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:44:15 + --> $DIR/redundant_pattern_matching_option.rs:49:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:52:5 + --> $DIR/redundant_pattern_matching_option.rs:57:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -65,7 +65,7 @@ LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:57:5 + --> $DIR/redundant_pattern_matching_option.rs:62:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -74,7 +74,7 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:62:13 + --> $DIR/redundant_pattern_matching_option.rs:67:13 | LL | let _ = match None::<()> { | _____________^ @@ -84,55 +84,55 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:68:20 + --> $DIR/redundant_pattern_matching_option.rs:73:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:74:20 + --> $DIR/redundant_pattern_matching_option.rs:79:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:76:19 + --> $DIR/redundant_pattern_matching_option.rs:81:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:82:12 + --> $DIR/redundant_pattern_matching_option.rs:87:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:97:12 + --> $DIR/redundant_pattern_matching_option.rs:102:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:99:12 + --> $DIR/redundant_pattern_matching_option.rs:104:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:101:15 + --> $DIR/redundant_pattern_matching_option.rs:106:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:103:15 + --> $DIR/redundant_pattern_matching_option.rs:108:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:105:5 + --> $DIR/redundant_pattern_matching_option.rs:110:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -141,7 +141,7 @@ LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:110:5 + --> $DIR/redundant_pattern_matching_option.rs:115:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -150,19 +150,19 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:118:12 + --> $DIR/redundant_pattern_matching_option.rs:123:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:119:12 + --> $DIR/redundant_pattern_matching_option.rs:124:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:125:5 + --> $DIR/redundant_pattern_matching_option.rs:130:5 | LL | / match x { LL | | Some(_) => true, @@ -171,7 +171,7 @@ LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:130:5 + --> $DIR/redundant_pattern_matching_option.rs:135:5 | LL | / match x { LL | | None => true, @@ -180,7 +180,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:135:5 + --> $DIR/redundant_pattern_matching_option.rs:140:5 | LL | / match x { LL | | Some(_) => false, @@ -189,7 +189,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:140:5 + --> $DIR/redundant_pattern_matching_option.rs:145:5 | LL | / match x { LL | | None => false, @@ -198,13 +198,13 @@ LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:155:13 + --> $DIR/redundant_pattern_matching_option.rs:160:13 | LL | let _ = matches!(x, Some(_)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:157:13 + --> $DIR/redundant_pattern_matching_option.rs:162:13 | LL | let _ = matches!(x, None); | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed new file mode 100644 index 00000000000..9668a6b99bf --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed @@ -0,0 +1,6 @@ +#![warn(clippy::unnecessary_fallible_conversions)] + +fn main() { + let _: i64 = 0i32.into(); + let _: i64 = 0i32.into(); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs new file mode 100644 index 00000000000..9fa6c08b1b0 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs @@ -0,0 +1,6 @@ +#![warn(clippy::unnecessary_fallible_conversions)] + +fn main() { + let _: i64 = 0i32.try_into().unwrap(); + let _: i64 = 0i32.try_into().expect("can't happen"); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr new file mode 100644 index 00000000000..b918fdf774b --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr @@ -0,0 +1,17 @@ +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions.rs:4:23 + | +LL | let _: i64 = 0i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: use: `into()` + | + = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions.rs:5:23 + | +LL | let _: i64 = 0i32.try_into().expect("can't happen"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `into()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs new file mode 100644 index 00000000000..68e617cc062 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs @@ -0,0 +1,43 @@ +//@aux-build:proc_macros.rs +//@no-rustfix +#![warn(clippy::unnecessary_fallible_conversions)] + +extern crate proc_macros; + +struct Foo; +impl TryFrom<i32> for Foo { + type Error = (); + fn try_from(_: i32) -> Result<Self, Self::Error> { + Ok(Foo) + } +} +impl From<i64> for Foo { + fn from(_: i64) -> Self { + Foo + } +} + +fn main() { + // `Foo` only implements `TryFrom<i32>` and not `From<i32>`, so don't lint + let _: Result<Foo, _> = 0i32.try_into(); + let _: Result<Foo, _> = i32::try_into(0i32); + let _: Result<Foo, _> = Foo::try_from(0i32); + + // ... it does impl From<i64> however + let _: Result<Foo, _> = 0i64.try_into(); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result<Foo, _> = i64::try_into(0i64); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result<Foo, _> = Foo::try_from(0i64); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + + let _: Result<i64, _> = 0i32.try_into(); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result<i64, _> = i32::try_into(0i32); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result<i64, _> = <_>::try_from(0i32); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + + // From a macro + let _: Result<i64, _> = proc_macros::external!(0i32).try_into(); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr new file mode 100644 index 00000000000..286decf8f35 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr @@ -0,0 +1,41 @@ +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:27:34 + | +LL | let _: Result<Foo, _> = 0i64.try_into(); + | ^^^^^^^^ help: use: `into` + | + = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:29:29 + | +LL | let _: Result<Foo, _> = i64::try_into(0i64); + | ^^^^^^^^^^^^^ help: use: `Into::into` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:31:29 + | +LL | let _: Result<Foo, _> = Foo::try_from(0i64); + | ^^^^^^^^^^^^^ help: use: `From::from` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:34:34 + | +LL | let _: Result<i64, _> = 0i32.try_into(); + | ^^^^^^^^ help: use: `into` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:36:29 + | +LL | let _: Result<i64, _> = i32::try_into(0i32); + | ^^^^^^^^^^^^^ help: use: `Into::into` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:38:29 + | +LL | let _: Result<i64, _> = <_>::try_from(0i32); + | ^^^^^^^^^^^^^ help: use: `From::from` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.fixed b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed new file mode 100644 index 00000000000..d079807ab58 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed @@ -0,0 +1,58 @@ +#![allow(unused)] +#![warn(clippy::unused_enumerate_index)] + +use std::iter::Enumerate; + +fn main() { + let v = [1, 2, 3]; + for x in v.iter() { + println!("{x}"); + } + + struct Dummy1; + impl Dummy1 { + fn enumerate(self) -> Vec<usize> { + vec![] + } + } + let dummy = Dummy1; + for x in dummy.enumerate() { + println!("{x}"); + } + + struct Dummy2; + impl Dummy2 { + fn enumerate(self) -> Enumerate<std::vec::IntoIter<usize>> { + vec![1, 2].into_iter().enumerate() + } + } + let dummy = Dummy2; + for (_, x) in dummy.enumerate() { + println!("{x}"); + } + + let mut with_used_iterator = [1, 2, 3].into_iter().enumerate(); + with_used_iterator.next(); + for (_, x) in with_used_iterator { + println!("{x}"); + } + + struct Dummy3(std::vec::IntoIter<usize>); + + impl Iterator for Dummy3 { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + } + + let dummy = Dummy3(vec![1, 2, 3].into_iter()); + for x in dummy { + println!("{x}"); + } +} diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.rs b/src/tools/clippy/tests/ui/unused_enumerate_index.rs new file mode 100644 index 00000000000..2d524da7632 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_enumerate_index.rs @@ -0,0 +1,58 @@ +#![allow(unused)] +#![warn(clippy::unused_enumerate_index)] + +use std::iter::Enumerate; + +fn main() { + let v = [1, 2, 3]; + for (_, x) in v.iter().enumerate() { + println!("{x}"); + } + + struct Dummy1; + impl Dummy1 { + fn enumerate(self) -> Vec<usize> { + vec![] + } + } + let dummy = Dummy1; + for x in dummy.enumerate() { + println!("{x}"); + } + + struct Dummy2; + impl Dummy2 { + fn enumerate(self) -> Enumerate<std::vec::IntoIter<usize>> { + vec![1, 2].into_iter().enumerate() + } + } + let dummy = Dummy2; + for (_, x) in dummy.enumerate() { + println!("{x}"); + } + + let mut with_used_iterator = [1, 2, 3].into_iter().enumerate(); + with_used_iterator.next(); + for (_, x) in with_used_iterator { + println!("{x}"); + } + + struct Dummy3(std::vec::IntoIter<usize>); + + impl Iterator for Dummy3 { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + } + + let dummy = Dummy3(vec![1, 2, 3].into_iter()); + for (_, x) in dummy.enumerate() { + println!("{x}"); + } +} diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.stderr b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr new file mode 100644 index 00000000000..b575fbbc4e6 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr @@ -0,0 +1,26 @@ +error: you seem to use `.enumerate()` and immediately discard the index + --> $DIR/unused_enumerate_index.rs:8:19 + | +LL | for (_, x) in v.iter().enumerate() { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unused-enumerate-index` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_enumerate_index)]` +help: remove the `.enumerate()` call + | +LL | for x in v.iter() { + | ~ ~~~~~~~~ + +error: you seem to use `.enumerate()` and immediately discard the index + --> $DIR/unused_enumerate_index.rs:55:19 + | +LL | for (_, x) in dummy.enumerate() { + | ^^^^^^^^^^^^^^^^^ + | +help: remove the `.enumerate()` call + | +LL | for x in dummy { + | ~ ~~~~~ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.rs b/src/tools/clippy/tests/ui/useless_conversion_try.rs index a5feefbe0f0..803d3b39f37 100644 --- a/src/tools/clippy/tests/ui/useless_conversion_try.rs +++ b/src/tools/clippy/tests/ui/useless_conversion_try.rs @@ -1,5 +1,5 @@ #![deny(clippy::useless_conversion)] -#![allow(clippy::needless_if)] +#![allow(clippy::needless_if, clippy::unnecessary_fallible_conversions)] fn test_generic<T: Copy>(val: T) -> T { let _ = T::try_from(val).unwrap(); diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.fixed b/src/tools/clippy/tests/ui/waker_clone_wake.fixed new file mode 100644 index 00000000000..9c02b9a90fd --- /dev/null +++ b/src/tools/clippy/tests/ui/waker_clone_wake.fixed @@ -0,0 +1,29 @@ +#[derive(Clone)] +pub struct Custom; + +impl Custom { + pub fn wake(self) {} +} + +macro_rules! mac { + ($cx:ident) => { + $cx.waker() + }; +} + +pub fn wake(cx: &mut std::task::Context) { + cx.waker().wake_by_ref(); + + mac!(cx).wake_by_ref(); +} + +pub fn no_lint(cx: &mut std::task::Context, c: &Custom) { + c.clone().wake(); + + let w = cx.waker().clone(); + w.wake(); + + cx.waker().clone().wake_by_ref(); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.rs b/src/tools/clippy/tests/ui/waker_clone_wake.rs new file mode 100644 index 00000000000..edc3bbd8fc0 --- /dev/null +++ b/src/tools/clippy/tests/ui/waker_clone_wake.rs @@ -0,0 +1,29 @@ +#[derive(Clone)] +pub struct Custom; + +impl Custom { + pub fn wake(self) {} +} + +macro_rules! mac { + ($cx:ident) => { + $cx.waker() + }; +} + +pub fn wake(cx: &mut std::task::Context) { + cx.waker().clone().wake(); + + mac!(cx).clone().wake(); +} + +pub fn no_lint(cx: &mut std::task::Context, c: &Custom) { + c.clone().wake(); + + let w = cx.waker().clone(); + w.wake(); + + cx.waker().clone().wake_by_ref(); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.stderr b/src/tools/clippy/tests/ui/waker_clone_wake.stderr new file mode 100644 index 00000000000..f1abf4d9cb0 --- /dev/null +++ b/src/tools/clippy/tests/ui/waker_clone_wake.stderr @@ -0,0 +1,17 @@ +error: cloning a `Waker` only to wake it + --> $DIR/waker_clone_wake.rs:15:5 + | +LL | cx.waker().clone().wake(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `cx.waker().wake_by_ref()` + | + = note: `-D clippy::waker-clone-wake` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::waker_clone_wake)]` + +error: cloning a `Waker` only to wake it + --> $DIR/waker_clone_wake.rs:17:5 + | +LL | mac!(cx).clone().wake(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `mac!(cx).wake_by_ref()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs index c721e9969c9..eba5405e67e 100644 --- a/src/tools/clippy/tests/versioncheck.rs +++ b/src/tools/clippy/tests/versioncheck.rs @@ -26,6 +26,7 @@ fn consistent_clippy_crate_versions() { let paths = [ "declare_clippy_lint/Cargo.toml", + "clippy_config/Cargo.toml", "clippy_lints/Cargo.toml", "clippy_utils/Cargo.toml", ]; diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index ca2bb80bd26..f90fd1f7fc5 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -223,9 +223,10 @@ degree documented below): - All Rust [Tier 1 targets](https://doc.rust-lang.org/rustc/platform-support.html) are supported by Miri. They are all checked on Miri's CI, and some (at least one per OS) are even checked on every Rust PR, so the shipped Miri should always work on these targets. -- We also support `s390x-unknown-linux-gnu` as our "big-endian target of choice". +- `aarch64-apple-darwin` is supported. +- `s390x-unknown-linux-gnu` is supported as our "big-endian target of choice". - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we - make no promises. + make no promises and we don't run tests for such targets. - For targets on other operating systems, even basic operations such as printing to the standard output might not work, and Miri might fail before even reaching the `main` function. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 60ae5d12598..2beb3bfef9e 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2e4e2a8f288f642cafcc41fff211955ceddc453d +3aaa0f57b7b877ef58532a8de075d1e5a79142bf diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 531128ed2ec..cd628444fed 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -241,7 +241,7 @@ fn run_compiler( mut args: Vec<String>, target_crate: bool, callbacks: &mut (dyn rustc_driver::Callbacks + Send), - using_internal_features: std::sync::Arc<std::sync::atomic::AtomicBool> + using_internal_features: std::sync::Arc<std::sync::atomic::AtomicBool>, ) -> ! { if target_crate { // Miri needs a custom sysroot for target crates. @@ -275,7 +275,8 @@ fn run_compiler( // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { rustc_driver::RunCompiler::new(&args, callbacks) - .set_using_internal_features(using_internal_features).run() + .set_using_internal_features(using_internal_features) + .run() }); std::process::exit(exit_code) } @@ -297,7 +298,8 @@ fn main() { // If the environment asks us to actually be rustc, then do that. if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { // Earliest rustc setup. - let using_internal_features = rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); + let using_internal_features = + rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); rustc_driver::init_rustc_env_logger(&handler); let target_crate = if crate_kind == "target" { @@ -318,7 +320,8 @@ fn main() { } // Add an ICE bug report hook. - let using_internal_features = rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ()); + let using_internal_features = + rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ()); // Init loggers the Miri way. init_early_loggers(&handler); @@ -581,5 +584,10 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config }, using_internal_features) + run_compiler( + rustc_args, + /* target_crate: */ true, + &mut MiriCompilerCalls { miri_config }, + using_internal_features, + ) } diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 4cab86af886..5d109a7d55c 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -41,7 +41,6 @@ //! on the data-race detection code. use std::{ - borrow::Cow, cell::{Cell, Ref, RefCell, RefMut}, fmt::Debug, mem, @@ -52,7 +51,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir; use rustc_span::Span; -use rustc_target::abi::{Align, Size}; +use rustc_target::abi::{Align, HasDataLayout, Size}; use crate::diagnostics::RacingOp; use crate::*; @@ -194,12 +193,19 @@ struct AtomicMemoryCellClocks { size: Size, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum AtomicAccessType { + Load(AtomicReadOrd), + Store, + Rmw, +} + /// Type of write operation: allocating memory /// non-atomic writes and deallocating memory /// are all treated as writes for the purpose /// of the data-race detector. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum WriteType { +enum NaWriteType { /// Allocate memory. Allocate, @@ -212,12 +218,48 @@ enum WriteType { /// (Same for `Allocate` above.) Deallocate, } -impl WriteType { - fn get_descriptor(self) -> &'static str { + +impl NaWriteType { + fn description(self) -> &'static str { match self { - WriteType::Allocate => "Allocate", - WriteType::Write => "Write", - WriteType::Deallocate => "Deallocate", + NaWriteType::Allocate => "creating a new allocation", + NaWriteType::Write => "non-atomic write", + NaWriteType::Deallocate => "deallocation", + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum AccessType { + NaRead, + NaWrite(NaWriteType), + AtomicLoad, + AtomicStore, + AtomicRmw, +} + +impl AccessType { + fn description(self) -> &'static str { + match self { + AccessType::NaRead => "non-atomic read", + AccessType::NaWrite(w) => w.description(), + AccessType::AtomicLoad => "atomic load", + AccessType::AtomicStore => "atomic store", + AccessType::AtomicRmw => "atomic read-modify-write", + } + } + + fn is_atomic(self) -> bool { + match self { + AccessType::AtomicLoad | AccessType::AtomicStore | AccessType::AtomicRmw => true, + AccessType::NaRead | AccessType::NaWrite(_) => false, + } + } + + fn is_read(self) -> bool { + match self { + AccessType::AtomicLoad | AccessType::NaRead => true, + AccessType::NaWrite(_) | AccessType::AtomicStore | AccessType::AtomicRmw => false, } } } @@ -234,7 +276,7 @@ struct MemoryCellClocks { /// The type of operation that the write index represents, /// either newly allocated memory, a non-atomic write or /// a deallocation of memory. - write_type: WriteType, + write_type: NaWriteType, /// The vector-clock of all non-atomic reads that happened since the last non-atomic write /// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to @@ -265,7 +307,7 @@ impl MemoryCellClocks { MemoryCellClocks { read: VClock::default(), write: (alloc_index, alloc), - write_type: WriteType::Allocate, + write_type: NaWriteType::Allocate, atomic_ops: None, } } @@ -488,7 +530,7 @@ impl MemoryCellClocks { &mut self, thread_clocks: &mut ThreadClockSet, index: VectorIdx, - write_type: WriteType, + write_type: NaWriteType, current_span: Span, ) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, thread_clocks); @@ -526,7 +568,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicReadOrd, ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_ref(); - this.atomic_access_check(place)?; + this.atomic_access_check(place, AtomicAccessType::Load(atomic))?; // This will read from the last store in the modification order of this location. In case // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. // This is fine with StackedBorrow and race checks because they don't concern metadata on @@ -546,7 +588,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.atomic_access_check(dest)?; + this.atomic_access_check(dest, AtomicAccessType::Store)?; this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; @@ -558,8 +600,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { this.buffered_atomic_write(val, dest, atomic, val) } - /// Perform an atomic operation on a memory location. - fn atomic_op_immediate( + /// Perform an atomic RMW operation on a memory location. + fn atomic_rmw_op_immediate( &mut self, place: &MPlaceTy<'tcx, Provenance>, rhs: &ImmTy<'tcx, Provenance>, @@ -568,7 +610,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); - this.atomic_access_check(place)?; + this.atomic_access_check(place, AtomicAccessType::Rmw)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; @@ -592,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); - this.atomic_access_check(place)?; + this.atomic_access_check(place, AtomicAccessType::Rmw)?; let old = this.allow_data_races_mut(|this| this.read_scalar(place))?; this.allow_data_races_mut(|this| this.write_scalar(new, place))?; @@ -613,7 +655,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); - this.atomic_access_check(place)?; + this.atomic_access_check(place, AtomicAccessType::Rmw)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; @@ -652,7 +694,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Immediate<Provenance>> { use rand::Rng as _; let this = self.eval_context_mut(); - this.atomic_access_check(place)?; + this.atomic_access_check(place, AtomicAccessType::Rmw)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success @@ -838,48 +880,45 @@ impl VClockAlloc { global: &GlobalState, thread_mgr: &ThreadManager<'_, '_>, mem_clocks: &MemoryCellClocks, - action: &str, - is_atomic: bool, + access: AccessType, access_size: Size, ptr_dbg: Pointer<AllocId>, ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(thread_mgr); - let mut action = Cow::Borrowed(action); - let mut involves_non_atomic = true; + let mut other_size = None; // if `Some`, this was a size-mismatch race let write_clock; - let (other_action, other_thread, other_clock) = + let (other_access, other_thread, other_clock) = // First check the atomic-nonatomic cases. If it looks like multiple // cases apply, this one should take precedence, else it might look like // we are reporting races between two non-atomic reads. - if !is_atomic && + if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) { - (format!("Atomic Store"), idx, &atomic.write_vector) - } else if !is_atomic && + (AccessType::AtomicStore, idx, &atomic.write_vector) + } else if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) { - (format!("Atomic Load"), idx, &atomic.read_vector) + (AccessType::AtomicLoad, idx, &atomic.read_vector) // Then check races with non-atomic writes/reads. } else if mem_clocks.write.1 > current_clocks.clock[mem_clocks.write.0] { write_clock = mem_clocks.write(); - (mem_clocks.write_type.get_descriptor().to_owned(), mem_clocks.write.0, &write_clock) + (AccessType::NaWrite(mem_clocks.write_type), mem_clocks.write.0, &write_clock) } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, ¤t_clocks.clock) { - (format!("Read"), idx, &mem_clocks.read) + (AccessType::NaRead, idx, &mem_clocks.read) // Finally, mixed-size races. - } else if is_atomic && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size { + } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size { // This is only a race if we are not synchronized with all atomic accesses, so find // the one we are not synchronized with. - involves_non_atomic = false; - action = format!("{}-byte (different-size) {action}", access_size.bytes()).into(); + other_size = Some(atomic.size); if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) { - (format!("{}-byte Atomic Store", atomic.size.bytes()), idx, &atomic.write_vector) + (AccessType::AtomicStore, idx, &atomic.write_vector) } else if let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) { - (format!("{}-byte Atomic Load", atomic.size.bytes()), idx, &atomic.read_vector) + (AccessType::AtomicLoad, idx, &atomic.read_vector) } else { unreachable!( "Failed to report data-race for mixed-size access: no race found" @@ -892,18 +931,39 @@ impl VClockAlloc { // Load elaborated thread information about the racing thread actions. let current_thread_info = global.print_thread_metadata(thread_mgr, current_index); let other_thread_info = global.print_thread_metadata(thread_mgr, other_thread); + let involves_non_atomic = !access.is_atomic() || !other_access.is_atomic(); // Throw the data-race detection. + let extra = if other_size.is_some() { + assert!(!involves_non_atomic); + Some("overlapping unsynchronized atomic accesses must use the same access size") + } else if access.is_read() && other_access.is_read() { + assert!(involves_non_atomic); + Some( + "overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only", + ) + } else { + None + }; Err(err_machine_stop!(TerminationInfo::DataRace { involves_non_atomic, + extra, ptr: ptr_dbg, op1: RacingOp { - action: other_action.to_string(), + action: if let Some(other_size) = other_size { + format!("{}-byte {}", other_size.bytes(), other_access.description()) + } else { + other_access.description().to_owned() + }, thread_info: other_thread_info, span: other_clock.as_slice()[other_thread.index()].span_data(), }, op2: RacingOp { - action: action.to_string(), + action: if other_size.is_some() { + format!("{}-byte {}", access_size.bytes(), access.description()) + } else { + access.description().to_owned() + }, thread_info: current_thread_info, span: current_clocks.clock.as_slice()[current_index.index()].span_data(), }, @@ -938,8 +998,7 @@ impl VClockAlloc { global, &machine.threads, mem_clocks, - "Read", - /* is_atomic */ false, + AccessType::NaRead, access_range.size, Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ); @@ -956,7 +1015,7 @@ impl VClockAlloc { &mut self, alloc_id: AllocId, access_range: AllocRange, - write_type: WriteType, + write_type: NaWriteType, machine: &mut MiriMachine<'_, '_>, ) -> InterpResult<'tcx> { let current_span = machine.current_span(); @@ -978,8 +1037,7 @@ impl VClockAlloc { global, &machine.threads, mem_clocks, - write_type.get_descriptor(), - /* is_atomic */ false, + AccessType::NaWrite(write_type), access_range.size, Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ); @@ -1001,7 +1059,7 @@ impl VClockAlloc { range: AllocRange, machine: &mut MiriMachine<'_, '_>, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Write, machine) + self.unique_access(alloc_id, range, NaWriteType::Write, machine) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -1014,7 +1072,7 @@ impl VClockAlloc { range: AllocRange, machine: &mut MiriMachine<'_, '_>, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Deallocate, machine) + self.unique_access(alloc_id, range, NaWriteType::Deallocate, machine) } } @@ -1062,7 +1120,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { } /// Checks that an atomic access is legal at the given place. - fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn atomic_access_check( + &self, + place: &MPlaceTy<'tcx, Provenance>, + access_type: AtomicAccessType, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -1080,15 +1142,34 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { .ptr_try_get_alloc_id(place.ptr()) .expect("there are no zero-sized atomic accesses"); if this.get_alloc_mutability(alloc_id)? == Mutability::Not { - // FIXME: make this prettier, once these messages have separate title/span/help messages. - throw_ub_format!( - "atomic operations cannot be performed on read-only memory\n\ - many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails \ - (and is hence nominally read-only)\n\ - some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; \ - it is possible that we could have an exception permitting this for specific kinds of loads\n\ - please report an issue at <https://github.com/rust-lang/miri/issues> if this is a problem for you" - ); + // See if this is fine. + match access_type { + AtomicAccessType::Rmw | AtomicAccessType::Store => { + throw_ub_format!( + "atomic store and read-modify-write operations cannot be performed on read-only memory\n\ + see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information" + ); + } + AtomicAccessType::Load(_) + if place.layout.size > this.tcx.data_layout().pointer_size() => + { + throw_ub_format!( + "large atomic load operations cannot be performed on read-only memory\n\ + these operations often have to be implemented using read-modify-write operations, which require writeable memory\n\ + see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information" + ); + } + AtomicAccessType::Load(o) if o != AtomicReadOrd::Relaxed => { + throw_ub_format!( + "non-relaxed atomic load operations cannot be performed on read-only memory\n\ + these operations sometimes have to be implemented using read-modify-write operations, which require writeable memory\n\ + see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information" + ); + } + _ => { + // Large relaxed loads are fine! + } + } } Ok(()) } @@ -1104,7 +1185,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { this.validate_atomic_op( place, atomic, - "Atomic Load", + AccessType::AtomicLoad, move |memory, clocks, index, atomic| { if atomic == AtomicReadOrd::Relaxed { memory.load_relaxed(&mut *clocks, index, place.layout.size) @@ -1126,7 +1207,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { this.validate_atomic_op( place, atomic, - "Atomic Store", + AccessType::AtomicStore, move |memory, clocks, index, atomic| { if atomic == AtomicWriteOrd::Relaxed { memory.store_relaxed(clocks, index, place.layout.size) @@ -1148,18 +1229,23 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); - this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { - if acquire { - memory.load_acquire(clocks, index, place.layout.size)?; - } else { - memory.load_relaxed(clocks, index, place.layout.size)?; - } - if release { - memory.rmw_release(clocks, index, place.layout.size) - } else { - memory.rmw_relaxed(clocks, index, place.layout.size) - } - }) + this.validate_atomic_op( + place, + atomic, + AccessType::AtomicRmw, + move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index, place.layout.size)?; + } else { + memory.load_relaxed(clocks, index, place.layout.size)?; + } + if release { + memory.rmw_release(clocks, index, place.layout.size) + } else { + memory.rmw_relaxed(clocks, index, place.layout.size) + } + }, + ) } /// Generic atomic operation implementation @@ -1167,7 +1253,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { &self, place: &MPlaceTy<'tcx, Provenance>, atomic: A, - description: &str, + access: AccessType, mut op: impl FnMut( &mut MemoryCellClocks, &mut ThreadClockSet, @@ -1176,6 +1262,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { ) -> Result<(), DataRace>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); + assert!(access.is_atomic()); if let Some(data_race) = &this.machine.data_race { if data_race.race_detecting() { let size = place.layout.size; @@ -1185,7 +1272,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", - description, + access.description(), &atomic, place.ptr(), size.bytes() @@ -1207,8 +1294,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { data_race, &this.machine.threads, mem_clocks, - description, - /* is_atomic */ true, + access, place.layout.size, Pointer::new( alloc_id, diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 9b8f263b7ce..fe445c6dcd9 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -4,7 +4,7 @@ use std::num::NonZeroU64; use log::trace; use rustc_errors::DiagnosticMessage; -use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol}; +use rustc_span::{SpanData, Symbol, DUMMY_SP}; use rustc_target::abi::{Align, Size}; use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory; @@ -47,6 +47,7 @@ pub enum TerminationInfo { ptr: Pointer, op1: RacingOp, op2: RacingOp, + extra: Option<&'static str>, }, } @@ -75,7 +76,7 @@ impl fmt::Display for TerminationInfo { write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",), - DataRace { involves_non_atomic, ptr, op1, op2 } => + DataRace { involves_non_atomic, ptr, op1, op2, .. } => write!( f, "{} detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here", @@ -266,12 +267,16 @@ pub fn report_error<'tcx, 'mir>( vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))], Int2PtrWithStrictProvenance => vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], - DataRace { op1, .. } => - vec![ - (Some(op1.span), format!("and (1) occurred earlier here")), - (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), - (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), - ], + DataRace { op1, extra, .. } => { + let mut helps = vec![(Some(op1.span), format!("and (1) occurred earlier here"))]; + if let Some(extra) = extra { + helps.push((None, format!("{extra}"))) + } + helps.push((None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"))); + helps.push((None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"))); + helps + } + , _ => vec![], }; (title, helps) diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 3946ce8ef9d..5b785c0143e 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -265,12 +265,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>> { let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; - let mut ecx = InterpCx::new( - tcx, - rustc_span::source_map::DUMMY_SP, - param_env, - MiriMachine::new(config, layout_cx), - ); + let mut ecx = + InterpCx::new(tcx, rustc_span::DUMMY_SP, param_env, MiriMachine::new(config, layout_cx)); // Some parts of initialization require a full `InterpCx`. MiriMachine::late_init(&mut ecx, config, { diff --git a/src/tools/miri/src/shims/intrinsics/atomic.rs b/src/tools/miri/src/shims/intrinsics/atomic.rs index e38b677f485..4d7f6a6b4e0 100644 --- a/src/tools/miri/src/shims/intrinsics/atomic.rs +++ b/src/tools/miri/src/shims/intrinsics/atomic.rs @@ -77,40 +77,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?, ["or", ord] => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord)?)?, + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord)?)?, ["xor", ord] => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord)?)?, + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord)?)?, ["and", ord] => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord)?)?, + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord)?)?, ["nand", ord] => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord)?)?, + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord)?)?, ["xadd", ord] => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord)?)?, + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord)?)?, ["xsub", ord] => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord)?)?, + this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord)?)?, ["min", ord] => { // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); - this.atomic_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; + this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; } ["umin", ord] => { // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); - this.atomic_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; + this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; } ["max", ord] => { // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); - this.atomic_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; + this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; } ["umax", ord] => { // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); - this.atomic_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; + this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; } _ => throw_unsup_format!("unimplemented intrinsic: `atomic_{intrinsic_name}`"), @@ -178,7 +178,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { Ok(()) } - fn atomic_op( + fn atomic_rmw_op( &mut self, args: &[OpTy<'tcx, Provenance>], dest: &PlaceTy<'tcx, Provenance>, @@ -213,7 +213,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { Ok(()) } AtomicOp::MirOp(op, neg) => { - let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; + let old = this.atomic_rmw_op_immediate(&place, &rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned Ok(()) } diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs index 868b3beb53b..7c67ea45bdf 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs @@ -17,7 +17,7 @@ fn thread_1(p: SendPtr) { fn thread_2(p: SendPtr) { let p = p.0; unsafe { - *p = 5; //~ ERROR: /Data race detected between \(1\) (Read|Write) on thread `<unnamed>` and \(2\) Write on thread `<unnamed>`/ + *p = 5; //~ ERROR: /Data race detected between \(1\) non-atomic (read|write) on thread `<unnamed>` and \(2\) non-atomic write on thread `<unnamed>`/ } } diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr index da5af600675..0de2f66fe0b 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/retag_data_race_write.rs:LL:CC | LL | *p = 5; - | ^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/retag_data_race_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr index 37d216b9877..8036c974eec 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/retag_data_race_write.rs:LL:CC | LL | *p = 5; - | ^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/retag_data_race_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.rs b/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.rs index cb6aeea665d..88c73d14ef7 100644 --- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.rs +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.rs @@ -7,5 +7,5 @@ fn main() { static X: i32 = 0; let x = &X as *const i32 as *const AtomicI32; let x = unsafe { &*x }; - x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); //~ERROR: atomic operations cannot be performed on read-only memory + x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); //~ERROR: cannot be performed on read-only memory } diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr index d51fdee0b25..fc5982e7f94 100644 --- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -1,14 +1,10 @@ -error: Undefined Behavior: atomic operations cannot be performed on read-only memory - many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) - some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads - please report an issue at <https://github.com/rust-lang/miri/issues> if this is a problem for you +error: Undefined Behavior: atomic store and read-modify-write operations cannot be performed on read-only memory + see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information --> $DIR/read_only_atomic_cmpxchg.rs:LL:CC | LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory -many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) -some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads -please report an issue at <https://github.com/rust-lang/miri/issues> if this is a problem for you + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic store and read-modify-write operations cannot be performed on read-only memory +see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load.stderr b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load.stderr deleted file mode 100644 index 17851d6b470..00000000000 --- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: Undefined Behavior: atomic operations cannot be performed on read-only memory - many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) - some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads - please report an issue at <https://github.com/rust-lang/miri/issues> if this is a problem for you - --> $DIR/read_only_atomic_load.rs:LL:CC - | -LL | x.load(Ordering::Relaxed); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory -many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) -some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads -please report an issue at <https://github.com/rust-lang/miri/issues> if this is a problem for you - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/read_only_atomic_load.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load.rs b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_acquire.rs index 6e92453e3c1..af0dc2d3fd6 100644 --- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load.rs +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_acquire.rs @@ -9,5 +9,5 @@ fn main() { let x = unsafe { &*x }; // Some targets can implement atomic loads via compare_exchange, so we cannot allow them on // read-only memory. - x.load(Ordering::Relaxed); //~ERROR: atomic operations cannot be performed on read-only memory + x.load(Ordering::Acquire); //~ERROR: cannot be performed on read-only memory } diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_acquire.stderr b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_acquire.stderr new file mode 100644 index 00000000000..2945344877a --- /dev/null +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_acquire.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: non-relaxed atomic load operations cannot be performed on read-only memory + these operations sometimes have to be implemented using read-modify-write operations, which require writeable memory + see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information + --> $DIR/read_only_atomic_load_acquire.rs:LL:CC + | +LL | x.load(Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ non-relaxed atomic load operations cannot be performed on read-only memory +these operations sometimes have to be implemented using read-modify-write operations, which require writeable memory +see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/read_only_atomic_load_acquire.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs new file mode 100644 index 00000000000..a9a8f0f5ddd --- /dev/null +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs @@ -0,0 +1,18 @@ +// Should not rely on the aliasing model for its failure. +//@compile-flags: -Zmiri-disable-stacked-borrows +// Needs atomic accesses larger than the pointer size +//@ignore-64bit + +use std::sync::atomic::{AtomicI64, Ordering}; + +#[repr(align(8))] +struct AlignedI64(i64); + +fn main() { + static X: AlignedI64 = AlignedI64(0); + let x = &X as *const AlignedI64 as *const AtomicI64; + let x = unsafe { &*x }; + // Some targets can implement atomic loads via compare_exchange, so we cannot allow them on + // read-only memory. + x.load(Ordering::Relaxed); //~ERROR: cannot be performed on read-only memory +} diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.stderr b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.stderr new file mode 100644 index 00000000000..5d8cb707f3f --- /dev/null +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: large atomic load operations cannot be performed on read-only memory + these operations often have to be implemented using read-modify-write operations, which require writeable memory + see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information + --> $DIR/read_only_atomic_load_large.rs:LL:CC + | +LL | x.load(Ordering::Relaxed); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ large atomic load operations cannot be performed on read-only memory +these operations often have to be implemented using read-modify-write operations, which require writeable memory +see <https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#atomic-accesses-to-read-only-memory> for more information + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/read_only_atomic_load_large.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs index 723c3f1e158..e77c8e06a0f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs @@ -14,4 +14,3 @@ fn main() { } panic!("this should never print"); } - diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs index 22a5ce8ea74..22a5ce8ea74 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr index 20f3a25a0b1..16841626dc2 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_project_underscore.rs:LL:CC + --> $DIR/dangling_pointer_project_underscore_let.rs:LL:CC | LL | let _ = (*p).1; | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling @@ -7,17 +7,17 @@ LL | let _ = (*p).1; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> $DIR/dangling_pointer_project_underscore.rs:LL:CC + --> $DIR/dangling_pointer_project_underscore_let.rs:LL:CC | LL | let b = Box::new(42); | ^^^^^^^^^^^^ help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_project_underscore.rs:LL:CC + --> $DIR/dangling_pointer_project_underscore_let.rs:LL:CC | LL | }; | ^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/dangling_pointer_project_underscore.rs:LL:CC + = note: inside `main` at $DIR/dangling_pointer_project_underscore_let.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs new file mode 100644 index 00000000000..fc10a826c1e --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs @@ -0,0 +1,12 @@ +// Make sure we find these even with many checks disabled. +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 as *const (u8, u8, u8, u8) + }; + unsafe { + let _: u8 = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic + } +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr new file mode 100644 index 00000000000..0cdb6639a2f --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + --> $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + | +LL | let _: u8 = (*p).1; + | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + | +LL | let b = Box::new(42); + | ^^^^^^^^^^^^ +help: ALLOC was deallocated here: + --> $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + | +LL | }; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/pass/dangling_pointer_deref_match_underscore.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs index c3cff1f4280..8541da84857 100644 --- a/src/tools/miri/tests/pass/dangling_pointer_deref_match_underscore.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs @@ -1,13 +1,14 @@ -// A `_` binding in a match is a nop, so we do not detect that the pointer is dangling. +// Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { let b = Box::new(42); - &*b as *const i32 + &*b as *const i32 as *const (u8, u8, u8, u8) }; unsafe { - match *p { + match (*p).1 { + //~^ ERROR: out-of-bounds pointer arithmetic _ => {} } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr new file mode 100644 index 00000000000..625a7b5f60b --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + --> $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + | +LL | match (*p).1 { + | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + | +LL | let b = Box::new(42); + | ^^^^^^^^^^^^ +help: ALLOC was deallocated here: + --> $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + | +LL | }; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/dangling_pointer_project_underscore_match.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs index 42077dfae2d..786e57666e2 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs @@ -39,7 +39,7 @@ pub fn main() { let pointer = &*ptr.0; // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. - *pointer.load(Ordering::Relaxed) //~ ERROR: Data race detected between (1) Allocate on thread `<unnamed>` and (2) Read on thread `<unnamed>` + *pointer.load(Ordering::Relaxed) //~ ERROR: Data race detected between (1) creating a new allocation on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr index 5b809722c70..9d21a3e0a45 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Allocate on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) creating a new allocation on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/alloc_read_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Allocate on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) creating a new allocation on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/alloc_read_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs index 53f4e637a19..8c685dcb760 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs @@ -37,7 +37,7 @@ pub fn main() { let j2 = spawn(move || { let ptr = ptr; // avoid field capturing let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR: Data race detected between (1) Allocate on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR: Data race detected between (1) creating a new allocation on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr index 8520bcf4e4e..13a19109e88 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Allocate on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) creating a new allocation on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/alloc_write_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) = 2; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Allocate on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) creating a new allocation on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/alloc_write_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs index 9606df1d6ff..d7e9561caf3 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing - (&*c.0).load(Ordering::SeqCst) //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` + (&*c.0).load(Ordering::SeqCst) //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) atomic load on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr index e25629e14ea..f55f839d0b8 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) atomic load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/atomic_read_na_write_race1.rs:LL:CC | LL | (&*c.0).load(Ordering::SeqCst) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) atomic load on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/atomic_read_na_write_race1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs index 0e29ab32eef..62bf8b65561 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -25,7 +25,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between (1) atomic load on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr index 6953b1403b4..a20c220b6c2 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) atomic load on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/atomic_read_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) atomic load on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/atomic_read_na_write_race2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs index 6f1792bc8f4..9186c562670 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -25,7 +25,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR: Data race detected between (1) Atomic Store on thread `<unnamed>` and (2) Read on thread `<unnamed>` + *atomic_ref.get_mut() //~ ERROR: Data race detected between (1) atomic store on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr index e52b8895a6a..a91d4cee054 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Atomic Store on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) atomic store on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/atomic_write_na_read_race1.rs:LL:CC | LL | *atomic_ref.get_mut() - | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Atomic Store on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) atomic store on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/atomic_write_na_read_race1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs index e84207e655d..0fcae906f09 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing - (&*c.0).store(32, Ordering::SeqCst); //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Store on thread `<unnamed>` + (&*c.0).store(32, Ordering::SeqCst); //~ ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) atomic store on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr index 513d13b0349..8831d9cfc1c 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) atomic store on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/atomic_write_na_read_race2.rs:LL:CC | LL | (&*c.0).store(32, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) atomic store on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/atomic_write_na_read_race2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs index ca269b1bd2a..822d86c1c1d 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing - (&*c.0).store(64, Ordering::SeqCst); //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Atomic Store on thread `<unnamed>` + (&*c.0).store(64, Ordering::SeqCst); //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) atomic store on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr index 2ff70ef1f6d..5aed907b166 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) atomic store on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/atomic_write_na_write_race1.rs:LL:CC | LL | (&*c.0).store(64, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) atomic store on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/atomic_write_na_write_race1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs index 0d69a9a332d..d84531646e2 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -25,7 +25,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between (1) Atomic Store on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between (1) atomic store on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr index 166b4d2269a..65114296f52 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Atomic Store on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) atomic store on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/atomic_write_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Atomic Store on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) atomic store on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/atomic_write_na_write_race2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs index 0679b81f012..0fdb8e631a1 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs @@ -36,7 +36,7 @@ fn main() { let join2 = unsafe { spawn(move || { let c = c; // capture `c`, not just its field. - *c.0 = 64; //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *c.0 = 64; //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }) }; diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr index a08b21ab0e4..7ac3a9cc929 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/dangling_thread_async_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/dangling_thread_async_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs index 3c5dd424eb1..fa2176d844f 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs @@ -34,6 +34,6 @@ fn main() { spawn(|| ()).join().unwrap(); unsafe { - *c.0 = 64; //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `main` + *c.0 = 64; //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `main` } } diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr index aa2e6a6f712..49256dff51f 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `main` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here --> $DIR/dangling_thread_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `main` at ALLOC. (2) just happened here + | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/dangling_thread_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs index 3c25cdc0d8d..1d914f0a808 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs @@ -27,7 +27,7 @@ pub fn main() { let j2 = spawn(move || { let ptr = ptr; // avoid field capturing __rust_dealloc( - //~^ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` + //~^ ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` ptr.0 as *mut _, std::mem::size_of::<usize>(), std::mem::align_of::<usize>(), diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr index 5e546646479..ef6b0c3616b 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/dealloc_read_race1.rs:LL:CC | LL | / __rust_dealloc( @@ -7,7 +7,7 @@ LL | | ptr.0 as *mut _, LL | | std::mem::size_of::<usize>(), LL | | std::mem::align_of::<usize>(), LL | | ); - | |_____________^ Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here + | |_____________^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/dealloc_read_race1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs index c921ce6b716..53f1d19fa71 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs @@ -30,7 +30,7 @@ pub fn main() { let j2 = spawn(move || { let ptr = ptr; // avoid field capturing - // Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Read on thread `<unnamed>` + // Also an error of the form: Data race detected between (1) deallocation on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` // but the invalid allocation is detected first. *ptr.0 //~ ERROR: has been freed }); diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs index 87b5f204816..728dc64d828 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` + } //~ ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` }); let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr index beb70c5a7fa..805d7c19642 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/dealloc_read_race_stack.rs:LL:CC | LL | } - | ^ Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here + | ^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/dealloc_read_race_stack.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs index b700f50ce19..e0d7f983a63 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs @@ -26,7 +26,7 @@ pub fn main() { let j2 = spawn(move || { let ptr = ptr; // avoid field capturing __rust_dealloc( - //~^ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` + //~^ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` ptr.0 as *mut _, std::mem::size_of::<usize>(), std::mem::align_of::<usize>(), diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr index cc4c4524ba2..22ef35959f2 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/dealloc_write_race1.rs:LL:CC | LL | / __rust_dealloc( @@ -7,7 +7,7 @@ LL | | ptr.0 as *mut _, LL | | std::mem::size_of::<usize>(), LL | | std::mem::align_of::<usize>(), LL | | ); - | |_____________^ Data race detected between (1) Write on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here + | |_____________^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/dealloc_write_race1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs index e01132202d4..11b9d97527c 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs @@ -29,7 +29,7 @@ pub fn main() { let j2 = spawn(move || { let ptr = ptr; // avoid field capturing - // Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Write on thread `<unnamed>` + // Also an error of the form: Data race detected between (1) deallocation on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` // but the invalid allocation is detected first. *ptr.0 = 2; //~ ERROR: has been freed }); diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs index 3d35187a018..da3cdc23ad6 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` + } //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` }); let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr index 5f9f4f9bee4..52c9abd5fe0 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/dealloc_write_race_stack.rs:LL:CC | LL | } - | ^ Data race detected between (1) Write on thread `<unnamed>` and (2) Deallocate on thread `<unnamed>` at ALLOC. (2) just happened here + | ^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) deallocation on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/dealloc_write_race_stack.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs index b44be4ac64e..c1407fc5391 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs @@ -32,7 +32,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing - *c.0 = 64; //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *c.0 = 64; //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr index 84d1c0bf7e6..1d8bf2d0d26 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/enable_after_join_to_main.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/enable_after_join_to_main.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.rs b/src/tools/miri/tests/fail/data_race/fence_after_load.rs index 0648aa55f4a..12c74740387 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.rs +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.rs @@ -20,5 +20,5 @@ fn main() { // The fence is useless, since it did not happen-after the `store` in the other thread. // Hence this is a data race. // Also see https://github.com/rust-lang/miri/issues/2192. - unsafe { V = 2 } //~ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `main` + unsafe { V = 2 } //~ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `main` } diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.stderr b/src/tools/miri/tests/fail/data_race/fence_after_load.stderr index c30d2354e76..17bcf24a505 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.stderr +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `main` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here --> $DIR/fence_after_load.rs:LL:CC | LL | unsafe { V = 2 } - | ^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `main` at ALLOC. (2) just happened here + | ^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/fence_after_load.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs index d530ed2f5a4..871d5f9a9db 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs @@ -19,7 +19,7 @@ fn main() { }); s.spawn(|| { a8[0].load(Ordering::SeqCst); - //~^ ERROR: Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` + //~^ ERROR: Race condition detected between (1) 2-byte atomic load on thread `<unnamed>` and (2) 1-byte atomic load on thread `<unnamed>` }); }); } diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr index 06944a11db8..cb7dc89359a 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr @@ -1,14 +1,15 @@ -error: Undefined Behavior: Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Race condition detected between (1) 2-byte atomic load on thread `<unnamed>` and (2) 1-byte atomic load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/mixed_size_read.rs:LL:CC | LL | a8[0].load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic load on thread `<unnamed>` and (2) 1-byte atomic load on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/mixed_size_read.rs:LL:CC | LL | a16.load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs index df3551612c3..e52e76e4802 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs @@ -19,7 +19,7 @@ fn main() { }); s.spawn(|| { a8[0].store(1, Ordering::SeqCst); - //~^ ERROR: Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` + //~^ ERROR: Race condition detected between (1) 2-byte atomic store on thread `<unnamed>` and (2) 1-byte atomic store on thread `<unnamed>` }); }); } diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr index 4bb949175bf..b3908e9c6bf 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr @@ -1,14 +1,15 @@ -error: Undefined Behavior: Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `<unnamed>` and (2) 1-byte atomic store on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/mixed_size_write.rs:LL:CC | LL | a8[0].store(1, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `<unnamed>` and (2) 1-byte atomic store on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/mixed_size_write.rs:LL:CC | LL | a16.store(1, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.rs b/src/tools/miri/tests/fail/data_race/read_read_race1.rs index eebfbc74d40..dd800af4af7 100644 --- a/src/tools/miri/tests/fail/data_race/read_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/read_read_race1.rs @@ -21,7 +21,7 @@ fn main() { unsafe { ptr.read() }; // Then do the atomic access. a.load(Ordering::SeqCst); - //~^ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` + //~^ ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) atomic load on thread `<unnamed>` }); }); } diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr index 158b438bd0d..0846a88f362 100644 --- a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr @@ -1,14 +1,15 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) atomic load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/read_read_race1.rs:LL:CC | LL | a.load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) atomic load on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/read_read_race1.rs:LL:CC | LL | unsafe { ptr.read() }; | ^^^^^^^^^^ + = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.rs b/src/tools/miri/tests/fail/data_race/read_read_race2.rs index 230b429e287..1f35cb639c3 100644 --- a/src/tools/miri/tests/fail/data_race/read_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/read_read_race2.rs @@ -21,7 +21,7 @@ fn main() { let ptr = &a as *const AtomicU16 as *mut u16; unsafe { ptr.read() }; - //~^ ERROR: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` + //~^ ERROR: Data race detected between (1) atomic load on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` }); }); } diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr index 7f867b9edbb..c6181cc45b2 100644 --- a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr @@ -1,14 +1,15 @@ -error: Undefined Behavior: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) atomic load on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/read_read_race2.rs:LL:CC | LL | unsafe { ptr.read() }; - | ^^^^^^^^^^ Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^ Data race detected between (1) atomic load on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/read_read_race2.rs:LL:CC | LL | a.load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.rs b/src/tools/miri/tests/fail/data_race/read_write_race.rs index aed3ca767f6..37208549686 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race.rs @@ -21,7 +21,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing - *c.0 = 64; //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *c.0 = 64; //~ ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.stderr b/src/tools/miri/tests/fail/data_race/read_write_race.stderr index 13bc5c74ae3..c3fdcdf9308 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/read_write_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/read_write_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs index c3e5c401d87..df000b7942e 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` + stack_var //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` }); let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr index 96fcb494822..1e45878bfdd 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/read_write_race_stack.rs:LL:CC | LL | stack_var - | ^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/read_write_race_stack.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs index 1b691b996f1..f20dcec4e28 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs @@ -39,7 +39,7 @@ pub fn main() { let j3 = spawn(move || { let c = c; // avoid field capturing if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` + *c.0 //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` } else { 0 } diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr index 92755f5551d..0c574299b69 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/relax_acquire_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/relax_acquire_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.rs b/src/tools/miri/tests/fail/data_race/release_seq_race.rs index 80b30053fc7..4050895f296 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.rs @@ -43,7 +43,7 @@ pub fn main() { let c = c; // avoid field capturing sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` + *c.0 //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` } else { 0 } diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr index 880268730db..9aff6c6c3a7 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/release_seq_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/release_seq_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs index 33de1f17558..2cba38a8e1e 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs @@ -39,7 +39,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` + *c.0 //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` } else { 0 } diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr index 386c012ba4e..f0522404fde 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/release_seq_race_same_thread.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/release_seq_race_same_thread.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.rs b/src/tools/miri/tests/fail/data_race/rmw_race.rs index 4d0ce8f9433..973ebdf48d3 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.rs +++ b/src/tools/miri/tests/fail/data_race/rmw_race.rs @@ -40,7 +40,7 @@ pub fn main() { let j3 = spawn(move || { let c = c; // capture `c`, not just its field. if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` + *c.0 //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` } else { 0 } diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.stderr b/src/tools/miri/tests/fail/data_race/rmw_race.stderr index 82cb2c4ecbb..b400b2b9a17 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.stderr +++ b/src/tools/miri/tests/fail/data_race/rmw_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/rmw_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/rmw_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs index d3c2ab3e4a4..047d3757f14 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs @@ -21,4 +21,4 @@ fn race(local: i32) { // Deallocating the local (when `main` returns) // races with the read in the other thread. // Make sure the error points at this function's end, not just the call site. -} //~ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `main` +} //~ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `main` diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr index 71e38c2727e..e6804f6520c 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `main` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `main` at ALLOC. (2) just happened here --> $DIR/stack_pop_race.rs:LL:CC | LL | } - | ^ Data race detected between (1) Read on thread `<unnamed>` and (2) Deallocate on thread `main` at ALLOC. (2) just happened here + | ^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) deallocation on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/stack_pop_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.rs b/src/tools/miri/tests/fail/data_race/write_write_race.rs index 30e3460f222..05ec8d63c7a 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race.rs @@ -21,7 +21,7 @@ pub fn main() { let j2 = spawn(move || { let c = c; // avoid field capturing - *c.0 = 64; //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *c.0 = 64; //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` }); j1.join().unwrap(); diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.stderr b/src/tools/miri/tests/fail/data_race/write_write_race.stderr index 3b7eb2b8000..bc793e9afb0 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/write_write_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/write_write_race.rs:LL:CC diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs index 25be42bd4eb..d3ef552eab8 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var = 1usize; //~ ERROR: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` + stack_var = 1usize; //~ ERROR: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` // read to silence errors stack_var diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr index c501ecd11a6..ea62dbf96b9 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/write_write_race_stack.rs:LL:CC | LL | stack_var = 1usize; - | ^^^^^^^^^^^^^^^^^^ Data race detected between (1) Write on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/write_write_race_stack.rs:LL:CC diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs index 670fe9858ed..71f1f132bc7 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs @@ -13,7 +13,7 @@ fn main() { let ptr = ptr; // We do a protected mutable retag (but no write!) in this thread. fn retag(_x: &mut i32) {} - retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>` + retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `<unnamed>` }); // We do a read in the main thread. diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr index 10fb1dece2a..ce77976f88b 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/retag_data_race_protected_read.rs:LL:CC | LL | retag(unsafe { &mut *ptr.0 }); - | ^^^^^^^^^^^ Data race detected between (1) Read on thread `main` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/retag_data_race_protected_read.rs:LL:CC diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs index 0637e08af9b..46694cd49e3 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs @@ -15,7 +15,7 @@ fn thread_1(p: SendPtr) { fn thread_2(p: SendPtr) { let p = p.0; unsafe { - *p = 5; //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` + *p = 5; //~ ERROR: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` } } diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr index c53a495b5e1..1496c353e52 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/retag_data_race_read.rs:LL:CC | LL | *p = 5; - | ^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^ Data race detected between (1) non-atomic read on thread `<unnamed>` and (2) non-atomic write on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/retag_data_race_read.rs:LL:CC diff --git a/src/tools/miri/tests/pass/union-uninhabited-match-underscore.rs b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.rs index 33db9c2d347..6c1df45ac0e 100644 --- a/src/tools/miri/tests/pass/union-uninhabited-match-underscore.rs +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.rs @@ -8,10 +8,8 @@ fn main() { unsafe { let x: Uninit<Void> = Uninit { uninit: () }; match x.value { - // rustc warns about un unreachable pattern, - // but is wrong in unsafe code. #[allow(unreachable_patterns)] - _ => println!("hi from the void!"), + _x => println!("hi from the void!"), //~ERROR: invalid value } } } diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr new file mode 100644 index 00000000000..c234467bddc --- /dev/null +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a value of uninhabited type `main::Void` + --> $DIR/match_binder_checks_validity1.rs:LL:CC + | +LL | _x => println!("hi from the void!"), + | ^^ constructing invalid value: encountered a value of uninhabited type `main::Void` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/match_binder_checks_validity1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.rs b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.rs new file mode 100644 index 00000000000..0517263a8f5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.rs @@ -0,0 +1,14 @@ +fn main() { + #[derive(Copy, Clone)] + union Uninit<T: Copy> { + value: T, + uninit: u8, + } + unsafe { + let x: Uninit<bool> = Uninit { uninit: 3 }; + match x.value { + #[allow(unreachable_patterns)] + _x => println!("hi from the void!"), //~ERROR: invalid value + } + } +} diff --git a/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr new file mode 100644 index 00000000000..8af2d37d74a --- /dev/null +++ b/src/tools/miri/tests/fail/validity/match_binder_checks_validity2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean + --> $DIR/match_binder_checks_validity2.rs:LL:CC + | +LL | _x => println!("hi from the void!"), + | ^^ constructing invalid value: encountered 0x03, but expected a boolean + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/match_binder_checks_validity2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs index 36dc0d5f3f7..e36d947565a 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs @@ -31,7 +31,7 @@ pub fn main() { let x_split = split_u32_ptr(x_ptr); unsafe { let hi = ptr::addr_of!((*x_split)[0]); - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: different-size + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: (1) 4-byte atomic store on thread `<unnamed>` and (2) 2-byte atomic load } }); diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr index 055585ab96f..03b5a4e4c17 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,14 +1,15 @@ -error: Undefined Behavior: Race condition detected between (1) 4-byte Atomic Store on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Race condition detected between (1) 4-byte atomic store on thread `<unnamed>` and (2) 2-byte atomic load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte Atomic Store on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic store on thread `<unnamed>` and (2) 2-byte atomic load on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/racing_mixed_size.rs:LL:CC | LL | x.store(1, Relaxed); | ^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs index 5cd14540ca3..34917245ea5 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -29,7 +29,7 @@ pub fn main() { let x_split = split_u32_ptr(x_ptr); unsafe { let hi = x_split as *const u16 as *const AtomicU16; - (*hi).load(Relaxed); //~ ERROR: different-size + (*hi).load(Relaxed); //~ ERROR: (1) 4-byte atomic load on thread `<unnamed>` and (2) 2-byte atomic load } }); diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr index 2eefa0a87b4..05eba41f4d5 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,14 +1,15 @@ -error: Undefined Behavior: Race condition detected between (1) 4-byte Atomic Load on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here +error: Undefined Behavior: Race condition detected between (1) 4-byte atomic load on thread `<unnamed>` and (2) 2-byte atomic load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/racing_mixed_size_read.rs:LL:CC | LL | (*hi).load(Relaxed); - | ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte Atomic Load on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic load on thread `<unnamed>` and (2) 2-byte atomic load on thread `<unnamed>` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> $DIR/racing_mixed_size_read.rs:LL:CC | LL | x.load(Relaxed); | ^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): diff --git a/src/tools/miri/tests/pass/atomic-readonly-load.rs b/src/tools/miri/tests/pass/atomic-readonly-load.rs new file mode 100644 index 00000000000..8f8086b3538 --- /dev/null +++ b/src/tools/miri/tests/pass/atomic-readonly-load.rs @@ -0,0 +1,12 @@ +// Stacked Borrows doesn't like this. +//@compile-flags: -Zmiri-tree-borrows + +use std::sync::atomic::*; + +fn main() { + // Atomic loads from read-only memory are fine if they are relaxed and small. + static X: i32 = 0; + let x = &X as *const i32 as *const AtomicI32; + let x = unsafe { &*x }; + x.load(Ordering::Relaxed); +} diff --git a/src/tools/miri/tests/pass/underscore_pattern.rs b/src/tools/miri/tests/pass/underscore_pattern.rs new file mode 100644 index 00000000000..b0e85bc1bb0 --- /dev/null +++ b/src/tools/miri/tests/pass/underscore_pattern.rs @@ -0,0 +1,71 @@ +// Various tests ensuring that underscore patterns really just construct the place, but don't check its contents. +#![feature(strict_provenance)] +use std::ptr; + +fn main() { + dangling_match(); + invalid_match(); + dangling_let(); + invalid_let(); + dangling_let_type_annotation(); + invalid_let_type_annotation(); +} + +fn dangling_match() { + let p = { + let b = Box::new(42); + &*b as *const i32 + }; + unsafe { + match *p { + _ => {} + } + } +} + +fn invalid_match() { + union Uninit<T: Copy> { + value: T, + uninit: (), + } + unsafe { + let x: Uninit<bool> = Uninit { uninit: () }; + match x.value { + _ => {} + } + } +} + +fn dangling_let() { + unsafe { + let ptr = ptr::invalid::<bool>(0x40); + let _ = *ptr; + } +} + +fn invalid_let() { + unsafe { + let val = 3u8; + let ptr = ptr::addr_of!(val).cast::<bool>(); + let _ = *ptr; + } +} + +// Adding a type annotation used to change how MIR is generated, make sure we cover both cases. +fn dangling_let_type_annotation() { + unsafe { + let ptr = ptr::invalid::<bool>(0x40); + let _: bool = *ptr; + } +} + +fn invalid_let_type_annotation() { + unsafe { + let val = 3u8; + let ptr = ptr::addr_of!(val).cast::<bool>(); + let _: bool = *ptr; + } +} + +// FIXME: we should also test `!`, not just `bool` -- but that s currently buggy: +// https://github.com/rust-lang/rust/issues/117288 diff --git a/src/tools/miri/tests/pass/union-uninhabited-match-underscore.stdout b/src/tools/miri/tests/pass/union-uninhabited-match-underscore.stdout deleted file mode 100644 index ff731696f01..00000000000 --- a/src/tools/miri/tests/pass/union-uninhabited-match-underscore.stdout +++ /dev/null @@ -1 +0,0 @@ -hi from the void! diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs index 152f05b2c3b..2ae3cd2a939 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs @@ -262,24 +262,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ naked_functions, experimental!(naked) ), - // Plugins: - // BuiltinAttribute { - // name: sym::plugin, - // only_local: false, - // type_: CrateLevel, - // template: template!(List: "name"), - // duplicates: DuplicatesOk, - // gate: Gated( - // Stability::Deprecated( - // "https://github.com/rust-lang/rust/pull/64675", - // Some("may be removed in a future compiler version"), - // ), - // sym::plugin, - // "compiler plugins are deprecated", - // cfg_fn!(plugin) - // ), - // }, - // Testing: gated!( test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks, diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4b12e9172af..5e6dfaca702 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -31,12 +31,49 @@ const LICENSES: &[&str] = &[ // tidy-alphabetical-end ]; +type ExceptionList = &'static [(&'static str, &'static str)]; + +/// The workspaces to check for licensing and optionally permitted dependencies. +/// +/// Each entry consists of a tuple with the following elements: +/// +/// * The path to the workspace root Cargo.toml file. +/// * The list of license exceptions. +/// * Optionally a tuple of: +/// * A list of crates for which dependencies need to be explicitly allowed. +/// * The list of allowed dependencies. +// FIXME auto detect all cargo workspaces +pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>)] = &[ + // The root workspace has to be first for check_rustfix to work. + (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES))), + // Outside of the alphabetical section because rustfmt formats it using multiple lines. + ( + "compiler/rustc_codegen_cranelift", + EXCEPTIONS_CRANELIFT, + Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)), + ), + // tidy-alphabetical-start + //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored + //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo + //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo + //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo + ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None), + ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None), + //("src/etc/test-float-parse", &[], None), // FIXME uncomment once all deps are vendored + ("src/tools/cargo", EXCEPTIONS_CARGO, None), + //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored + //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored + ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None), + ("src/tools/x", &[], None), + // tidy-alphabetical-end +]; + /// These are exceptions to Rust's permissive licensing policy, and /// should be considered bugs. Exceptions are only allowed in Rust /// tooling. It is _crucial_ that no exception crates be dependencies /// of the Rust runtime (std/test). #[rustfmt::skip] -const EXCEPTIONS: &[(&str, &str)] = &[ +const EXCEPTIONS: ExceptionList = &[ // tidy-alphabetical-start ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc ("colored", "MPL-2.0"), // rustfmt @@ -49,17 +86,27 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("openssl", "Apache-2.0"), // opt-dist ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses) - ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde) + ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde) ("self_cell", "Apache-2.0"), // rustc (fluent translations) ("snap", "BSD-3-Clause"), // rustc // tidy-alphabetical-end ]; -const EXCEPTIONS_CARGO: &[(&str, &str)] = &[ +// FIXME uncomment once rust-lang/stdarch#1462 lands +/* +const EXCEPTIONS_STDARCH: ExceptionList = &[ + // tidy-alphabetical-start + ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 + ("wasmparser", "Apache-2.0 WITH LLVM-exception"), + ("wasmprinter", "Apache-2.0 WITH LLVM-exception"), + // tidy-alphabetical-end +]; +*/ + +const EXCEPTIONS_CARGO: ExceptionList = &[ // tidy-alphabetical-start ("bitmaps", "MPL-2.0+"), ("bytesize", "Apache-2.0"), - ("byteyarn", "Apache-2.0"), ("ciborium", "Apache-2.0"), ("ciborium-io", "Apache-2.0"), ("ciborium-ll", "Apache-2.0"), @@ -69,7 +116,7 @@ const EXCEPTIONS_CARGO: &[(&str, &str)] = &[ ("im-rc", "MPL-2.0+"), ("normalize-line-endings", "Apache-2.0"), ("openssl", "Apache-2.0"), - ("ryu", "Apache-2.0 OR BSL-1.0"), + ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 ("sha1_smol", "BSD-3-Clause"), ("similar", "Apache-2.0"), ("sized-chunks", "MPL-2.0+"), @@ -78,7 +125,20 @@ const EXCEPTIONS_CARGO: &[(&str, &str)] = &[ // tidy-alphabetical-end ]; -const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ +const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ + // tidy-alphabetical-start + ("anymap", "BlueOak-1.0.0 OR MIT OR Apache-2.0"), // BlueOak is not acceptable, but we use it under MIT OR Apache-2 .0 + ("dissimilar", "Apache-2.0"), + ("instant", "BSD-3-Clause"), + ("notify", "CC0-1.0"), + ("pulldown-cmark-to-cmark", "Apache-2.0"), + ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 + ("scip", "Apache-2.0"), + ("snap", "BSD-3-Clause"), + // tidy-alphabetical-end +]; + +const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-start ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"), @@ -99,8 +159,22 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ // tidy-alphabetical-end ]; -const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[ - ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde +// FIXME uncomment once all deps are vendored +/* +const EXCEPTIONS_GCC: ExceptionList = &[ + // tidy-alphabetical-start + ("gccjit", "GPL-3.0"), + ("gccjit_sys", "GPL-3.0"), + // tidy-alphabetical-end +]; +*/ + +const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[ + ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0 +]; + +const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[ + ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptible, but we use it under MIT OR Apache-2.0 ]; /// These are the root crates that are part of the runtime. The licenses for @@ -185,6 +259,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "is-terminal", "itertools", "itoa", + "jemalloc-sys", "jobserver", "lazy_static", "libc", @@ -383,65 +458,90 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ /// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path /// to the cargo executable. pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { - let mut cmd = cargo_metadata::MetadataCommand::new(); - cmd.cargo_path(cargo) - .manifest_path(root.join("Cargo.toml")) - .features(cargo_metadata::CargoOpt::AllFeatures); - let metadata = t!(cmd.exec()); - let runtime_ids = compute_runtime_crates(&metadata); - check_license_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad); - check_permitted_dependencies( - &metadata, - "rustc", - PERMITTED_RUSTC_DEPENDENCIES, - &["rustc_driver", "rustc_codegen_llvm"], - bad, - ); - - // Check cargo independently as it has it's own workspace. - let mut cmd = cargo_metadata::MetadataCommand::new(); - cmd.cargo_path(cargo) - .manifest_path(root.join("src/tools/cargo/Cargo.toml")) - .features(cargo_metadata::CargoOpt::AllFeatures); - let cargo_metadata = t!(cmd.exec()); - let runtime_ids = HashSet::new(); - check_license_exceptions(&cargo_metadata, EXCEPTIONS_CARGO, runtime_ids, bad); - check_rustfix(&metadata, &cargo_metadata, bad); - - // Check rustc_codegen_cranelift independently as it has it's own workspace. - let mut cmd = cargo_metadata::MetadataCommand::new(); - cmd.cargo_path(cargo) - .manifest_path(root.join("compiler/rustc_codegen_cranelift/Cargo.toml")) - .features(cargo_metadata::CargoOpt::AllFeatures); - let metadata = t!(cmd.exec()); - let runtime_ids = HashSet::new(); - check_license_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad); - check_permitted_dependencies( - &metadata, - "cranelift", - PERMITTED_CRANELIFT_DEPENDENCIES, - &["rustc_codegen_cranelift"], - bad, - ); - - let mut cmd = cargo_metadata::MetadataCommand::new(); - cmd.cargo_path(cargo) - .manifest_path(root.join("src/bootstrap/Cargo.toml")) - .features(cargo_metadata::CargoOpt::AllFeatures); - let metadata = t!(cmd.exec()); - let runtime_ids = HashSet::new(); - check_license_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad); + let mut checked_runtime_licenses = false; + let mut rust_metadata = None; + + for &(workspace, exceptions, permitted_deps) in WORKSPACES { + if !root.join(workspace).join("Cargo.lock").exists() { + tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock"); + continue; + } + + let mut cmd = cargo_metadata::MetadataCommand::new(); + cmd.cargo_path(cargo) + .manifest_path(root.join(workspace).join("Cargo.toml")) + .features(cargo_metadata::CargoOpt::AllFeatures) + .other_options(vec!["--locked".to_owned()]); + let metadata = t!(cmd.exec()); + + check_license_exceptions(&metadata, exceptions, bad); + if let Some((crates, permitted_deps)) = permitted_deps { + check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad); + } + + if workspace == "." { + let runtime_ids = compute_runtime_crates(&metadata); + check_runtime_license_exceptions(&metadata, runtime_ids, bad); + checked_runtime_licenses = true; + rust_metadata = Some(metadata); + } else if workspace == "src/tools/cargo" { + check_rustfix( + rust_metadata + .as_ref() + .expect("The root workspace should be the first to be checked"), + &metadata, + bad, + ); + } + } + + // Sanity check to ensure we don't accidentally remove the workspace containing the runtime + // crates. + assert!(checked_runtime_licenses); } -/// Check that all licenses are in the valid list in `LICENSES`. +/// Check that all licenses of runtime dependencies are in the valid list in `LICENSES`. /// -/// Packages listed in `exceptions` are allowed for tools. -fn check_license_exceptions( +/// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole +/// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx. +fn check_runtime_license_exceptions( metadata: &Metadata, - exceptions: &[(&str, &str)], runtime_ids: HashSet<&PackageId>, bad: &mut bool, ) { + for pkg in &metadata.packages { + if !runtime_ids.contains(&pkg.id) { + // Only checking dependencies of runtime libraries here. + continue; + } + if pkg.source.is_none() { + // No need to check local packages. + continue; + } + let license = match &pkg.license { + Some(license) => license, + None => { + tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); + continue; + } + }; + if !LICENSES.contains(&license.as_str()) { + // This is a specific exception because SGX is considered "third party". + // See https://github.com/rust-lang/rust/issues/62620 for more. + // In general, these should never be added and this exception + // should not be taken as precedent for any new target. + if pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") { + continue; + } + tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); + } + } +} + +/// Check that all licenses of tool dependencies are in the valid list in `LICENSES`. +/// +/// Packages listed in `exceptions` are allowed for tools. +fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], bad: &mut bool) { // Validate the EXCEPTIONS list hasn't changed. for (name, license) in exceptions { // Check that the package actually exists. @@ -483,7 +583,7 @@ fn check_license_exceptions( // No need to check local packages. continue; } - if !runtime_ids.contains(&pkg.id) && exception_names.contains(&pkg.name.as_str()) { + if exception_names.contains(&pkg.name.as_str()) { continue; } let license = match &pkg.license { @@ -494,13 +594,6 @@ fn check_license_exceptions( } }; if !LICENSES.contains(&license.as_str()) { - if pkg.name == "fortanix-sgx-abi" { - // This is a specific exception because SGX is considered - // "third party". See - // https://github.com/rust-lang/rust/issues/62620 for more. In - // general, these should never be added. - continue; - } tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index aad57cacbb4..ff71ca53725 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -9,25 +9,33 @@ const ALLOWED_SOURCES: &[&str] = &["\"registry+https://github.com/rust-lang/crat /// Checks for external package sources. `root` is the path to the directory that contains the /// workspace `Cargo.toml`. pub fn check(root: &Path, bad: &mut bool) { - // `Cargo.lock` of rust. - let path = root.join("Cargo.lock"); + for &(workspace, _, _) in crate::deps::WORKSPACES { + // FIXME check other workspaces too + // `Cargo.lock` of rust. + let path = root.join(workspace).join("Cargo.lock"); - // Open and read the whole file. - let cargo_lock = t!(fs::read_to_string(&path)); - - // Process each line. - for line in cargo_lock.lines() { - // Consider only source entries. - if !line.starts_with("source = ") { + if !path.exists() { + tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock"); continue; } - // Extract source value. - let source = line.split_once('=').unwrap().1.trim(); + // Open and read the whole file. + let cargo_lock = t!(fs::read_to_string(&path)); + + // Process each line. + for line in cargo_lock.lines() { + // Consider only source entries. + if !line.starts_with("source = ") { + continue; + } + + // Extract source value. + let source = line.split_once('=').unwrap().1.trim(); - // Ensure source is allowed. - if !ALLOWED_SOURCES.contains(&&*source) { - tidy_error!(bad, "invalid source: {}", source); + // Ensure source is allowed. + if !ALLOWED_SOURCES.contains(&&*source) { + tidy_error!(bad, "invalid source: {}", source); + } } } } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index dcf218bc189..7e24793adee 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1854; -const ROOT_ENTRY_LIMIT: usize = 866; +const ROOT_ENTRY_LIMIT: usize = 867; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/codegen/vec-reserve-extend.rs b/tests/codegen/vec-reserve-extend.rs new file mode 100644 index 00000000000..d95220104c2 --- /dev/null +++ b/tests/codegen/vec-reserve-extend.rs @@ -0,0 +1,14 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @should_reserve_once +#[no_mangle] +pub fn should_reserve_once(v: &mut Vec<u8>) { + // CHECK: tail call void @llvm.assume + v.try_reserve(3).unwrap(); + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}do_reserve_and_handle + // CHECK-NOT: call {{.*}}__rust_alloc( + v.extend([1, 2, 3]); +} diff --git a/tests/debuginfo/simple-struct.rs b/tests/debuginfo/simple-struct.rs index aa3cf023a71..fea8109223a 100644 --- a/tests/debuginfo/simple-struct.rs +++ b/tests/debuginfo/simple-struct.rs @@ -1,7 +1,7 @@ // min-lldb-version: 310 // ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 -// compile-flags:-g +// compile-flags: -g -Zmir-enable-passes=-CheckAlignment // === GDB TESTS =================================================================================== diff --git a/tests/mir-opt/building/while_storage.rs b/tests/mir-opt/building/while_storage.rs new file mode 100644 index 00000000000..b06c1639c3f --- /dev/null +++ b/tests/mir-opt/building/while_storage.rs @@ -0,0 +1,60 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// Test that we correctly generate StorageDead statements for while loop +// conditions on all branches +// compile-flags: -Zmir-opt-level=0 + +fn get_bool(c: bool) -> bool { + c +} + +// EMIT_MIR while_storage.while_loop.PreCodegen.after.mir +fn while_loop(c: bool) { + // CHECK-LABEL: fn while_loop( + // CHECK: bb0: { + // CHECK-NEXT: goto -> bb1; + // CHECK: bb1: { + // CHECK-NEXT: StorageLive(_3); + // CHECK-NEXT: StorageLive(_2); + // CHECK-NEXT: _2 = _1; + // CHECK-NEXT: _3 = get_bool(move _2) -> [return: bb2, unwind + // CHECK: bb2: { + // CHECK-NEXT: switchInt(move _3) -> [0: bb3, otherwise: bb4]; + // CHECK: bb3: { + // CHECK-NEXT: StorageDead(_2); + // CHECK-NEXT: StorageLive(_9); + // CHECK-NEXT: _0 = const (); + // CHECK-NEXT: StorageDead(_9); + // CHECK-NEXT: goto -> bb8; + // CHECK: bb4: { + // CHECK-NEXT: StorageDead(_2); + // CHECK-NEXT: StorageLive(_5); + // CHECK-NEXT: StorageLive(_4); + // CHECK-NEXT: _4 = _1; + // CHECK-NEXT: _5 = get_bool(move _4) -> [return: bb5, unwind + // CHECK: bb5: { + // CHECK-NEXT: switchInt(move _5) -> [0: bb6, otherwise: bb7]; + // CHECK: bb6: { + // CHECK-NEXT: StorageDead(_4); + // CHECK-NEXT: _6 = const (); + // CHECK-NEXT: StorageDead(_5); + // CHECK-NEXT: StorageDead(_3); + // CHECK-NEXT: goto -> bb1; + // CHECK: bb7: { + // CHECK-NEXT: StorageDead(_4); + // CHECK-NEXT: _0 = const (); + // CHECK-NEXT: StorageDead(_5); + // CHECK-NEXT: goto -> bb8; + // CHECK: bb8: { + // CHECK-NEXT: StorageDead(_3); + // CHECK-NEXT: return; + + while get_bool(c) { + if get_bool(c) { + break; + } + } +} + +fn main() { + while_loop(false); +} diff --git a/tests/mir-opt/building/while_storage.while_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/building/while_storage.while_loop.PreCodegen.after.panic-abort.mir new file mode 100644 index 00000000000..26c82edf2d5 --- /dev/null +++ b/tests/mir-opt/building/while_storage.while_loop.PreCodegen.after.panic-abort.mir @@ -0,0 +1,70 @@ +// MIR for `while_loop` after PreCodegen + +fn while_loop(_1: bool) -> () { + debug c => _1; + let mut _0: (); + let mut _2: bool; + let mut _3: bool; + let mut _4: bool; + let mut _5: bool; + let mut _6: (); + let mut _7: !; + let mut _8: !; + let _9: (); + let mut _10: !; + + bb0: { + goto -> bb1; + } + + bb1: { + StorageLive(_3); + StorageLive(_2); + _2 = _1; + _3 = get_bool(move _2) -> [return: bb2, unwind unreachable]; + } + + bb2: { + switchInt(move _3) -> [0: bb3, otherwise: bb4]; + } + + bb3: { + StorageDead(_2); + StorageLive(_9); + _0 = const (); + StorageDead(_9); + goto -> bb8; + } + + bb4: { + StorageDead(_2); + StorageLive(_5); + StorageLive(_4); + _4 = _1; + _5 = get_bool(move _4) -> [return: bb5, unwind unreachable]; + } + + bb5: { + switchInt(move _5) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + StorageDead(_4); + _6 = const (); + StorageDead(_5); + StorageDead(_3); + goto -> bb1; + } + + bb7: { + StorageDead(_4); + _0 = const (); + StorageDead(_5); + goto -> bb8; + } + + bb8: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/building/while_storage.while_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/building/while_storage.while_loop.PreCodegen.after.panic-unwind.mir new file mode 100644 index 00000000000..1bb72074846 --- /dev/null +++ b/tests/mir-opt/building/while_storage.while_loop.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,70 @@ +// MIR for `while_loop` after PreCodegen + +fn while_loop(_1: bool) -> () { + debug c => _1; + let mut _0: (); + let mut _2: bool; + let mut _3: bool; + let mut _4: bool; + let mut _5: bool; + let mut _6: (); + let mut _7: !; + let mut _8: !; + let _9: (); + let mut _10: !; + + bb0: { + goto -> bb1; + } + + bb1: { + StorageLive(_3); + StorageLive(_2); + _2 = _1; + _3 = get_bool(move _2) -> [return: bb2, unwind continue]; + } + + bb2: { + switchInt(move _3) -> [0: bb3, otherwise: bb4]; + } + + bb3: { + StorageDead(_2); + StorageLive(_9); + _0 = const (); + StorageDead(_9); + goto -> bb8; + } + + bb4: { + StorageDead(_2); + StorageLive(_5); + StorageLive(_4); + _4 = _1; + _5 = get_bool(move _4) -> [return: bb5, unwind continue]; + } + + bb5: { + switchInt(move _5) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + StorageDead(_4); + _6 = const (); + StorageDead(_5); + StorageDead(_3); + goto -> bb1; + } + + bb7: { + StorageDead(_4); + _0 = const (); + StorageDead(_5); + goto -> bb8; + } + + bb8: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index f5d822520a7..87c07279552 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -4,6 +4,12 @@ fn main() -> () { let mut _0: (); let _1: u8; + let mut _5: u8; + let mut _6: u8; + let mut _7: u8; + let mut _8: u8; + let mut _14: u32; + let mut _15: u32; scope 1 { - debug x => _1; + debug x => const 1_u8; @@ -19,34 +25,23 @@ scope 4 { - debug sum => _4; + debug sum => const 6_u8; - let _5: &str; + let _9: &str; scope 5 { -- debug s => _5; +- debug s => _9; + debug s => const "hello, world!"; - let _8: bool; - let _9: bool; - let _10: u32; + let _10: (bool, bool, u32); scope 6 { -- debug ((f: (bool, bool, u32)).0: bool) => _8; -- debug ((f: (bool, bool, u32)).1: bool) => _9; -- debug ((f: (bool, bool, u32)).2: u32) => _10; -+ debug ((f: (bool, bool, u32)).0: bool) => const true; -+ debug ((f: (bool, bool, u32)).1: bool) => const false; -+ debug ((f: (bool, bool, u32)).2: u32) => const 123_u32; - let _6: std::option::Option<u16>; + debug f => _10; + let _11: std::option::Option<u16>; scope 7 { -- debug o => _6; -+ debug o => const Option::<u16>::Some(99_u16); - let _11: u32; - let _12: u32; + debug o => _11; + let _12: Point; scope 8 { -- debug ((p: Point).0: u32) => _11; -- debug ((p: Point).1: u32) => _12; -+ debug ((p: Point).0: u32) => const 32_u32; -+ debug ((p: Point).1: u32) => const 32_u32; - let _7: u32; +- debug p => _12; ++ debug p => const Point {{ x: 32_u32, y: 32_u32 }}; + let _13: u32; scope 9 { -- debug a => _7; +- debug a => _13; + debug a => const 64_u32; } } @@ -59,37 +54,57 @@ } bb0: { + StorageLive(_1); _1 = const 1_u8; + StorageLive(_2); _2 = const 2_u8; + StorageLive(_3); _3 = const 3_u8; StorageLive(_4); - _4 = const 6_u8; StorageLive(_5); - _5 = const "hello, world!"; - StorageLive(_8); - StorageLive(_9); - StorageLive(_10); - _8 = const true; - _9 = const false; - _10 = const 123_u32; StorageLive(_6); - _6 = const Option::<u16>::Some(99_u16); - _11 = const 32_u32; - _12 = const 32_u32; + _6 = const 1_u8; StorageLive(_7); - _7 = const 64_u32; + _7 = const 2_u8; + _5 = const 3_u8; StorageDead(_7); StorageDead(_6); + StorageLive(_8); + _8 = const 3_u8; + _4 = const 6_u8; StorageDead(_8); - StorageDead(_9); - StorageDead(_10); StorageDead(_5); + StorageLive(_9); + _9 = const "hello, world!"; + StorageLive(_10); + _10 = (const true, const false, const 123_u32); + StorageLive(_11); + _11 = Option::<u16>::Some(const 99_u16); + StorageLive(_12); + _12 = const Point {{ x: 32_u32, y: 32_u32 }}; + StorageLive(_13); + StorageLive(_14); + _14 = const 32_u32; + StorageLive(_15); + _15 = const 32_u32; + _13 = const 64_u32; + StorageDead(_15); + StorageDead(_14); + _0 = const (); + StorageDead(_13); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); return; } } - ALLOC0 (size: 4, align: 2) { - 01 00 63 00 │ ..c. + ALLOC0 (size: 8, align: 4) { + 20 00 00 00 20 00 00 00 │ ... ... } diff --git a/tests/mir-opt/const_debuginfo.rs b/tests/mir-opt/const_debuginfo.rs index d8ae08a0723..0e5ac4b8bd6 100644 --- a/tests/mir-opt/const_debuginfo.rs +++ b/tests/mir-opt/const_debuginfo.rs @@ -1,12 +1,23 @@ -// skip-filecheck -// compile-flags: -C overflow-checks=no -Zunsound-mir-opts +// unit-test: ConstDebugInfo +// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+ConstProp struct Point { x: u32, y: u32, } +// EMIT_MIR const_debuginfo.main.ConstDebugInfo.diff fn main() { + // CHECK-LABEL: fn main( + // CHECK: debug x => const 1_u8; + // CHECK: debug y => const 2_u8; + // CHECK: debug z => const 3_u8; + // CHECK: debug sum => const 6_u8; + // CHECK: debug s => const "hello, world!"; + // CHECK: debug f => {{_.*}}; + // CHECK: debug o => {{_.*}}; + // CHECK: debug p => const Point + // CHECK: debug a => const 64_u32; let x = 1u8; let y = 2u8; let z = 3u8; @@ -21,5 +32,3 @@ fn main() { let p = Point { x: 32, y: 32 }; let a = p.x + p.y; } - -// EMIT_MIR const_debuginfo.main.ConstDebugInfo.diff diff --git a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/tests/mir-opt/const_prop/indirect_mutation.bar.ConstProp.diff index 4eafb8d0917..4eafb8d0917 100644 --- a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff +++ b/tests/mir-opt/const_prop/indirect_mutation.bar.ConstProp.diff diff --git a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/tests/mir-opt/const_prop/indirect_mutation.foo.ConstProp.diff index 445d9895d6a..445d9895d6a 100644 --- a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff +++ b/tests/mir-opt/const_prop/indirect_mutation.foo.ConstProp.diff diff --git a/tests/mir-opt/const_prop/indirect_mutation.rs b/tests/mir-opt/const_prop/indirect_mutation.rs new file mode 100644 index 00000000000..ec9da6e8e5c --- /dev/null +++ b/tests/mir-opt/const_prop/indirect_mutation.rs @@ -0,0 +1,41 @@ +// unit-test: ConstProp +// Check that we do not propagate past an indirect mutation. +#![feature(raw_ref_op)] + +// EMIT_MIR indirect_mutation.foo.ConstProp.diff +fn foo() { + // CHECK-LABEL: fn foo( + // CHECK: debug u => _1; + // CHECK: debug y => _3; + // CHECK: _1 = (const 1_i32,); + // CHECK: _2 = &mut (_1.0: i32); + // CHECK: (*_2) = const 5_i32; + // CHECK: _4 = (_1.0: i32); + // CHECK: _3 = Eq(move _4, const 5_i32); + + let mut u = (1,); + *&mut u.0 = 5; + let y = { u.0 } == 5; +} + +// EMIT_MIR indirect_mutation.bar.ConstProp.diff +fn bar() { + // CHECK-LABEL: fn bar( + // CHECK: debug v => _1; + // CHECK: debug y => _4; + // CHECK: _3 = &raw mut (_1.0: i32); + // CHECK: (*_3) = const 5_i32; + // CHECK: _5 = (_1.0: i32); + // CHECK: _4 = Eq(move _5, const 5_i32); + + let mut v = (1,); + unsafe { + *&raw mut v.0 = 5; + } + let y = { v.0 } == 5; +} + +fn main() { + foo(); + bar(); +} diff --git a/tests/mir-opt/const_prop_miscompile.rs b/tests/mir-opt/const_prop_miscompile.rs deleted file mode 100644 index 00696535ac1..00000000000 --- a/tests/mir-opt/const_prop_miscompile.rs +++ /dev/null @@ -1,24 +0,0 @@ -// skip-filecheck -// unit-test: ConstProp -#![feature(raw_ref_op)] - -// EMIT_MIR const_prop_miscompile.foo.ConstProp.diff -fn foo() { - let mut u = (1,); - *&mut u.0 = 5; - let y = { u.0 } == 5; -} - -// EMIT_MIR const_prop_miscompile.bar.ConstProp.diff -fn bar() { - let mut v = (1,); - unsafe { - *&raw mut v.0 = 5; - } - let y = { v.0 } == 5; -} - -fn main() { - foo(); - bar(); -} diff --git a/tests/mir-opt/while_storage.rs b/tests/mir-opt/while_storage.rs deleted file mode 100644 index 3a3d451ee8d..00000000000 --- a/tests/mir-opt/while_storage.rs +++ /dev/null @@ -1,21 +0,0 @@ -// skip-filecheck -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// Test that we correctly generate StorageDead statements for while loop -// conditions on all branches - -fn get_bool(c: bool) -> bool { - c -} - -// EMIT_MIR while_storage.while_loop.PreCodegen.after.mir -fn while_loop(c: bool) { - while get_bool(c) { - if get_bool(c) { - break; - } - } -} - -fn main() { - while_loop(false); -} diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir deleted file mode 100644 index 21c4b92cf04..00000000000 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir +++ /dev/null @@ -1,16 +0,0 @@ -// MIR for `while_loop` after PreCodegen - -fn while_loop(_1: bool) -> () { - debug c => _1; - let mut _0: (); - scope 1 (inlined get_bool) { - debug c => _1; - } - scope 2 (inlined get_bool) { - debug c => _1; - } - - bb0: { - return; - } -} diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir deleted file mode 100644 index 21c4b92cf04..00000000000 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir +++ /dev/null @@ -1,16 +0,0 @@ -// MIR for `while_loop` after PreCodegen - -fn while_loop(_1: bool) -> () { - debug c => _1; - let mut _0: (); - scope 1 (inlined get_bool) { - debug c => _1; - } - scope 2 (inlined get_bool) { - debug c => _1; - } - - bb0: { - return; - } -} diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 71009d32477..1a94649163b 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -7,7 +7,7 @@ extern crate rustc_span; use rustc_interface::interface; use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes}; -use rustc_span::source_map::FileName; +use rustc_span::FileName; use std::path::PathBuf; diff --git a/tests/run-make/crate-hash-rustc-version/Makefile b/tests/run-make/crate-hash-rustc-version/Makefile index f1d2a360410..6bf504bf01b 100644 --- a/tests/run-make/crate-hash-rustc-version/Makefile +++ b/tests/run-make/crate-hash-rustc-version/Makefile @@ -4,7 +4,7 @@ include ../tools.mk # Ensure that crates compiled with different rustc versions cannot # be dynamically linked. -FLAGS := -Cprefer-dynamic -Zsymbol-mangling-version=v0 +FLAGS := -Cprefer-dynamic -Csymbol-mangling-version=v0 UNAME := $(shell uname) ifeq ($(UNAME),Linux) EXT=".so" diff --git a/tests/run-make/use-extern-for-plugins/Makefile b/tests/run-make/use-extern-for-plugins/Makefile deleted file mode 100644 index b8ec7e8dcda..00000000000 --- a/tests/run-make/use-extern-for-plugins/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../tools.mk - -# ignore-freebsd -# ignore-openbsd -# ignore-solaris - -HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //') -ifeq ($(findstring i686,$(HOST)),i686) -TARGET := $(subst i686,x86_64,$(HOST)) -else -TARGET := $(subst x86_64,i686,$(HOST)) -endif - -all: - $(RUSTC) foo.rs -C extra-filename=-host - $(RUSTC) bar.rs -C extra-filename=-targ --target $(TARGET) - $(RUSTC) baz.rs --extern a=$(TMPDIR)/liba-targ.rlib --target $(TARGET) diff --git a/tests/run-make/use-extern-for-plugins/bar.rs b/tests/run-make/use-extern-for-plugins/bar.rs deleted file mode 100644 index 704d2120362..00000000000 --- a/tests/run-make/use-extern-for-plugins/bar.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(no_core)] -#![no_core] -#![crate_type = "lib"] -#![crate_name = "a"] - -#[macro_export] -macro_rules! bar { - () => () -} diff --git a/tests/run-make/use-extern-for-plugins/baz.rs b/tests/run-make/use-extern-for-plugins/baz.rs deleted file mode 100644 index 49a96a0c80b..00000000000 --- a/tests/run-make/use-extern-for-plugins/baz.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(no_core)] -#![no_core] -#![crate_type = "lib"] - -#[macro_use] -extern crate a; - -bar!(); diff --git a/tests/run-make/use-extern-for-plugins/foo.rs b/tests/run-make/use-extern-for-plugins/foo.rs deleted file mode 100644 index dffdc079887..00000000000 --- a/tests/run-make/use-extern-for-plugins/foo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![no_std] -#![crate_type = "lib"] -#![crate_name = "a"] - -#[macro_export] -macro_rules! foo { - () => () -} diff --git a/tests/rustdoc-gui/impl_on_foreign_order.goml b/tests/rustdoc-gui/impl_on_foreign_order.goml new file mode 100644 index 00000000000..a6f5343beb2 --- /dev/null +++ b/tests/rustdoc-gui/impl_on_foreign_order.goml @@ -0,0 +1,6 @@ +// This test ensures that the "implementations on foreign types" of a trait are correctly sorted. +go-to: "file://" + |DOC_PATH| + "/test_docs/foreign_impl_order/trait.Foo.html" +assert-text: ("details:nth-of-type(1) h3", "impl Foo<1> for [u8; 1]") +assert-text: ("details:nth-of-type(2) h3", "impl Foo<2> for [u8; 2]") +assert-text: ("details:nth-of-type(3) h3", "impl Foo<3> for [u8; 3]") +assert-text: ("details:nth-of-type(4) h3", "impl Foo<4> for [u8; 4]") diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml index 1c0c9e79e40..db1605ff220 100644 --- a/tests/rustdoc-gui/search-tab.goml +++ b/tests/rustdoc-gui/search-tab.goml @@ -79,7 +79,7 @@ call-function: ("check-colors", { set-window-size: (851, 600) // Check the size and count in tabs -assert-text: ("#search-tabs > button:nth-child(1) > .count", " (24) ") +assert-text: ("#search-tabs > button:nth-child(1) > .count", " (25) ") assert-text: ("#search-tabs > button:nth-child(2) > .count", " (5) ") assert-text: ("#search-tabs > button:nth-child(3) > .count", " (0) ") store-property: ("#search-tabs > button:nth-child(1)", {"offsetWidth": buttonWidth}) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 138a1b302fd..c7d115bdb98 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -574,3 +574,22 @@ impl ZyxwvutTrait for ZyxwvutMethodDisambiguation { x } } + +pub mod foreign_impl_order { + pub trait Foo<const W: usize> { + fn f(&mut self, with: [u8; W]); + } + + impl Foo<4> for [u8; 4] { + fn f(&mut self, fg: [u8; 4]) {} + } + impl Foo<2> for [u8; 2] { + fn f(&mut self, fg: [u8; 2]) {} + } + impl Foo<1> for [u8; 1] { + fn f(&mut self, fg: [u8; 1]) {} + } + impl Foo<3> for [u8; 3] { + fn f(&mut self, fg: [u8; 3]) {} + } +} diff --git a/tests/rustdoc-ui/issues/issue-83883-describe-lints.stdout b/tests/rustdoc-ui/issues/issue-83883-describe-lints.stdout index bbf66a31583..6021bce6939 100644 --- a/tests/rustdoc-ui/issues/issue-83883-describe-lints.stdout +++ b/tests/rustdoc-ui/issues/issue-83883-describe-lints.stdout @@ -14,11 +14,11 @@ Lint groups provided by rustc: $NAMES $SUB_LINTS -Lint checks provided by plugins loaded by this crate: +Lint checks loaded by this crate: $NAMES $LEVELS $MEANINGS -Lint groups provided by plugins loaded by this crate: +Lint groups loaded by this crate: $NAMES $SUB_LINTS diff --git a/tests/ui-fulldeps/plugin/auxiliary/empty-plugin.rs b/tests/ui-fulldeps/plugin/auxiliary/empty-plugin.rs deleted file mode 100644 index c24cdc97aa5..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/empty-plugin.rs +++ /dev/null @@ -1,9 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_driver; -use rustc_driver::plugin::Registry; - -#[no_mangle] -fn __rustc_plugin_registrar(_: &mut Registry) {} diff --git a/tests/ui-fulldeps/plugin/auxiliary/issue-40001-plugin.rs b/tests/ui-fulldeps/plugin/auxiliary/issue-40001-plugin.rs deleted file mode 100644 index 3f6caecaa5a..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/issue-40001-plugin.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![feature(plugin, rustc_private)] -#![crate_type = "dylib"] - -extern crate rustc_ast_pretty; -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; -extern crate rustc_ast; -extern crate rustc_span; - -use rustc_ast_pretty::pprust; -use rustc_driver::plugin::Registry; -use rustc_hir as hir; -use rustc_hir::intravisit; -use rustc_hir::Node; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_span::def_id::LocalDefId; -use rustc_span::source_map; - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]); - reg.lint_store.register_late_pass(|_| Box::new(MissingAllowedAttrPass)); -} - -declare_lint! { - MISSING_ALLOWED_ATTR, - Deny, - "Checks for missing `allowed_attr` attribute" -} - -declare_lint_pass!(MissingAllowedAttrPass => [MISSING_ALLOWED_ATTR]); - -impl<'tcx> LateLintPass<'tcx> for MissingAllowedAttrPass { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - _: intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Body, - span: source_map::Span, - def_id: LocalDefId, - ) { - let id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - let item = match cx.tcx.hir().get(id) { - Node::Item(item) => item, - _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).def_id), - }; - - let allowed = |attr| pprust::attribute_to_string(attr).contains("allowed_attr"); - if !cx.tcx.hir().attrs(item.hir_id()).iter().any(allowed) { - cx.lint( - MISSING_ALLOWED_ATTR, - "Missing 'allowed_attr' attribute", - |lint| lint.set_span(span) - ); - } - } -} diff --git a/tests/ui-fulldeps/plugin/auxiliary/lint-for-crate.rs b/tests/ui-fulldeps/plugin/auxiliary/lint-for-crate.rs deleted file mode 100644 index 6304c07d2c7..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/lint-for-crate.rs +++ /dev/null @@ -1,43 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; -extern crate rustc_ast; -extern crate rustc_span; - -use rustc_ast::attr; -use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::symbol::Symbol; - -declare_lint! { - CRATE_NOT_OKAY, - Warn, - "crate not marked with #![crate_okay]" -} - -declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); - -impl<'tcx> LateLintPass<'tcx> for Pass { - fn check_crate(&mut self, cx: &LateContext) { - let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let span = cx.tcx.def_span(CRATE_DEF_ID); - if !attr::contains_name(attrs, Symbol::intern("crate_okay")) { - cx.lint(CRATE_NOT_OKAY, "crate is not marked with #![crate_okay]", |lint| { - lint.set_span(span) - }); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]); - reg.lint_store.register_late_pass(|_| Box::new(Pass)); -} diff --git a/tests/ui-fulldeps/plugin/auxiliary/lint-group-plugin-test.rs b/tests/ui-fulldeps/plugin/auxiliary/lint-group-plugin-test.rs deleted file mode 100644 index 150f0c6b9a2..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/lint-group-plugin-test.rs +++ /dev/null @@ -1,43 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -// Load rustc as a plugin to get macros. -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintContext, LintId}; - -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint!(PLEASE_LINT, Warn, "Warn about items named 'pleaselintme'"); - -declare_lint_pass!(Pass => [TEST_LINT, PLEASE_LINT]); - -impl<'tcx> LateLintPass<'tcx> for Pass { - fn check_item(&mut self, cx: &LateContext, it: &rustc_hir::Item) { - match it.ident.as_str() { - "lintme" => cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)), - "pleaselintme" => { - cx.lint(PLEASE_LINT, "item is named 'pleaselintme'", |lint| lint.set_span(it.span)) - } - _ => {} - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]); - reg.lint_store.register_late_pass(|_| Box::new(Pass)); - reg.lint_store.register_group( - true, - "lint_me", - None, - vec![LintId::of(&TEST_LINT), LintId::of(&PLEASE_LINT)], - ); -} diff --git a/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs b/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs deleted file mode 100644 index acc5fe76051..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs +++ /dev/null @@ -1,33 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_ast; - -// Load rustc as a plugin to get macros -extern crate rustc_driver; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_ast::ast; -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; - -declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); - -declare_lint_pass!(Pass => [TEST_LINT]); - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| Box::new(Pass)); -} diff --git a/tests/ui-fulldeps/plugin/auxiliary/lint-tool-test.rs b/tests/ui-fulldeps/plugin/auxiliary/lint-tool-test.rs deleted file mode 100644 index 21de4aa7008..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/lint-tool-test.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![feature(rustc_private)] - -extern crate rustc_ast; - -// Load rustc as a plugin to get macros -extern crate rustc_driver; -extern crate rustc_lint; -#[macro_use] -extern crate rustc_session; - -use rustc_ast as ast; -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext, LintId}; - -declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff"); -declare_tool_lint!( - /// Some docs - pub clippy::TEST_GROUP, - Warn, "Warn about other stuff" -); - -declare_tool_lint!( - /// Some docs - pub rustc::TEST_RUSTC_TOOL_LINT, - Deny, - "Deny internal stuff" -); - -declare_lint_pass!(Pass => [TEST_LINT, TEST_GROUP, TEST_RUSTC_TOOL_LINT]); - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)); - } - if it.ident.name.as_str() == "lintmetoo" { - cx.lint(TEST_GROUP, "item is named 'lintmetoo'", |lint| lint.set_span(it.span)); - } - } -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]); - reg.lint_store.register_early_pass(|| Box::new(Pass)); - reg.lint_store.register_group( - true, - "clippy::group", - Some("clippy_group"), - vec![LintId::of(&TEST_LINT), LintId::of(&TEST_GROUP)], - ); -} diff --git a/tests/ui-fulldeps/plugin/auxiliary/lto-syntax-extension-lib.rs b/tests/ui-fulldeps/plugin/auxiliary/lto-syntax-extension-lib.rs deleted file mode 100644 index 954a1e554da..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/lto-syntax-extension-lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -// no-prefer-dynamic - -#![crate_type = "rlib"] - -pub fn foo() {} diff --git a/tests/ui-fulldeps/plugin/auxiliary/lto-syntax-extension-plugin.rs b/tests/ui-fulldeps/plugin/auxiliary/lto-syntax-extension-plugin.rs deleted file mode 100644 index 9b075c1a5b9..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/lto-syntax-extension-plugin.rs +++ /dev/null @@ -1,11 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; - -use rustc_driver::plugin::Registry; - -#[no_mangle] -fn __rustc_plugin_registrar(_reg: &mut Registry) {} diff --git a/tests/ui-fulldeps/plugin/auxiliary/multiple-plugins-1.rs b/tests/ui-fulldeps/plugin/auxiliary/multiple-plugins-1.rs deleted file mode 100644 index fd6e9e20f03..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/multiple-plugins-1.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type = "dylib"] -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; - -use rustc_driver::plugin::Registry; - -#[no_mangle] -fn __rustc_plugin_registrar(_: &mut Registry) {} diff --git a/tests/ui-fulldeps/plugin/auxiliary/multiple-plugins-2.rs b/tests/ui-fulldeps/plugin/auxiliary/multiple-plugins-2.rs deleted file mode 100644 index fd6e9e20f03..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/multiple-plugins-2.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type = "dylib"] -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; - -use rustc_driver::plugin::Registry; - -#[no_mangle] -fn __rustc_plugin_registrar(_: &mut Registry) {} diff --git a/tests/ui-fulldeps/plugin/auxiliary/outlive-expansion-phase.rs b/tests/ui-fulldeps/plugin/auxiliary/outlive-expansion-phase.rs deleted file mode 100644 index e83dfe80463..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/outlive-expansion-phase.rs +++ /dev/null @@ -1,24 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; - -use std::any::Any; -use std::cell::RefCell; -use rustc_driver::plugin::Registry; - -struct Foo { - foo: isize -} - -impl Drop for Foo { - fn drop(&mut self) {} -} - -#[no_mangle] -fn __rustc_plugin_registrar(_: &mut Registry) { - thread_local!(static FOO: RefCell<Option<Box<Any+Send>>> = RefCell::new(None)); - FOO.with(|s| *s.borrow_mut() = Some(Box::new(Foo { foo: 10 }) as Box<Any+Send>)); -} diff --git a/tests/ui-fulldeps/plugin/auxiliary/rlib-crate-test.rs b/tests/ui-fulldeps/plugin/auxiliary/rlib-crate-test.rs deleted file mode 100644 index 3ba73538ecf..00000000000 --- a/tests/ui-fulldeps/plugin/auxiliary/rlib-crate-test.rs +++ /dev/null @@ -1,12 +0,0 @@ -// no-prefer-dynamic - -#![crate_type = "rlib"] -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; - -use rustc_driver::plugin::Registry; - -#[no_mangle] -fn __rustc_plugin_registrar(_: &mut Registry) {} diff --git a/tests/ui-fulldeps/plugin/feature-gate-plugin.rs b/tests/ui-fulldeps/plugin/feature-gate-plugin.rs deleted file mode 100644 index 85eaf533643..00000000000 --- a/tests/ui-fulldeps/plugin/feature-gate-plugin.rs +++ /dev/null @@ -1,8 +0,0 @@ -// aux-build:empty-plugin.rs -// ignore-stage1 - -#![plugin(empty_plugin)] -//~^ ERROR compiler plugins are deprecated -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui-fulldeps/plugin/feature-gate-plugin.stderr b/tests/ui-fulldeps/plugin/feature-gate-plugin.stderr deleted file mode 100644 index 5e40561c7f5..00000000000 --- a/tests/ui-fulldeps/plugin/feature-gate-plugin.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0658]: compiler plugins are deprecated - --> $DIR/feature-gate-plugin.rs:4:1 - | -LL | #![plugin(empty_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #29597 <https://github.com/rust-lang/rust/issues/29597> for more information - = help: add `#![feature(plugin)]` to the crate attributes to enable - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/feature-gate-plugin.rs:4:1 - | -LL | #![plugin(empty_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui-fulldeps/plugin/gated-plugin.rs b/tests/ui-fulldeps/plugin/gated-plugin.rs deleted file mode 100644 index 85eaf533643..00000000000 --- a/tests/ui-fulldeps/plugin/gated-plugin.rs +++ /dev/null @@ -1,8 +0,0 @@ -// aux-build:empty-plugin.rs -// ignore-stage1 - -#![plugin(empty_plugin)] -//~^ ERROR compiler plugins are deprecated -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui-fulldeps/plugin/gated-plugin.stderr b/tests/ui-fulldeps/plugin/gated-plugin.stderr deleted file mode 100644 index f48f1eab60b..00000000000 --- a/tests/ui-fulldeps/plugin/gated-plugin.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0658]: compiler plugins are deprecated - --> $DIR/gated-plugin.rs:4:1 - | -LL | #![plugin(empty_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #29597 <https://github.com/rust-lang/rust/issues/29597> for more information - = help: add `#![feature(plugin)]` to the crate attributes to enable - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/gated-plugin.rs:4:1 - | -LL | #![plugin(empty_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui-fulldeps/plugin/issue-15778-fail.rs b/tests/ui-fulldeps/plugin/issue-15778-fail.rs deleted file mode 100644 index beecaadf955..00000000000 --- a/tests/ui-fulldeps/plugin/issue-15778-fail.rs +++ /dev/null @@ -1,9 +0,0 @@ -// aux-build:lint-for-crate.rs -// ignore-stage1 -// compile-flags: -D crate-not-okay - -#![feature(plugin)] //~ ERROR crate is not marked with #![crate_okay] -#![plugin(lint_for_crate)] -//~^ WARN use of deprecated attribute `plugin` - -pub fn main() { } diff --git a/tests/ui-fulldeps/plugin/issue-15778-fail.stderr b/tests/ui-fulldeps/plugin/issue-15778-fail.stderr deleted file mode 100644 index a37893e1203..00000000000 --- a/tests/ui-fulldeps/plugin/issue-15778-fail.stderr +++ /dev/null @@ -1,22 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-15778-fail.rs:6:1 - | -LL | #![plugin(lint_for_crate)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: crate is not marked with #![crate_okay] - --> $DIR/issue-15778-fail.rs:5:1 - | -LL | / #![feature(plugin)] -LL | | #![plugin(lint_for_crate)] -LL | | -LL | | -LL | | pub fn main() { } - | |_________________^ - | - = note: requested on the command line with `-D crate-not-okay` - -error: aborting due to previous error; 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/issue-40001.rs b/tests/ui-fulldeps/plugin/issue-40001.rs deleted file mode 100644 index e14338fdbbf..00000000000 --- a/tests/ui-fulldeps/plugin/issue-40001.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass -// aux-build:issue-40001-plugin.rs -// ignore-stage1 - -#![feature(plugin, register_tool)] -#![plugin(issue_40001_plugin)] //~ WARNING compiler plugins are deprecated -#![register_tool(plugin)] - -#[plugin::allowed_attr] -fn main() {} diff --git a/tests/ui-fulldeps/plugin/issue-40001.stderr b/tests/ui-fulldeps/plugin/issue-40001.stderr deleted file mode 100644 index 73ec0692464..00000000000 --- a/tests/ui-fulldeps/plugin/issue-40001.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-40001.rs:6:1 - | -LL | #![plugin(issue_40001_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.rs b/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.rs deleted file mode 100644 index 9f8a879608c..00000000000 --- a/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.rs +++ /dev/null @@ -1,17 +0,0 @@ -// aux-build:lint-group-plugin-test.rs -// ignore-stage1 -// compile-flags: -D lint-me - -#![feature(plugin)] - -#![plugin(lint_group_plugin_test)] -//~^ WARN use of deprecated attribute `plugin` - -fn lintme() { } //~ ERROR item is named 'lintme' - -fn pleaselintme() { } //~ ERROR item is named 'pleaselintme' - -pub fn main() { - lintme(); - pleaselintme(); -} diff --git a/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr b/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr deleted file mode 100644 index 6e17bbde021..00000000000 --- a/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr +++ /dev/null @@ -1,28 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-group-plugin-deny-cmdline.rs:7:1 - | -LL | #![plugin(lint_group_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: item is named 'lintme' - --> $DIR/lint-group-plugin-deny-cmdline.rs:10:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: `-D test-lint` implied by `-D lint-me` - = help: to override `-D lint-me` add `#[allow(test_lint)]` - -error: item is named 'pleaselintme' - --> $DIR/lint-group-plugin-deny-cmdline.rs:12:1 - | -LL | fn pleaselintme() { } - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D please-lint` implied by `-D lint-me` - = help: to override `-D lint-me` add `#[allow(please_lint)]` - -error: aborting due to 2 previous errors; 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/lint-group-plugin.rs b/tests/ui-fulldeps/plugin/lint-group-plugin.rs deleted file mode 100644 index 7b74be7a954..00000000000 --- a/tests/ui-fulldeps/plugin/lint-group-plugin.rs +++ /dev/null @@ -1,17 +0,0 @@ -// run-pass -// aux-build:lint-group-plugin-test.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(lint_group_plugin_test)] //~ WARNING use of deprecated attribute -#![allow(dead_code)] - -fn lintme() { } //~ WARNING item is named 'lintme' -fn pleaselintme() { } //~ WARNING item is named 'pleaselintme' - -#[allow(lint_me)] -pub fn main() { - fn lintme() { } - - fn pleaselintme() { } -} diff --git a/tests/ui-fulldeps/plugin/lint-group-plugin.stderr b/tests/ui-fulldeps/plugin/lint-group-plugin.stderr deleted file mode 100644 index 6f429dad017..00000000000 --- a/tests/ui-fulldeps/plugin/lint-group-plugin.stderr +++ /dev/null @@ -1,26 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-group-plugin.rs:6:1 - | -LL | #![plugin(lint_group_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: item is named 'lintme' - --> $DIR/lint-group-plugin.rs:9:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(test_lint)]` on by default - -warning: item is named 'pleaselintme' - --> $DIR/lint-group-plugin.rs:10:1 - | -LL | fn pleaselintme() { } - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(please_lint)]` on by default - -warning: 3 warnings emitted - diff --git a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-allow.rs b/tests/ui-fulldeps/plugin/lint-plugin-cmdline-allow.rs deleted file mode 100644 index 1cc16e2fd1c..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-allow.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -// aux-build:lint-plugin-test.rs -// ignore-stage1 -// compile-flags: -A test-lint - -#![feature(plugin)] -#![plugin(lint_plugin_test)] //~ WARNING compiler plugins are deprecated - -fn lintme() { } - -pub fn main() { -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-allow.stderr b/tests/ui-fulldeps/plugin/lint-plugin-cmdline-allow.stderr deleted file mode 100644 index f06703a2784..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-allow.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-cmdline-allow.rs:7:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-load.rs b/tests/ui-fulldeps/plugin/lint-plugin-cmdline-load.rs deleted file mode 100644 index 0bd95dfbd14..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-load.rs +++ /dev/null @@ -1,13 +0,0 @@ -// check-pass -// aux-build:lint-plugin-test.rs -// ignore-stage1 -// compile-flags: -Z crate-attr=plugin(lint_plugin_test) - -#![feature(plugin)] - -fn lintme() { } //~ WARNING item is named 'lintme' - -#[allow(test_lint)] -pub fn main() { - fn lintme() { } -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-load.stderr b/tests/ui-fulldeps/plugin/lint-plugin-cmdline-load.stderr deleted file mode 100644 index 82679c9e10a..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-cmdline-load.stderr +++ /dev/null @@ -1,18 +0,0 @@ -warning: item is named 'lintme' - --> $DIR/lint-plugin-cmdline-load.rs:8:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(test_lint)]` on by default - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> <crate attribute>:1:1 - | -LL | plugin(lint_plugin_test) - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: 2 warnings emitted - diff --git a/tests/ui-fulldeps/plugin/lint-plugin-deny-attr.rs b/tests/ui-fulldeps/plugin/lint-plugin-deny-attr.rs deleted file mode 100644 index 04230a8e883..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-deny-attr.rs +++ /dev/null @@ -1,13 +0,0 @@ -// aux-build:lint-plugin-test.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(lint_plugin_test)] -//~^ WARN use of deprecated attribute `plugin` -#![deny(test_lint)] - -fn lintme() { } //~ ERROR item is named 'lintme' - -pub fn main() { - lintme(); -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin-deny-attr.stderr b/tests/ui-fulldeps/plugin/lint-plugin-deny-attr.stderr deleted file mode 100644 index 5e8891bf1f1..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-deny-attr.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: item is named 'lintme' - --> $DIR/lint-plugin-deny-attr.rs:9:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-plugin-deny-attr.rs:7:9 - | -LL | #![deny(test_lint)] - | ^^^^^^^^^ - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-deny-attr.rs:5:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/lint-plugin-deny-cmdline.rs b/tests/ui-fulldeps/plugin/lint-plugin-deny-cmdline.rs deleted file mode 100644 index c460cfd5f94..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-deny-cmdline.rs +++ /dev/null @@ -1,13 +0,0 @@ -// aux-build:lint-plugin-test.rs -// ignore-stage1 -// compile-flags: -D test-lint - -#![feature(plugin)] -#![plugin(lint_plugin_test)] -//~^ WARN use of deprecated attribute `plugin` - -fn lintme() { } //~ ERROR item is named 'lintme' - -pub fn main() { - lintme(); -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin-deny-cmdline.stderr b/tests/ui-fulldeps/plugin/lint-plugin-deny-cmdline.stderr deleted file mode 100644 index d5d6b535214..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-deny-cmdline.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: item is named 'lintme' - --> $DIR/lint-plugin-deny-cmdline.rs:9:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: requested on the command line with `-D test-lint` - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-deny-cmdline.rs:6:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/lint-plugin-forbid-attrs.rs b/tests/ui-fulldeps/plugin/lint-plugin-forbid-attrs.rs deleted file mode 100644 index cf31b3ec158..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-forbid-attrs.rs +++ /dev/null @@ -1,16 +0,0 @@ -// aux-build:lint-plugin-test.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(lint_plugin_test)] -//~^ WARN use of deprecated attribute `plugin` -#![forbid(test_lint)] - -fn lintme() {} //~ ERROR item is named 'lintme' - -#[allow(test_lint)] -//~^ ERROR allow(test_lint) incompatible -//~| ERROR allow(test_lint) incompatible -pub fn main() { - lintme(); -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin-forbid-attrs.stderr b/tests/ui-fulldeps/plugin/lint-plugin-forbid-attrs.stderr deleted file mode 100644 index 66ea2e88f0c..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-forbid-attrs.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0453]: allow(test_lint) incompatible with previous forbid - --> $DIR/lint-plugin-forbid-attrs.rs:11:9 - | -LL | #![forbid(test_lint)] - | --------- `forbid` level set here -... -LL | #[allow(test_lint)] - | ^^^^^^^^^ overruled by previous forbid - -error: item is named 'lintme' - --> $DIR/lint-plugin-forbid-attrs.rs:9:1 - | -LL | fn lintme() {} - | ^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-plugin-forbid-attrs.rs:7:11 - | -LL | #![forbid(test_lint)] - | ^^^^^^^^^ - -error[E0453]: allow(test_lint) incompatible with previous forbid - --> $DIR/lint-plugin-forbid-attrs.rs:11:9 - | -LL | #![forbid(test_lint)] - | --------- `forbid` level set here -... -LL | #[allow(test_lint)] - | ^^^^^^^^^ overruled by previous forbid - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-forbid-attrs.rs:5:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to 3 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0453`. diff --git a/tests/ui-fulldeps/plugin/lint-plugin-forbid-cmdline.rs b/tests/ui-fulldeps/plugin/lint-plugin-forbid-cmdline.rs deleted file mode 100644 index b9d1aa85a69..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-forbid-cmdline.rs +++ /dev/null @@ -1,15 +0,0 @@ -// aux-build:lint-plugin-test.rs -// ignore-stage1 -// compile-flags: -F test-lint - -#![feature(plugin)] -#![plugin(lint_plugin_test)] -//~^ WARN use of deprecated attribute `plugin` -fn lintme() { } //~ ERROR item is named 'lintme' - -#[allow(test_lint)] //~ ERROR allow(test_lint) incompatible - //~| ERROR allow(test_lint) incompatible - -pub fn main() { - lintme(); -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin-forbid-cmdline.stderr b/tests/ui-fulldeps/plugin/lint-plugin-forbid-cmdline.stderr deleted file mode 100644 index 9dbad702545..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin-forbid-cmdline.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0453]: allow(test_lint) incompatible with previous forbid - --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 - | -LL | #[allow(test_lint)] - | ^^^^^^^^^ overruled by previous forbid - | - = note: `forbid` lint level was set on command line - -error: item is named 'lintme' - --> $DIR/lint-plugin-forbid-cmdline.rs:8:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: requested on the command line with `-F test-lint` - -error[E0453]: allow(test_lint) incompatible with previous forbid - --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 - | -LL | #[allow(test_lint)] - | ^^^^^^^^^ overruled by previous forbid - | - = note: `forbid` lint level was set on command line - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin-forbid-cmdline.rs:6:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to 3 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0453`. diff --git a/tests/ui-fulldeps/plugin/lint-plugin.rs b/tests/ui-fulldeps/plugin/lint-plugin.rs deleted file mode 100644 index 66057eea6bc..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// aux-build:lint-plugin-test.rs -// ignore-stage1 -#![feature(plugin)] -#![plugin(lint_plugin_test)] //~ WARNING use of deprecated attribute -#![allow(dead_code)] - -fn lintme() { } //~ WARNING item is named 'lintme' - -#[allow(test_lint)] -pub fn main() { - fn lintme() { } -} diff --git a/tests/ui-fulldeps/plugin/lint-plugin.stderr b/tests/ui-fulldeps/plugin/lint-plugin.stderr deleted file mode 100644 index dd5d3d72ecf..00000000000 --- a/tests/ui-fulldeps/plugin/lint-plugin.stderr +++ /dev/null @@ -1,18 +0,0 @@ -warning: item is named 'lintme' - --> $DIR/lint-plugin.rs:8:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | - = note: `#[warn(test_lint)]` on by default - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-plugin.rs:5:1 - | -LL | #![plugin(lint_plugin_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: 2 warnings emitted - diff --git a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.rs b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.rs deleted file mode 100644 index 83a8b3e1a7e..00000000000 --- a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -// aux-build:lint-tool-test.rs -// ignore-stage1 -// compile-flags: -A test-lint - -#![feature(plugin)] -#![plugin(lint_tool_test)] //~ WARNING compiler plugins are deprecated - -fn lintme() {} -//~^ WARNING item is named 'lintme' [clippy::test_lint] - -pub fn main() {} diff --git a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr deleted file mode 100644 index 4916b180a36..00000000000 --- a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - | - = help: change it to clippy::test_lint - = note: requested on the command line with `-A test_lint` - = note: `#[warn(renamed_and_removed_lints)]` on by default - -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - | - = help: change it to clippy::test_lint - = note: requested on the command line with `-A test_lint` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: item is named 'lintme' - --> $DIR/lint-tool-cmdline-allow.rs:9:1 - | -LL | fn lintme() {} - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(clippy::test_lint)]` on by default - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-tool-cmdline-allow.rs:7:1 - | -LL | #![plugin(lint_tool_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - | - = help: change it to clippy::test_lint - = note: requested on the command line with `-A test_lint` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: 5 warnings emitted - diff --git a/tests/ui-fulldeps/plugin/lint-tool-test.rs b/tests/ui-fulldeps/plugin/lint-tool-test.rs deleted file mode 100644 index f92bcd213b8..00000000000 --- a/tests/ui-fulldeps/plugin/lint-tool-test.rs +++ /dev/null @@ -1,36 +0,0 @@ -// aux-build:lint-tool-test.rs -// ignore-stage1 -// compile-flags: --cfg foo - -#![feature(plugin)] -#![plugin(lint_tool_test)] -//~^ WARN use of deprecated attribute `plugin` -#![allow(dead_code)] -#![cfg_attr(foo, warn(test_lint))] -//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future -#![deny(clippy_group)] -//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future -//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future -//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future - -fn lintme() { } //~ ERROR item is named 'lintme' - -#[allow(clippy::group)] -fn lintmetoo() {} - -#[allow(clippy::test_lint)] -pub fn main() { - fn lintme() { } - fn lintmetoo() { } //~ ERROR item is named 'lintmetoo' -} - -#[allow(test_group)] -//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future -#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist` -fn hello() { - fn lintmetoo() { } -} diff --git a/tests/ui-fulldeps/plugin/lint-tool-test.stderr b/tests/ui-fulldeps/plugin/lint-tool-test.stderr deleted file mode 100644 index d1f0714f042..00000000000 --- a/tests/ui-fulldeps/plugin/lint-tool-test.stderr +++ /dev/null @@ -1,107 +0,0 @@ -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:9:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - | - = note: `#[warn(renamed_and_removed_lints)]` on by default - -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ help: change it to: `clippy::group` - -warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 - | -LL | #[allow(test_group)] - | ^^^^^^^^^^ help: change it to: `clippy::test_group` - -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:9:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ help: change it to: `clippy::group` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: item is named 'lintme' - --> $DIR/lint-tool-test.rs:18:1 - | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-tool-test.rs:13:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ - = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]` - -error: item is named 'lintmetoo' - --> $DIR/lint-tool-test.rs:26:5 - | -LL | fn lintmetoo() { } - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]` - -warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 - | -LL | #[allow(test_group)] - | ^^^^^^^^^^ help: change it to: `clippy::test_group` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: unknown lint: `this_lint_does_not_exist` - --> $DIR/lint-tool-test.rs:33:8 - | -LL | #[deny(this_lint_does_not_exist)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unknown_lints)]` on by default - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lint-tool-test.rs:6:1 - | -LL | #![plugin(lint_tool_test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:9:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 - | -LL | #![deny(clippy_group)] - | ^^^^^^^^^^^^ help: change it to: `clippy::group` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 - | -LL | #[allow(test_group)] - | ^^^^^^^^^^ help: change it to: `clippy::test_group` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors; 11 warnings emitted - diff --git a/tests/ui-fulldeps/plugin/lto-syntax-extension.rs b/tests/ui-fulldeps/plugin/lto-syntax-extension.rs deleted file mode 100644 index 5964e70f195..00000000000 --- a/tests/ui-fulldeps/plugin/lto-syntax-extension.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass -// aux-build:lto-syntax-extension-lib.rs -// aux-build:lto-syntax-extension-plugin.rs -// compile-flags:-C lto -// ignore-stage1 -// no-prefer-dynamic - -#![feature(plugin)] -#![plugin(lto_syntax_extension_plugin)] //~ WARNING compiler plugins are deprecated - -extern crate lto_syntax_extension_lib; - -fn main() { - lto_syntax_extension_lib::foo(); -} diff --git a/tests/ui-fulldeps/plugin/lto-syntax-extension.stderr b/tests/ui-fulldeps/plugin/lto-syntax-extension.stderr deleted file mode 100644 index 555493f3230..00000000000 --- a/tests/ui-fulldeps/plugin/lto-syntax-extension.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/lto-syntax-extension.rs:9:1 - | -LL | #![plugin(lto_syntax_extension_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/macro-crate-rlib.rs b/tests/ui-fulldeps/plugin/macro-crate-rlib.rs deleted file mode 100644 index 38bd340539b..00000000000 --- a/tests/ui-fulldeps/plugin/macro-crate-rlib.rs +++ /dev/null @@ -1,9 +0,0 @@ -// aux-build:rlib-crate-test.rs -// ignore-stage1 -// ignore-cross-compile gives a different error message - -#![feature(plugin)] -#![plugin(rlib_crate_test)] -//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib - -fn main() {} diff --git a/tests/ui-fulldeps/plugin/macro-crate-rlib.stderr b/tests/ui-fulldeps/plugin/macro-crate-rlib.stderr deleted file mode 100644 index 0651cee56f7..00000000000 --- a/tests/ui-fulldeps/plugin/macro-crate-rlib.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0457]: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format - --> $DIR/macro-crate-rlib.rs:6:11 - | -LL | #![plugin(rlib_crate_test)] - | ^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0457`. diff --git a/tests/ui-fulldeps/plugin/multiple-plugins.rs b/tests/ui-fulldeps/plugin/multiple-plugins.rs deleted file mode 100644 index 9af3ebd570c..00000000000 --- a/tests/ui-fulldeps/plugin/multiple-plugins.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass -// aux-build:multiple-plugins-1.rs -// aux-build:multiple-plugins-2.rs -// ignore-stage1 - -// Check that the plugin registrar of multiple plugins doesn't conflict - -#![feature(plugin)] -#![plugin(multiple_plugins_1)] //~ WARN use of deprecated attribute `plugin` -#![plugin(multiple_plugins_2)] //~ WARN use of deprecated attribute `plugin` - -fn main() {} diff --git a/tests/ui-fulldeps/plugin/multiple-plugins.stderr b/tests/ui-fulldeps/plugin/multiple-plugins.stderr deleted file mode 100644 index 878ffabfc7f..00000000000 --- a/tests/ui-fulldeps/plugin/multiple-plugins.stderr +++ /dev/null @@ -1,16 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/multiple-plugins.rs:9:1 - | -LL | #![plugin(multiple_plugins_1)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/multiple-plugins.rs:10:1 - | -LL | #![plugin(multiple_plugins_2)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - -warning: 2 warnings emitted - diff --git a/tests/ui-fulldeps/plugin/outlive-expansion-phase.rs b/tests/ui-fulldeps/plugin/outlive-expansion-phase.rs deleted file mode 100644 index fb22888d98a..00000000000 --- a/tests/ui-fulldeps/plugin/outlive-expansion-phase.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass -// aux-build:outlive-expansion-phase.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(outlive_expansion_phase)] //~ WARNING compiler plugins are deprecated - -pub fn main() {} diff --git a/tests/ui-fulldeps/plugin/outlive-expansion-phase.stderr b/tests/ui-fulldeps/plugin/outlive-expansion-phase.stderr deleted file mode 100644 index e40a08ae73b..00000000000 --- a/tests/ui-fulldeps/plugin/outlive-expansion-phase.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/outlive-expansion-phase.rs:6:1 - | -LL | #![plugin(outlive_expansion_phase)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui-fulldeps/plugin/plugin-args.rs b/tests/ui-fulldeps/plugin/plugin-args.rs deleted file mode 100644 index 488f2b775bf..00000000000 --- a/tests/ui-fulldeps/plugin/plugin-args.rs +++ /dev/null @@ -1,9 +0,0 @@ -// aux-build:empty-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(empty_plugin(args))] -//~^ ERROR malformed `plugin` attribute -//~| WARNING compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui-fulldeps/plugin/plugin-args.stderr b/tests/ui-fulldeps/plugin/plugin-args.stderr deleted file mode 100644 index 177f33005c8..00000000000 --- a/tests/ui-fulldeps/plugin/plugin-args.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0498]: malformed `plugin` attribute - --> $DIR/plugin-args.rs:5:11 - | -LL | #![plugin(empty_plugin(args))] - | ^^^^^^^^^^^^^^^^^^ malformed attribute - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/plugin-args.rs:5:1 - | -LL | #![plugin(empty_plugin(args))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0498`. diff --git a/tests/ui-fulldeps/plugin/plugin-as-extern-crate.rs b/tests/ui-fulldeps/plugin/plugin-as-extern-crate.rs deleted file mode 100644 index 4d26e08d81e..00000000000 --- a/tests/ui-fulldeps/plugin/plugin-as-extern-crate.rs +++ /dev/null @@ -1,10 +0,0 @@ -// check-pass -// aux-build:empty-plugin.rs -// ignore-cross-compile -// -// empty_plugin will not compile on a cross-compiled target because -// librustc_ast is not compiled for it. - -extern crate empty_plugin; // OK, plugin crates are still crates - -fn main() {} diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 541be7ebbc0..3d6cff00a6d 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -38,9 +38,9 @@ use rustc_ast::*; use rustc_ast_pretty::pprust; use rustc_parse::new_parser_from_source_str; use rustc_session::parse::ParseSess; -use rustc_span::source_map::FilePathMapping; -use rustc_span::source_map::{FileName, Spanned, DUMMY_SP}; +use rustc_span::source_map::{FilePathMapping, Spanned}; use rustc_span::symbol::Ident; +use rustc_span::{FileName, DUMMY_SP}; use thin_vec::{thin_vec, ThinVec}; fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> { diff --git a/tests/ui/borrowck/alias-liveness/escaping-bounds-2.rs b/tests/ui/borrowck/alias-liveness/escaping-bounds-2.rs new file mode 100644 index 00000000000..05884f6741c --- /dev/null +++ b/tests/ui/borrowck/alias-liveness/escaping-bounds-2.rs @@ -0,0 +1,14 @@ +trait Trait { + type Gat<'a: 'b, 'b: 'c, 'c>: 'c; +} + +fn get_func<'a, T: Trait>(_: &'a str) -> fn(T::Gat<'a, '_, 'static>) { + loop {} +} + +fn test<T: Trait>() { + let func = get_func::<T>(&String::new()); //~ ERROR temporary value dropped + drop(func); +} + +fn main() {} diff --git a/tests/ui/borrowck/alias-liveness/escaping-bounds-2.stderr b/tests/ui/borrowck/alias-liveness/escaping-bounds-2.stderr new file mode 100644 index 00000000000..7fd0cb9bb02 --- /dev/null +++ b/tests/ui/borrowck/alias-liveness/escaping-bounds-2.stderr @@ -0,0 +1,19 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/escaping-bounds-2.rs:10:31 + | +LL | let func = get_func::<T>(&String::new()); + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | drop(func); + | ---- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = String::new(); +LL ~ let func = get_func::<T>(&binding); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/alias-liveness/escaping-bounds.rs b/tests/ui/borrowck/alias-liveness/escaping-bounds.rs new file mode 100644 index 00000000000..3ccdc78e60a --- /dev/null +++ b/tests/ui/borrowck/alias-liveness/escaping-bounds.rs @@ -0,0 +1,22 @@ +// check-pass + +// Ensure that we don't ICE when an alias that has escaping bound vars is +// required to be live. This is because the code that allows us to deduce an +// appropriate outlives bound for a given alias type (in this test, a +// projection) does not handle aliases with escaping bound vars. +// See <https://github.com/rust-lang/rust/issues/117455>. + +trait Foo { + type Assoc<'a, 'b>: 'static; +} + +struct MentionsLifetimeAndType<'a, T>(&'a (), T); + +fn foo<'a, 'b, T: Foo>(_: <T as Foo>::Assoc<'a, 'b>) {} + +fn test<'b, T: Foo>() { + let y: MentionsLifetimeAndType<'_, for<'a> fn(<T as Foo>::Assoc<'a, 'b>)> = + MentionsLifetimeAndType(&(), foo); +} + +fn main() {} diff --git a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr index 0807f459029..85426dd9a5e 100644 --- a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr @@ -5,10 +5,10 @@ LL | let _b = || { match l1 { L1::A => () } }; | ^^ pattern `L1::B` not covered | note: `L1` defined here - --> $DIR/non-exhaustive-match.rs:12:14 + --> $DIR/non-exhaustive-match.rs:12:6 | LL | enum L1 { A, B } - | -- ^ not covered + | ^^ - not covered = note: the matched value is of type `L1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/closures/closure-expected.rs b/tests/ui/closures/closure-expected.rs index 68cac3dd85e..d730bcd1faf 100644 --- a/tests/ui/closures/closure-expected.rs +++ b/tests/ui/closures/closure-expected.rs @@ -1,5 +1,5 @@ fn main() { let x = Some(1); let y = x.or_else(4); - //~^ ERROR expected a `FnOnce<()>` closure, found `{integer}` + //~^ ERROR expected a `FnOnce()` closure, found `{integer}` } diff --git a/tests/ui/closures/closure-expected.stderr b/tests/ui/closures/closure-expected.stderr index 87a5d67a420..565038f5144 100644 --- a/tests/ui/closures/closure-expected.stderr +++ b/tests/ui/closures/closure-expected.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` +error[E0277]: expected a `FnOnce()` closure, found `{integer}` --> $DIR/closure-expected.rs:3:23 | LL | let y = x.or_else(4); - | ------- ^ expected an `FnOnce<()>` closure, found `{integer}` + | ------- ^ expected an `FnOnce()` closure, found `{integer}` | | | required by a bound introduced by this call | diff --git a/tests/ui/closures/coerce-unsafe-to-closure.stderr b/tests/ui/closures/coerce-unsafe-to-closure.stderr index 449cd0b3177..bd4ab13a205 100644 --- a/tests/ui/closures/coerce-unsafe-to-closure.stderr +++ b/tests/ui/closures/coerce-unsafe-to-closure.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` +error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` --> $DIR/coerce-unsafe-to-closure.rs:2:44 | LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); diff --git a/tests/ui/consts/assert-type-intrinsics.rs b/tests/ui/consts/assert-type-intrinsics.rs index b4fd423becd..32b5f5c92c5 100644 --- a/tests/ui/consts/assert-type-intrinsics.rs +++ b/tests/ui/consts/assert-type-intrinsics.rs @@ -1,5 +1,4 @@ #![feature(never_type)] -#![feature(const_assert_type2)] #![feature(core_intrinsics)] use std::intrinsics; diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr index 3c03b03deee..66c4f0f9cd6 100644 --- a/tests/ui/consts/assert-type-intrinsics.stderr +++ b/tests/ui/consts/assert-type-intrinsics.stderr @@ -1,20 +1,20 @@ error[E0080]: evaluation of constant value failed - --> $DIR/assert-type-intrinsics.rs:12:9 + --> $DIR/assert-type-intrinsics.rs:11:9 | LL | MaybeUninit::<!>::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to instantiate uninhabited type `!`', $DIR/assert-type-intrinsics.rs:12:36 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to instantiate uninhabited type `!`', $DIR/assert-type-intrinsics.rs:11:36 error[E0080]: evaluation of constant value failed - --> $DIR/assert-type-intrinsics.rs:16:9 + --> $DIR/assert-type-intrinsics.rs:15:9 | LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to leave type `&i32` uninitialized, which is invalid', $DIR/assert-type-intrinsics.rs:16:9 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to leave type `&i32` uninitialized, which is invalid', $DIR/assert-type-intrinsics.rs:15:9 error[E0080]: evaluation of constant value failed - --> $DIR/assert-type-intrinsics.rs:20:9 + --> $DIR/assert-type-intrinsics.rs:19:9 | LL | intrinsics::assert_zero_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to zero-initialize type `&i32`, which is invalid', $DIR/assert-type-intrinsics.rs:20:9 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to zero-initialize type `&i32`, which is invalid', $DIR/assert-type-intrinsics.rs:19:9 error: aborting due to 3 previous errors diff --git a/tests/ui/coroutine/borrowing.stderr b/tests/ui/coroutine/borrowing.stderr index 192ffaaa26b..acd4cdafdfd 100644 --- a/tests/ui/coroutine/borrowing.stderr +++ b/tests/ui/coroutine/borrowing.stderr @@ -1,24 +1,16 @@ error[E0597]: `a` does not live long enough --> $DIR/borrowing.rs:9:33 | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; LL | Pin::new(&mut || yield &a).resume(()) - | ----------^ - | | | - | | borrowed value does not live long enough + | -- ^ borrowed value does not live long enough + | | | value captured here by coroutine - | a temporary with access to the borrow is created here ... LL | LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for coroutine - | | - | `a` dropped here while still borrowed - | - = note: the temporary is part of an expression at the end of a block; - consider forcing this temporary to be dropped sooner, before the block's local variables are dropped -help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block - | -LL | let x = Pin::new(&mut || yield &a).resume(()); x - | +++++++ +++ + | - `a` dropped here while still borrowed error[E0597]: `a` does not live long enough --> $DIR/borrowing.rs:16:20 diff --git a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs index feaaa71ea9c..ad39b71b0eb 100644 --- a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs +++ b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs @@ -1,4 +1,5 @@ // edition:2021 +// check-pass #![feature(coroutines)] fn main() { @@ -6,6 +7,5 @@ fn main() { || { let _c = || yield *&mut *x; || _ = &mut *x; - //~^ cannot borrow `*x` as mutable more than once at a time }; } diff --git a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.stderr b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.stderr deleted file mode 100644 index 77da6c4cdc9..00000000000 --- a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/issue-110929-coroutine-conflict-error-ice.rs:8:9 - | -LL | let _c = || yield *&mut *x; - | -- -- first borrow occurs due to use of `*x` in coroutine - | | - | first mutable borrow occurs here -LL | || _ = &mut *x; - | ^^ -- second borrow occurs due to use of `*x` in closure - | | - | second mutable borrow occurs here -LL | -LL | }; - | - first borrow might be used here, when `_c` is dropped and runs the destructor for coroutine - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/coroutine/retain-resume-ref.stderr b/tests/ui/coroutine/retain-resume-ref.stderr index 983443bbfeb..e33310d12d9 100644 --- a/tests/ui/coroutine/retain-resume-ref.stderr +++ b/tests/ui/coroutine/retain-resume-ref.stderr @@ -4,10 +4,9 @@ error[E0499]: cannot borrow `thing` as mutable more than once at a time LL | gen.as_mut().resume(&mut thing); | ---------- first mutable borrow occurs here LL | gen.as_mut().resume(&mut thing); - | ^^^^^^^^^^ second mutable borrow occurs here -LL | -LL | } - | - first borrow might be used here, when `gen` is dropped and runs the destructor for coroutine + | ------ ^^^^^^^^^^ second mutable borrow occurs here + | | + | first borrow later used by call error: aborting due to previous error diff --git a/tests/ui/dropck/coroutine-liveness-1.rs b/tests/ui/dropck/coroutine-liveness-1.rs new file mode 100644 index 00000000000..aea4d15ad90 --- /dev/null +++ b/tests/ui/dropck/coroutine-liveness-1.rs @@ -0,0 +1,18 @@ +// check-pass +// edition: 2021 + +// regression test for #116242. +use std::future; + +fn main() { + let mut recv = future::ready(()); + let _combined_fut = async { + let _ = || read(&mut recv); + }; + + drop(recv); +} + +fn read<F: future::Future>(_: &mut F) -> F::Output { + todo!() +} diff --git a/tests/ui/dropck/coroutine-liveness-2.rs b/tests/ui/dropck/coroutine-liveness-2.rs new file mode 100644 index 00000000000..416a073c6b9 --- /dev/null +++ b/tests/ui/dropck/coroutine-liveness-2.rs @@ -0,0 +1,23 @@ +// check-pass +// edition: 2021 + +// regression test found while working on #117134. +use std::future; + +fn main() { + let mut recv = future::ready(()); + let _combined_fut = async { + let _ = || read(&mut recv); + }; + + let _uwu = (String::new(), _combined_fut); + // Dropping a coroutine as part of a more complex + // types should not add unnecessary liveness + // constraints. + + drop(recv); +} + +fn read<F: future::Future>(_: &mut F) -> F::Output { + todo!() +} diff --git a/tests/ui/error-codes/E0004.stderr b/tests/ui/error-codes/E0004.stderr index 603bc5237ea..ced478d65ea 100644 --- a/tests/ui/error-codes/E0004.stderr +++ b/tests/ui/error-codes/E0004.stderr @@ -5,12 +5,12 @@ LL | match x { | ^ pattern `Terminator::HastaLaVistaBaby` not covered | note: `Terminator` defined here - --> $DIR/E0004.rs:2:5 + --> $DIR/E0004.rs:1:6 | LL | enum Terminator { - | ---------- + | ^^^^^^^^^^ LL | HastaLaVistaBaby, - | ^^^^^^^^^^^^^^^^ not covered + | ---------------- not covered = note: the matched value is of type `Terminator` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/error-codes/E0463.rs b/tests/ui/error-codes/E0463.rs deleted file mode 100644 index 683565281cf..00000000000 --- a/tests/ui/error-codes/E0463.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(plugin)] -#![plugin(cookie_monster)] -//~^ ERROR E0463 -extern crate cake_is_a_lie; - -fn main() { -} diff --git a/tests/ui/error-codes/E0463.stderr b/tests/ui/error-codes/E0463.stderr deleted file mode 100644 index 1aa66e1ec88..00000000000 --- a/tests/ui/error-codes/E0463.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0463]: can't find crate for `cookie_monster` - --> $DIR/E0463.rs:2:11 - | -LL | #![plugin(cookie_monster)] - | ^^^^^^^^^^^^^^ can't find crate - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0463`. diff --git a/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs index 9c685590b8b..5e64fd5d2af 100644 --- a/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs +++ b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs @@ -1,6 +1,6 @@ fn main() { let number = 2; - Some(true).filter({ //~ ERROR expected a `FnOnce<(&bool,)>` closure, found `bool` + Some(true).filter({ //~ ERROR expected a `FnOnce(&bool)` closure, found `bool` if number % 2 == 0 { number == 0 } else { diff --git a/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr index b72360562f2..f70b3211743 100644 --- a/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr +++ b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce<(&bool,)>` closure, found `bool` +error[E0277]: expected a `FnOnce(&bool)` closure, found `bool` --> $DIR/block_instead_of_closure_in_arg.rs:3:23 | LL | Some(true).filter({ @@ -12,7 +12,7 @@ LL | || number != 0 LL | || } | ||_________- this tail expression is of type `bool` LL | | }); - | |______^ expected an `FnOnce<(&bool,)>` closure, found `bool` + | |______^ expected an `FnOnce(&bool)` closure, found `bool` | = help: the trait `for<'a> FnOnce<(&'a bool,)>` is not implemented for `bool` note: required by a bound in `Option::<T>::filter` diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs index 982b9fd00f6..bb2e9c0a63c 100644 --- a/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs @@ -1,6 +1,6 @@ const x: usize =42; fn main() { - let p = Some(45).and_then({|x| //~ ERROR expected a `FnOnce<({integer},)>` closure, found `Option<usize>` + let p = Some(45).and_then({|x| //~ ERROR expected a `FnOnce({integer})` closure, found `Option<usize>` 1 + 1; Some(x * 2) }); diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr index 32d34430b7c..e44ec5ca93c 100644 --- a/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<usize>` +error[E0277]: expected a `FnOnce({integer})` closure, found `Option<usize>` --> $DIR/ruby_style_closure_successful_parse.rs:3:31 | LL | let p = Some(45).and_then({|x| @@ -9,7 +9,7 @@ LL | | 1 + 1; LL | | Some(x * 2) | | ----------- this tail expression is of type `Option<usize>` LL | | }); - | |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<usize>` + | |_____^ expected an `FnOnce({integer})` closure, found `Option<usize>` | = help: the trait `FnOnce<({integer},)>` is not implemented for `Option<usize>` note: required by a bound in `Option::<T>::and_then` diff --git a/tests/ui/extern/extern-wrong-value-type.rs b/tests/ui/extern/extern-wrong-value-type.rs index 337865ec18d..56c6cf1dfab 100644 --- a/tests/ui/extern/extern-wrong-value-type.rs +++ b/tests/ui/extern/extern-wrong-value-type.rs @@ -7,5 +7,5 @@ fn main() { // extern functions are extern "C" fn let _x: extern "C" fn() = f; // OK is_fn(f); - //~^ ERROR expected a `Fn<()>` closure, found `extern "C" fn() {f}` + //~^ ERROR expected a `Fn()` closure, found `extern "C" fn() {f}` } diff --git a/tests/ui/extern/extern-wrong-value-type.stderr b/tests/ui/extern/extern-wrong-value-type.stderr index ff2934a2ba8..463cee83169 100644 --- a/tests/ui/extern/extern-wrong-value-type.stderr +++ b/tests/ui/extern/extern-wrong-value-type.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() {f}` +error[E0277]: expected a `Fn()` closure, found `extern "C" fn() {f}` --> $DIR/extern-wrong-value-type.rs:9:11 | LL | is_fn(f); - | ----- ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` + | ----- ^ expected an `Fn()` closure, found `extern "C" fn() {f}` | | | required by a bound introduced by this call | diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index eb61c4cf159..8af0eedc82b 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -134,13 +134,13 @@ LL | match Foo::A { | ^^^^^^ pattern `Foo::C` not covered | note: `Foo` defined here - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:16:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:10 | LL | enum Foo { - | --- + | ^^^ ... LL | C, - | ^ not covered + | - not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/fn/fn-trait-formatting.rs b/tests/ui/fn/fn-trait-formatting.rs index 636ac7107e6..61a8791ab1f 100644 --- a/tests/ui/fn/fn-trait-formatting.rs +++ b/tests/ui/fn/fn-trait-formatting.rs @@ -17,5 +17,5 @@ fn main() { //~| found struct `Box<dyn FnMut() -> isize>` needs_fn(1); - //~^ ERROR expected a `Fn<(isize,)>` closure, found `{integer}` + //~^ ERROR expected a `Fn(isize)` closure, found `{integer}` } diff --git a/tests/ui/fn/fn-trait-formatting.stderr b/tests/ui/fn/fn-trait-formatting.stderr index 45d543bda53..c5e2f41691f 100644 --- a/tests/ui/fn/fn-trait-formatting.stderr +++ b/tests/ui/fn/fn-trait-formatting.stderr @@ -39,11 +39,11 @@ LL | let _: () = Box::new(|| -> isize { unimplemented!() }) as Box<dyn FnMut = note: expected unit type `()` found struct `Box<dyn FnMut() -> isize>` -error[E0277]: expected a `Fn<(isize,)>` closure, found `{integer}` +error[E0277]: expected a `Fn(isize)` closure, found `{integer}` --> $DIR/fn-trait-formatting.rs:19:14 | LL | needs_fn(1); - | -------- ^ expected an `Fn<(isize,)>` closure, found `{integer}` + | -------- ^ expected an `Fn(isize)` closure, found `{integer}` | | | required by a bound introduced by this call | diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs new file mode 100644 index 00000000000..7b168707239 --- /dev/null +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(associated_type_defaults)] + +trait Foo { + type Bar<T>: Baz<Self> = i32; + // We should be able to prove that `i32: Baz<Self>` because of + // the impl below, which requires that `Self::Bar<()>: Eq<i32>` + // which is true, because we assume `for<T> Self::Bar<T> = i32`. +} + +trait Baz<T: ?Sized> {} +impl<T: Foo + ?Sized> Baz<T> for i32 where T::Bar<()>: Eq<i32> {} + +trait Eq<T> {} +impl<T> Eq<T> for T {} + +fn main() {} diff --git a/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs index f5502adee42..c444ee9e1cd 100644 --- a/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs +++ b/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -10,7 +10,7 @@ trait Fun { impl<T> Fun for T { type F<'a> = Self; - //~^ ERROR expected a `Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn()` closure, found `T` } fn main() { diff --git a/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 07452137b5b..2376bda8190 100644 --- a/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `T` +error[E0277]: expected a `Fn()` closure, found `T` --> $DIR/issue-68642-broken-llvm-ir.rs:12:18 | LL | type F<'a> = Self; - | ^^^^ expected an `Fn<()>` closure, found `T` + | ^^^^ expected an `Fn()` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` diff --git a/tests/ui/generic-associated-types/issue-68643-broken-mir.rs b/tests/ui/generic-associated-types/issue-68643-broken-mir.rs index 6050a8bf561..39db51c0e2a 100644 --- a/tests/ui/generic-associated-types/issue-68643-broken-mir.rs +++ b/tests/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -10,7 +10,7 @@ trait Fun { impl<T> Fun for T { type F<'a> = Self; - //~^ ERROR expected a `Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn()` closure, found `T` } pub fn main() { diff --git a/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr b/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr index 31ded5dab95..2429531e4e5 100644 --- a/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `T` +error[E0277]: expected a `Fn()` closure, found `T` --> $DIR/issue-68643-broken-mir.rs:12:18 | LL | type F<'a> = Self; - | ^^^^ expected an `Fn<()>` closure, found `T` + | ^^^^ expected an `Fn()` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` diff --git a/tests/ui/generic-associated-types/issue-68644-codegen-selection.rs b/tests/ui/generic-associated-types/issue-68644-codegen-selection.rs index 898cfa1e744..e379bce07d3 100644 --- a/tests/ui/generic-associated-types/issue-68644-codegen-selection.rs +++ b/tests/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -10,7 +10,7 @@ trait Fun { impl<T> Fun for T { type F<'a> = Self; - //~^ ERROR expected a `Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn()` closure, found `T` } fn main() { diff --git a/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr index e2f9930cc67..11221353a92 100644 --- a/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `T` +error[E0277]: expected a `Fn()` closure, found `T` --> $DIR/issue-68644-codegen-selection.rs:12:18 | LL | type F<'a> = Self; - | ^^^^ expected an `Fn<()>` closure, found `T` + | ^^^^ expected an `Fn()` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` diff --git a/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs index 60b065bfc31..e69a08b0a39 100644 --- a/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs +++ b/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -10,7 +10,7 @@ trait Fun { impl<T> Fun for T { type F<'a> = Self; - //~^ ERROR expected a `Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn()` closure, found `T` } fn main() { diff --git a/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 0065368ad31..52300efc2d8 100644 --- a/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `T` +error[E0277]: expected a `Fn()` closure, found `T` --> $DIR/issue-68645-codegen-fulfillment.rs:12:18 | LL | type F<'a> = Self; - | ^^^^ expected an `Fn<()>` closure, found `T` + | ^^^^ expected an `Fn()` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr index 9af6bc45c7a..8ab88c58075 100644 --- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr +++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<(&'w (),)>` closure, found `fn(&'w ())` +error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())` --> $DIR/fn-ptr.rs:12:5 | LL | ice(); - | ^^^ expected an `Fn<(&'w (),)>` closure, found `fn(&'w ())` + | ^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())` | = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())` note: required by a bound in `ice` diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs index 853160f9612..adb19c035bc 100644 --- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs +++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs @@ -10,5 +10,5 @@ where fn main() { ice(); - //[classic]~^ ERROR expected a `Fn<(&'w (),)>` closure, found `fn(&'w ())` + //[classic]~^ ERROR expected a `Fn(&'w ())` closure, found `fn(&'w ())` } diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr index 2cc2bb2bbc3..7b0743cc7c5 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F` +error[E0277]: expected a `Fn(<_ as ATC<'a>>::Type)` closure, found `F` --> $DIR/issue-62529-3.rs:25:14 | LL | call(f, ()); - | ---- ^ expected an `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F` + | ---- ^ expected an `Fn(<_ as ATC<'a>>::Type)` closure, found `F` | | | required by a bound introduced by this call | diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index 1fd61084130..e0dc13c0c95 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/alloc/src/raw_vec.rs:535:5: +thread 'main' panicked at library/alloc/src/raw_vec.rs:545:5: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/impl-trait/in-trait/async-and-ret-ref.rs b/tests/ui/impl-trait/in-trait/async-and-ret-ref.rs new file mode 100644 index 00000000000..af6ffe83394 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/async-and-ret-ref.rs @@ -0,0 +1,11 @@ +// edition:2021 +// https://github.com/rust-lang/rust/issues/117547 + +trait T {} + +trait MyTrait { + async fn foo() -> &'static impl T; + //~^ ERROR the associated type `<Self as MyTrait>::{opaque#0}` may not live long enough +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr new file mode 100644 index 00000000000..7c9028a8cd5 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr @@ -0,0 +1,14 @@ +error[E0310]: the associated type `<Self as MyTrait>::{opaque#0}` may not live long enough + --> $DIR/async-and-ret-ref.rs:7:5 + | +LL | async fn foo() -> &'static impl T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `<Self as MyTrait>::{opaque#0}` must be valid for the static lifetime... + | ...so that the reference type `&'static impl T` does not outlive the data it points at + | + = help: consider adding an explicit lifetime bound `<Self as MyTrait>::{opaque#0}: 'static`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs new file mode 100644 index 00000000000..b97fd7d1ffe --- /dev/null +++ b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs @@ -0,0 +1,11 @@ +// check-pass + +use std::ops::Deref; + +trait Foo { + fn foo() -> impl Deref<Target = impl Deref<Target = impl Sized>> { + &&() + } +} + +fn main() {} diff --git a/tests/ui/implied-bounds/issue-100690.rs b/tests/ui/implied-bounds/issue-100690.rs index 5599cd410ba..ea33c9f423b 100644 --- a/tests/ui/implied-bounds/issue-100690.rs +++ b/tests/ui/implied-bounds/issue-100690.rs @@ -35,8 +35,8 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static, { real_dispatch(f) - //~^ ERROR expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` - //~| NOTE expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` + //~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` + //~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` //~| NOTE expected a closure with arguments //~| NOTE required by a bound introduced by this call } diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr index dba0353377f..ac9f7ab2529 100644 --- a/tests/ui/implied-bounds/issue-100690.stderr +++ b/tests/ui/implied-bounds/issue-100690.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` +error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` --> $DIR/issue-100690.rs:37:23 | LL | real_dispatch(f) - | ------------- ^ expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` + | ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` | | | required by a bound introduced by this call | diff --git a/tests/ui/intrinsics/const-eval-select-bad.rs b/tests/ui/intrinsics/const-eval-select-bad.rs index 991d1450aff..7e75de88d29 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.rs +++ b/tests/ui/intrinsics/const-eval-select-bad.rs @@ -8,8 +8,8 @@ const fn not_fn_items() { //~^ ERROR this argument must be a function item //~| ERROR this argument must be a function item const_eval_select((), 42, 0xDEADBEEF); - //~^ ERROR expected a `FnOnce<()>` closure - //~| ERROR expected a `FnOnce<()>` closure + //~^ ERROR expected a `FnOnce()` closure + //~| ERROR expected a `FnOnce()` closure //~| ERROR this argument must be a function item //~| ERROR this argument must be a function item } diff --git a/tests/ui/intrinsics/const-eval-select-bad.stderr b/tests/ui/intrinsics/const-eval-select-bad.stderr index ecd08e3cdfd..e6ff9d5a0df 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.stderr +++ b/tests/ui/intrinsics/const-eval-select-bad.stderr @@ -25,11 +25,11 @@ LL | const_eval_select((), 42, 0xDEADBEEF); = note: expected a function item, found {integer} = help: consult the documentation on `const_eval_select` for more information -error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` +error[E0277]: expected a `FnOnce()` closure, found `{integer}` --> $DIR/const-eval-select-bad.rs:10:27 | LL | const_eval_select((), 42, 0xDEADBEEF); - | ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}` + | ----------------- ^^ expected an `FnOnce()` closure, found `{integer}` | | | required by a bound introduced by this call | @@ -47,11 +47,11 @@ LL | const_eval_select((), 42, 0xDEADBEEF); = note: expected a function item, found {integer} = help: consult the documentation on `const_eval_select` for more information -error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` +error[E0277]: expected a `FnOnce()` closure, found `{integer}` --> $DIR/const-eval-select-bad.rs:10:31 | LL | const_eval_select((), 42, 0xDEADBEEF); - | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}` + | ----------------- ^^^^^^^^^^ expected an `FnOnce()` closure, found `{integer}` | | | required by a bound introduced by this call | diff --git a/tests/ui/invalid/invalid-plugin-attr.rs b/tests/ui/invalid/invalid-plugin-attr.rs deleted file mode 100644 index 3080af24500..00000000000 --- a/tests/ui/invalid/invalid-plugin-attr.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![deny(unused_attributes)] -#![feature(plugin)] - -#[plugin(bla)] //~ ERROR should be an inner attribute -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui/invalid/invalid-plugin-attr.stderr b/tests/ui/invalid/invalid-plugin-attr.stderr deleted file mode 100644 index d3882d33fc4..00000000000 --- a/tests/ui/invalid/invalid-plugin-attr.stderr +++ /dev/null @@ -1,22 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/invalid-plugin-attr.rs:4:1 - | -LL | #[plugin(bla)] - | ^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/invalid-plugin-attr.rs:4:1 - | -LL | #[plugin(bla)] - | ^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/invalid-plugin-attr.rs:1:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error; 1 warning emitted - diff --git a/tests/ui/issues/issue-22034.rs b/tests/ui/issues/issue-22034.rs index 405ffd089c2..ed741779f68 100644 --- a/tests/ui/issues/issue-22034.rs +++ b/tests/ui/issues/issue-22034.rs @@ -6,6 +6,6 @@ fn main() { let ptr: *mut () = core::ptr::null_mut(); let _: &mut dyn Fn() = unsafe { &mut *(ptr as *mut dyn Fn()) - //~^ ERROR expected a `Fn<()>` closure, found `()` + //~^ ERROR expected a `Fn()` closure, found `()` }; } diff --git a/tests/ui/issues/issue-22034.stderr b/tests/ui/issues/issue-22034.stderr index 9833e559cbc..d64b024098c 100644 --- a/tests/ui/issues/issue-22034.stderr +++ b/tests/ui/issues/issue-22034.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `()` +error[E0277]: expected a `Fn()` closure, found `()` --> $DIR/issue-22034.rs:8:16 | LL | &mut *(ptr as *mut dyn Fn()) - | ^^^ expected an `Fn<()>` closure, found `()` + | ^^^ expected an `Fn()` closure, found `()` | = help: the trait `Fn<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` diff --git a/tests/ui/issues/issue-23966.stderr b/tests/ui/issues/issue-23966.stderr index 8f934481d85..542aed0eb26 100644 --- a/tests/ui/issues/issue-23966.stderr +++ b/tests/ui/issues/issue-23966.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `FnMut<(_, char)>` closure, found `()` +error[E0277]: expected a `FnMut(_, char)` closure, found `()` --> $DIR/issue-23966.rs:2:32 | LL | "".chars().fold(|_, _| (), ()); - | ---- ^^ expected an `FnMut<(_, char)>` closure, found `()` + | ---- ^^ expected an `FnMut(_, char)` closure, found `()` | | | required by a bound introduced by this call | diff --git a/tests/ui/issues/issue-59494.rs b/tests/ui/issues/issue-59494.rs index a53e28f7246..8dcdd88c618 100644 --- a/tests/ui/issues/issue-59494.rs +++ b/tests/ui/issues/issue-59494.rs @@ -19,5 +19,5 @@ fn main() { let g = |(a, _)| a; let t7 = |env| |a| |b| t7p(f, g)(((env, a), b)); let t8 = t8n(t7, t7p(f, g)); - //~^ ERROR: expected a `Fn<(_,)>` closure, found `impl Fn(((_, _), _))` [E0277] + //~^ ERROR: expected a `Fn(_)` closure, found `impl Fn(((_, _), _))` [E0277] } diff --git a/tests/ui/issues/issue-59494.stderr b/tests/ui/issues/issue-59494.stderr index a9284535e4d..e9a4bf96741 100644 --- a/tests/ui/issues/issue-59494.stderr +++ b/tests/ui/issues/issue-59494.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<(_,)>` closure, found `impl Fn(((_, _), _))` +error[E0277]: expected a `Fn(_)` closure, found `impl Fn(((_, _), _))` --> $DIR/issue-59494.rs:21:22 | LL | let t8 = t8n(t7, t7p(f, g)); - | --- ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn(((_, _), _))` + | --- ^^^^^^^^^ expected an `Fn(_)` closure, found `impl Fn(((_, _), _))` | | | required by a bound introduced by this call | diff --git a/tests/ui/late-bound-lifetimes/predicate-is-global.rs b/tests/ui/late-bound-lifetimes/predicate-is-global.rs new file mode 100644 index 00000000000..ee4c4706005 --- /dev/null +++ b/tests/ui/late-bound-lifetimes/predicate-is-global.rs @@ -0,0 +1,32 @@ +// check-pass + +trait Foo { + type Assoc; + + fn do_it(_: &Self::Assoc) + where + for<'a> Self: Baz<'a>; +} + +trait Baz<'a>: Foo {} + +impl Foo for () { + type Assoc = Inherent; + + // Ensure that the `for<'a> Self: Baz<'a>` predicate, which has + // a supertrait `for<'a> Self: Foo`, does not cause us to fail + // to normalize `Self::Assoc`. + fn do_it(x: &Self::Assoc) + where + for<'a> Self: Baz<'a>, + { + x.inherent(); + } +} + +struct Inherent; +impl Inherent { + fn inherent(&self) {} +} + +fn main() {} diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs index 081e962028c..b0b6b318d8f 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs @@ -4,14 +4,14 @@ use std::future::Future; async fn wrapper<F>(f: F) -//~^ ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` -//~| ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` -//~| ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +//~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` +//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` +//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` where F:, for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, { - //~^ ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` + //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` let mut i = 41; &mut i; } diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr index 9d8c15d4a6a..5b77051dc88 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` --> $DIR/issue-76168-hr-outlives-3.rs:6:1 | LL | / async fn wrapper<F>(f: F) @@ -8,19 +8,19 @@ LL | | LL | | where LL | | F:, LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, - | |______________________________________________________________________________^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` -error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` --> $DIR/issue-76168-hr-outlives-3.rs:6:10 | LL | async fn wrapper<F>(f: F) - | ^^^^^^^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | ^^^^^^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` -error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` --> $DIR/issue-76168-hr-outlives-3.rs:13:1 | LL | / { @@ -28,11 +28,11 @@ LL | | LL | | let mut i = 41; LL | | &mut i; LL | | } - | |_^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | |_^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` -error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` --> $DIR/issue-76168-hr-outlives-3.rs:6:1 | LL | / async fn wrapper<F>(f: F) @@ -42,7 +42,7 @@ LL | | LL | | where LL | | F:, LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, - | |______________________________________________________________________________^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` diff --git a/tests/ui/malformed/malformed-plugin-1.rs b/tests/ui/malformed/malformed-plugin-1.rs deleted file mode 100644 index d4c1a2a1679..00000000000 --- a/tests/ui/malformed/malformed-plugin-1.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(plugin)] -#![plugin] //~ ERROR malformed `plugin` attribute -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui/malformed/malformed-plugin-1.stderr b/tests/ui/malformed/malformed-plugin-1.stderr deleted file mode 100644 index 505f6b6f140..00000000000 --- a/tests/ui/malformed/malformed-plugin-1.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: malformed `plugin` attribute input - --> $DIR/malformed-plugin-1.rs:2:1 - | -LL | #![plugin] - | ^^^^^^^^^^ help: must be of the form: `#![plugin(name)]` - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/malformed-plugin-1.rs:2:1 - | -LL | #![plugin] - | ^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - diff --git a/tests/ui/malformed/malformed-plugin-2.rs b/tests/ui/malformed/malformed-plugin-2.rs deleted file mode 100644 index ba80d97a3c2..00000000000 --- a/tests/ui/malformed/malformed-plugin-2.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(plugin)] -#![plugin="bleh"] //~ ERROR malformed `plugin` attribute -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui/malformed/malformed-plugin-2.stderr b/tests/ui/malformed/malformed-plugin-2.stderr deleted file mode 100644 index 52bbd82a389..00000000000 --- a/tests/ui/malformed/malformed-plugin-2.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: malformed `plugin` attribute input - --> $DIR/malformed-plugin-2.rs:2:1 - | -LL | #![plugin="bleh"] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![plugin(name)]` - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/malformed-plugin-2.rs:2:1 - | -LL | #![plugin="bleh"] - | ^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - diff --git a/tests/ui/malformed/malformed-plugin-3.rs b/tests/ui/malformed/malformed-plugin-3.rs deleted file mode 100644 index d2bd8f9f8dc..00000000000 --- a/tests/ui/malformed/malformed-plugin-3.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(plugin)] -#![plugin(foo="bleh")] //~ ERROR malformed `plugin` attribute -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/tests/ui/malformed/malformed-plugin-3.stderr b/tests/ui/malformed/malformed-plugin-3.stderr deleted file mode 100644 index 64cb429ea74..00000000000 --- a/tests/ui/malformed/malformed-plugin-3.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0498]: malformed `plugin` attribute - --> $DIR/malformed-plugin-3.rs:2:11 - | -LL | #![plugin(foo="bleh")] - | ^^^^^^^^^^ malformed attribute - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/malformed-plugin-3.rs:2:1 - | -LL | #![plugin(foo="bleh")] - | ^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0498`. diff --git a/tests/ui/match/match_non_exhaustive.stderr b/tests/ui/match/match_non_exhaustive.stderr index 7b8bdfe0053..40be39ec077 100644 --- a/tests/ui/match/match_non_exhaustive.stderr +++ b/tests/ui/match/match_non_exhaustive.stderr @@ -5,10 +5,10 @@ LL | match l { L::A => () }; | ^ pattern `L::B` not covered | note: `L` defined here - --> $DIR/match_non_exhaustive.rs:10:13 + --> $DIR/match_non_exhaustive.rs:10:6 | LL | enum L { A, B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `L` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/mir/addrof_alignment.rs b/tests/ui/mir/alignment/addrof_alignment.rs index 892638bfb92..f3423e97a8a 100644 --- a/tests/ui/mir/addrof_alignment.rs +++ b/tests/ui/mir/alignment/addrof_alignment.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-wasm32-bare: No panic messages // compile-flags: -C debug-assertions struct Misalignment { @@ -9,7 +8,7 @@ struct Misalignment { fn main() { let items: [Misalignment; 2] = [Misalignment { a: 0 }, Misalignment { a: 1 }]; unsafe { - let ptr: *const Misalignment = items.as_ptr().cast::<u8>().add(1).cast::<Misalignment>(); + let ptr: *const Misalignment = items.as_ptr().byte_add(1); let _ptr = core::ptr::addr_of!((*ptr).a); } } diff --git a/tests/ui/mir/mir_alignment_check_i686-pc-windows-msvc.rs b/tests/ui/mir/alignment/i686-pc-windows-msvc.rs index 56388c1047e..74ba1fde649 100644 --- a/tests/ui/mir/mir_alignment_check_i686-pc-windows-msvc.rs +++ b/tests/ui/mir/alignment/i686-pc-windows-msvc.rs @@ -11,9 +11,9 @@ fn main() { let mut x = [0u64; 2]; - let ptr: *mut u8 = x.as_mut_ptr().cast::<u8>(); + let ptr = x.as_mut_ptr(); unsafe { - let misaligned = ptr.add(4).cast::<u64>(); + let misaligned = ptr.byte_add(4); assert!(misaligned.addr() % 8 != 0); assert!(misaligned.addr() % 4 == 0); *misaligned = 42; diff --git a/tests/ui/mir/mir_alignment_check.rs b/tests/ui/mir/alignment/misaligned_lhs.rs index d1bf3d46a7c..97644ba8e09 100644 --- a/tests/ui/mir/mir_alignment_check.rs +++ b/tests/ui/mir/alignment/misaligned_lhs.rs @@ -6,8 +6,8 @@ fn main() { let mut x = [0u32; 2]; - let ptr: *mut u8 = x.as_mut_ptr().cast::<u8>(); + let ptr = x.as_mut_ptr(); unsafe { - *(ptr.add(1).cast::<u32>()) = 42; + *(ptr.byte_add(1)) = 42; } } diff --git a/tests/ui/mir/alignment/misaligned_rhs.rs b/tests/ui/mir/alignment/misaligned_rhs.rs new file mode 100644 index 00000000000..8534bc71a3a --- /dev/null +++ b/tests/ui/mir/alignment/misaligned_rhs.rs @@ -0,0 +1,13 @@ +// run-fail +// ignore-wasm32-bare: No panic messages +// ignore-i686-pc-windows-msvc: #112480 +// compile-flags: -C debug-assertions +// error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is + +fn main() { + let mut x = [0u32; 2]; + let ptr = x.as_mut_ptr(); + unsafe { + let _v = *(ptr.byte_add(1)); + } +} diff --git a/tests/ui/mir/alignment/packed.rs b/tests/ui/mir/alignment/packed.rs new file mode 100644 index 00000000000..754698591e3 --- /dev/null +++ b/tests/ui/mir/alignment/packed.rs @@ -0,0 +1,29 @@ +// run-pass +// compile-flags: -C debug-assertions + +#![feature(strict_provenance, pointer_is_aligned)] + +#[repr(packed)] +struct Misaligner { + _head: u8, + tail: u64, +} + +fn main() { + let memory = [Misaligner { _head: 0, tail: 0}, Misaligner { _head: 0, tail: 0}]; + // Test that we can use addr_of! to get the address of a packed member which according to its + // type is not aligned, but because it is a projection from a packed type is a valid place. + let ptr0 = std::ptr::addr_of!(memory[0].tail); + let ptr1 = std::ptr::addr_of!(memory[0].tail); + // Even if ptr0 happens to be aligned by chance, ptr1 is not. + assert!(!ptr0.is_aligned() || !ptr1.is_aligned()); + + // And also test that we can get the addr of a packed struct then do a member read from it. + unsafe { + let ptr = std::ptr::addr_of!(memory[0]); + let _tail = (*ptr).tail; + + let ptr = std::ptr::addr_of!(memory[1]); + let _tail = (*ptr).tail; + } +} diff --git a/tests/ui/mir/alignment/place_computation.rs b/tests/ui/mir/alignment/place_computation.rs new file mode 100644 index 00000000000..fdd4864250a --- /dev/null +++ b/tests/ui/mir/alignment/place_computation.rs @@ -0,0 +1,16 @@ +// run-pass +// compile-flags: -C debug-assertions + +#[repr(align(8))] +struct Misalignment { + a: u8, +} + +fn main() { + let mem = 0u64; + let ptr = &mem as *const u64 as *const Misalignment; + unsafe { + let ptr = ptr.byte_add(1); + let _ref: &u8 = &(*ptr).a; + } +} diff --git a/tests/ui/mir/alignment/place_without_read.rs b/tests/ui/mir/alignment/place_without_read.rs new file mode 100644 index 00000000000..b4be7a50f61 --- /dev/null +++ b/tests/ui/mir/alignment/place_without_read.rs @@ -0,0 +1,9 @@ +// run-pass +// compile-flags: -C debug-assertions + +fn main() { + let ptr = 1 as *const u16; + unsafe { + let _ = *ptr; + } +} diff --git a/tests/ui/mir/alignment/two_pointers.rs b/tests/ui/mir/alignment/two_pointers.rs new file mode 100644 index 00000000000..29af21dffc1 --- /dev/null +++ b/tests/ui/mir/alignment/two_pointers.rs @@ -0,0 +1,15 @@ +// run-fail +// ignore-wasm32-bare: No panic messages +// ignore-i686-pc-windows-msvc: #112480 +// compile-flags: -C debug-assertions +// error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is + +fn main() { + let x = [0u32; 2]; + let ptr = x.as_ptr(); + let mut dest = 0u32; + let dest_ptr = &mut dest as *mut u32; + unsafe { + *dest_ptr = *(ptr.byte_add(1)); + } +} diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs index ac0831ce655..42adff43a58 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs @@ -24,9 +24,9 @@ fn main() { let _ = produces_string().and_then(takes_str_but_too_many_refs); //~^ ERROR type mismatch in function arguments let _ = produces_string().and_then(takes_str_but_wrong_abi); - //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` + //~^ ERROR expected a `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` let _ = produces_string().and_then(takes_str_but_unsafe); - //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` + //~^ ERROR expected a `FnOnce(String)` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` let _ = produces_string().and_then(no_args); //~^ ERROR function is expected to take 1 argument, but it takes 0 arguments let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr index ecfbd27b180..3175a258906 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr @@ -14,11 +14,11 @@ LL | let _ = produces_string().and_then(takes_str_but_too_many_refs); note: required by a bound in `Option::<T>::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL -error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` +error[E0277]: expected a `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` --> $DIR/suggest-option-asderef-unfixable.rs:26:40 | LL | let _ = produces_string().and_then(takes_str_but_wrong_abi); - | -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` + | -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` | | | required by a bound introduced by this call | @@ -26,7 +26,7 @@ LL | let _ = produces_string().and_then(takes_str_but_wrong_abi); note: required by a bound in `Option::<T>::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL -error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` +error[E0277]: expected a `FnOnce(String)` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` --> $DIR/suggest-option-asderef-unfixable.rs:28:40 | LL | let _ = produces_string().and_then(takes_str_but_unsafe); diff --git a/tests/ui/pattern/issue-94866.stderr b/tests/ui/pattern/issue-94866.stderr index b3c17ce8974..dee4b3f557c 100644 --- a/tests/ui/pattern/issue-94866.stderr +++ b/tests/ui/pattern/issue-94866.stderr @@ -5,10 +5,10 @@ LL | match Enum::A { | ^^^^^^^ pattern `Enum::B` not covered | note: `Enum` defined here - --> $DIR/issue-94866.rs:7:16 + --> $DIR/issue-94866.rs:7:6 | LL | enum Enum { A, B } - | ---- ^ not covered + | ^^^^ - not covered = note: the matched value is of type `Enum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs new file mode 100644 index 00000000000..0b3e7ce9e9a --- /dev/null +++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs @@ -0,0 +1,24 @@ +#![feature(if_let_guard, let_chains)] + +fn main() { + let mut x = Some(String::new()); + let ref mut y @ ref mut z = x; + //~^ ERROR: mutable more than once + let Some(ref mut y @ ref mut z) = x else { return }; + //~^ ERROR: mutable more than once + if let Some(ref mut y @ ref mut z) = x {} + //~^ ERROR: mutable more than once + if let Some(ref mut y @ ref mut z) = x && true {} + //~^ ERROR: mutable more than once + while let Some(ref mut y @ ref mut z) = x {} + //~^ ERROR: mutable more than once + while let Some(ref mut y @ ref mut z) = x && true {} + //~^ ERROR: mutable more than once + match x { + ref mut y @ ref mut z => {} //~ ERROR: mutable more than once + } + match () { + () if let Some(ref mut y @ ref mut z) = x => {} //~ ERROR: mutable more than once + _ => {} + } +} diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr new file mode 100644 index 00000000000..679fc83e7f5 --- /dev/null +++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr @@ -0,0 +1,66 @@ +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:5:9 + | +LL | let ref mut y @ ref mut z = x; + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:7:14 + | +LL | let Some(ref mut y @ ref mut z) = x else { return }; + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:9:17 + | +LL | if let Some(ref mut y @ ref mut z) = x {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:11:17 + | +LL | if let Some(ref mut y @ ref mut z) = x && true {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:13:20 + | +LL | while let Some(ref mut y @ ref mut z) = x {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:15:20 + | +LL | while let Some(ref mut y @ ref mut z) = x && true {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:18:9 + | +LL | ref mut y @ ref mut z => {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:21:24 + | +LL | () if let Some(ref mut y @ ref mut z) = x => {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: aborting due to 8 previous errors + diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr index ff29de03d6b..24f3eaa5230 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr +++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr @@ -23,13 +23,13 @@ LL | match HiddenEnum::A { | ^^^^^^^^^^^^^ pattern `HiddenEnum::B` not covered | note: `HiddenEnum` defined here - --> $DIR/auxiliary/hidden.rs:3:5 + --> $DIR/auxiliary/hidden.rs:1:1 | LL | pub enum HiddenEnum { - | ------------------- + | ^^^^^^^^^^^^^^^^^^^ LL | A, LL | B, - | ^ not covered + | - not covered = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -44,13 +44,13 @@ LL | match HiddenEnum::A { | ^^^^^^^^^^^^^ patterns `HiddenEnum::B` and `_` not covered | note: `HiddenEnum` defined here - --> $DIR/auxiliary/hidden.rs:3:5 + --> $DIR/auxiliary/hidden.rs:1:1 | LL | pub enum HiddenEnum { - | ------------------- + | ^^^^^^^^^^^^^^^^^^^ LL | A, LL | B, - | ^ not covered + | - not covered = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -83,13 +83,13 @@ LL | match InCrate::A { | ^^^^^^^^^^ pattern `InCrate::C` not covered | note: `InCrate` defined here - --> $DIR/doc-hidden-non-exhaustive.rs:11:5 + --> $DIR/doc-hidden-non-exhaustive.rs:7:6 | LL | enum InCrate { - | ------- + | ^^^^^^^ ... LL | C, - | ^ not covered + | - not covered = note: the matched value is of type `InCrate` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index 5b81a8c3d3c..8f9bd5bde89 100644 --- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-match.rs:58:9 + --> $DIR/empty-match.rs:68:9 | LL | _ => {}, | ^ @@ -11,25 +11,25 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:61:9 + --> $DIR/empty-match.rs:71:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:68:9 + --> $DIR/empty-match.rs:78:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:71:9 + --> $DIR/empty-match.rs:81:9 | LL | _ if false => {}, | ^ error[E0005]: refutable pattern in local binding - --> $DIR/empty-match.rs:76:9 + --> $DIR/empty-match.rs:86:9 | LL | let None = x; | ^^^^ pattern `Some(_)` not covered @@ -44,19 +44,19 @@ LL | if let None = x { todo!() }; | ++ +++++++++++ error: unreachable pattern - --> $DIR/empty-match.rs:88:9 + --> $DIR/empty-match.rs:98:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:91:9 + --> $DIR/empty-match.rs:101:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:109:20 + --> $DIR/empty-match.rs:119:20 | LL | match_no_arms!(0u8); | ^^^ @@ -65,7 +65,7 @@ LL | match_no_arms!(0u8); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:111:20 + --> $DIR/empty-match.rs:121:20 | LL | match_no_arms!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | struct NonEmptyStruct1; = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:113:20 + --> $DIR/empty-match.rs:123:20 | LL | match_no_arms!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | struct NonEmptyStruct2(bool); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:115:20 + --> $DIR/empty-match.rs:125:20 | LL | match_no_arms!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | union NonEmptyUnion1 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:117:20 + --> $DIR/empty-match.rs:127:20 | LL | match_no_arms!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,42 +121,44 @@ LL | union NonEmptyUnion2 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:119:20 + --> $DIR/empty-match.rs:129:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:122:20 + --> $DIR/empty-match.rs:132:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:125:20 + --> $DIR/empty-match.rs:135:20 | LL | match_no_arms!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -166,11 +168,19 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:129:24 + --> $DIR/empty-match.rs:139:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -184,7 +194,7 @@ LL + _ => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:134:24 + --> $DIR/empty-match.rs:144:24 | LL | match_guarded_arm!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered @@ -203,7 +213,7 @@ LL + NonEmptyStruct1 => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:139:24 + --> $DIR/empty-match.rs:149:24 | LL | match_guarded_arm!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered @@ -222,7 +232,7 @@ LL + NonEmptyStruct2(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:144:24 + --> $DIR/empty-match.rs:154:24 | LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered @@ -241,7 +251,7 @@ LL + NonEmptyUnion1 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:149:24 + --> $DIR/empty-match.rs:159:24 | LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered @@ -260,18 +270,19 @@ LL + NonEmptyUnion2 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:154:24 + --> $DIR/empty-match.rs:164:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown @@ -281,21 +292,22 @@ LL + NonEmptyEnum1::Foo(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:159:24 + --> $DIR/empty-match.rs:169:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms @@ -305,7 +317,7 @@ LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:164:24 + --> $DIR/empty-match.rs:174:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -315,6 +327,14 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr index 6d17455086b..7f0389f40e2 100644 --- a/tests/ui/pattern/usefulness/empty-match.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-match.rs:58:9 + --> $DIR/empty-match.rs:68:9 | LL | _ => {}, | ^ @@ -11,25 +11,25 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:61:9 + --> $DIR/empty-match.rs:71:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:68:9 + --> $DIR/empty-match.rs:78:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:71:9 + --> $DIR/empty-match.rs:81:9 | LL | _ if false => {}, | ^ error[E0005]: refutable pattern in local binding - --> $DIR/empty-match.rs:76:9 + --> $DIR/empty-match.rs:86:9 | LL | let None = x; | ^^^^ pattern `Some(_)` not covered @@ -43,19 +43,19 @@ LL | if let None = x { todo!() }; | ++ +++++++++++ error: unreachable pattern - --> $DIR/empty-match.rs:88:9 + --> $DIR/empty-match.rs:98:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:91:9 + --> $DIR/empty-match.rs:101:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:109:20 + --> $DIR/empty-match.rs:119:20 | LL | match_no_arms!(0u8); | ^^^ @@ -64,7 +64,7 @@ LL | match_no_arms!(0u8); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:111:20 + --> $DIR/empty-match.rs:121:20 | LL | match_no_arms!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ @@ -78,7 +78,7 @@ LL | struct NonEmptyStruct1; = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:113:20 + --> $DIR/empty-match.rs:123:20 | LL | match_no_arms!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | struct NonEmptyStruct2(bool); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:115:20 + --> $DIR/empty-match.rs:125:20 | LL | match_no_arms!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | union NonEmptyUnion1 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:117:20 + --> $DIR/empty-match.rs:127:20 | LL | match_no_arms!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,42 +120,44 @@ LL | union NonEmptyUnion2 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:119:20 + --> $DIR/empty-match.rs:129:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:122:20 + --> $DIR/empty-match.rs:132:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:125:20 + --> $DIR/empty-match.rs:135:20 | LL | match_no_arms!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -165,11 +167,19 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:129:24 + --> $DIR/empty-match.rs:139:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -183,7 +193,7 @@ LL + _ => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:134:24 + --> $DIR/empty-match.rs:144:24 | LL | match_guarded_arm!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered @@ -202,7 +212,7 @@ LL + NonEmptyStruct1 => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:139:24 + --> $DIR/empty-match.rs:149:24 | LL | match_guarded_arm!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered @@ -221,7 +231,7 @@ LL + NonEmptyStruct2(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:144:24 + --> $DIR/empty-match.rs:154:24 | LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered @@ -240,7 +250,7 @@ LL + NonEmptyUnion1 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:149:24 + --> $DIR/empty-match.rs:159:24 | LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered @@ -259,18 +269,19 @@ LL + NonEmptyUnion2 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:154:24 + --> $DIR/empty-match.rs:164:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown @@ -280,21 +291,22 @@ LL + NonEmptyEnum1::Foo(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:159:24 + --> $DIR/empty-match.rs:169:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms @@ -304,7 +316,7 @@ LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:164:24 + --> $DIR/empty-match.rs:174:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -314,6 +326,14 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs index d56d2e3c817..fe5d0bce14f 100644 --- a/tests/ui/pattern/usefulness/empty-match.rs +++ b/tests/ui/pattern/usefulness/empty-match.rs @@ -30,17 +30,17 @@ union NonEmptyUnion2 { bar: (), } enum NonEmptyEnum1 { - Foo(bool), //~^ NOTE `NonEmptyEnum1` defined here //~| NOTE `NonEmptyEnum1` defined here - //~| NOTE not covered + Foo(bool), + //~^ NOTE not covered //~| NOTE not covered } enum NonEmptyEnum2 { - Foo(bool), //~^ NOTE `NonEmptyEnum2` defined here //~| NOTE `NonEmptyEnum2` defined here - //~| NOTE not covered + Foo(bool), + //~^ NOTE not covered //~| NOTE not covered Bar, //~^ NOTE not covered @@ -50,6 +50,16 @@ enum NonEmptyEnum5 { //~^ NOTE `NonEmptyEnum5` defined here //~| NOTE `NonEmptyEnum5` defined here V1, V2, V3, V4, V5, + //~^ NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered } fn empty_enum(x: EmptyEnum) { diff --git a/tests/ui/pattern/usefulness/issue-35609.stderr b/tests/ui/pattern/usefulness/issue-35609.stderr index 6d5e2f410bc..9feedfde469 100644 --- a/tests/ui/pattern/usefulness/issue-35609.stderr +++ b/tests/ui/pattern/usefulness/issue-35609.stderr @@ -107,6 +107,9 @@ LL | match Some(A) { | note: `Option<Enum>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered = note: the matched value is of type `Option<Enum>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/issue-39362.stderr b/tests/ui/pattern/usefulness/issue-39362.stderr index b8b17918aef..8dc53491606 100644 --- a/tests/ui/pattern/usefulness/issue-39362.stderr +++ b/tests/ui/pattern/usefulness/issue-39362.stderr @@ -5,12 +5,12 @@ LL | match f { | ^ patterns `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered | note: `Foo` defined here - --> $DIR/issue-39362.rs:2:5 + --> $DIR/issue-39362.rs:1:6 | LL | enum Foo { - | --- + | ^^^ LL | Bar { bar: Bar, id: usize } - | ^^^ not covered + | --- not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/issue-40221.stderr b/tests/ui/pattern/usefulness/issue-40221.stderr index 4973e42b054..40b42af26b3 100644 --- a/tests/ui/pattern/usefulness/issue-40221.stderr +++ b/tests/ui/pattern/usefulness/issue-40221.stderr @@ -5,12 +5,12 @@ LL | match proto { | ^^^^^ pattern `P::C(PC::QA)` not covered | note: `P` defined here - --> $DIR/issue-40221.rs:2:5 + --> $DIR/issue-40221.rs:1:6 | LL | enum P { - | - + | ^ LL | C(PC), - | ^ not covered + | - not covered = note: the matched value is of type `P` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/issue-56379.stderr b/tests/ui/pattern/usefulness/issue-56379.stderr index b3e40b99239..50e13bdfdfe 100644 --- a/tests/ui/pattern/usefulness/issue-56379.stderr +++ b/tests/ui/pattern/usefulness/issue-56379.stderr @@ -5,16 +5,16 @@ LL | match Foo::A(true) { | ^^^^^^^^^^^^ patterns `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered | note: `Foo` defined here - --> $DIR/issue-56379.rs:2:5 + --> $DIR/issue-56379.rs:1:6 | LL | enum Foo { - | --- + | ^^^ LL | A(bool), - | ^ not covered + | - not covered LL | B(bool), - | ^ not covered + | - not covered LL | C(bool), - | ^ not covered + | - not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs index 5145f769075..1d1ea8e4964 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs @@ -1,10 +1,15 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] // Test the "defined here" and "not covered" diagnostic hints. // We also make sure that references are peeled off from the scrutinee type // so that the diagnostics work better with default binding modes. #[derive(Clone)] enum E { - //~^ NOTE + //~^ NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE //~| NOTE //~| NOTE //~| NOTE @@ -12,10 +17,7 @@ enum E { //~| NOTE A, B, - //~^ NOTE `E` defined here - //~| NOTE `E` defined here - //~| NOTE `E` defined here - //~| NOTE not covered + //~^ NOTE not covered //~| NOTE not covered //~| NOTE not covered //~| NOTE not covered @@ -79,12 +81,12 @@ fn by_ref_thrice(e: & &mut &E) { } enum Opt { - //~^ NOTE + //~^ NOTE `Opt` defined here + //~| NOTE //~| NOTE Some(u8), None, - //~^ NOTE `Opt` defined here - //~| NOTE not covered + //~^ NOTE not covered //~| NOTE not covered } diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 8489e2f14b8..a9e55fa53a6 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -1,20 +1,20 @@ error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:35:11 + --> $DIR/non-exhaustive-defined-here.rs:37:11 | LL | match e1 { | ^^ patterns `E::B` and `E::C` not covered | note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { - | - + | ^ ... LL | B, - | ^ not covered + | - not covered ... LL | C - | ^ not covered + | - not covered = note: the matched value is of type `E` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -23,7 +23,7 @@ LL + E::B | E::C => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:41:9 + --> $DIR/non-exhaustive-defined-here.rs:43:9 | LL | let E::A = e; | ^^^^ patterns `E::B` and `E::C` not covered @@ -31,7 +31,7 @@ LL | let E::A = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:6:6 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { | ^ @@ -48,22 +48,22 @@ LL | if let E::A = e { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:50:11 + --> $DIR/non-exhaustive-defined-here.rs:52:11 | LL | match e { | ^ patterns `&E::B` and `&E::C` not covered | note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { - | - + | ^ ... LL | B, - | ^ not covered + | - not covered ... LL | C - | ^ not covered + | - not covered = note: the matched value is of type `&E` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -72,7 +72,7 @@ LL + &E::B | &E::C => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:57:9 + --> $DIR/non-exhaustive-defined-here.rs:59:9 | LL | let E::A = e; | ^^^^ patterns `&E::B` and `&E::C` not covered @@ -80,7 +80,7 @@ LL | let E::A = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:6:6 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { | ^ @@ -97,22 +97,22 @@ LL | if let E::A = e { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:66:11 + --> $DIR/non-exhaustive-defined-here.rs:68:11 | LL | match e { | ^ patterns `&&mut &E::B` and `&&mut &E::C` not covered | note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { - | - + | ^ ... LL | B, - | ^ not covered + | - not covered ... LL | C - | ^ not covered + | - not covered = note: the matched value is of type `&&mut &E` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -121,7 +121,7 @@ LL + &&mut &E::B | &&mut &E::C => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:73:9 + --> $DIR/non-exhaustive-defined-here.rs:75:9 | LL | let E::A = e; | ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered @@ -129,7 +129,7 @@ LL | let E::A = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:6:6 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { | ^ @@ -146,19 +146,19 @@ LL | if let E::A = e { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `Opt::None` not covered - --> $DIR/non-exhaustive-defined-here.rs:92:11 + --> $DIR/non-exhaustive-defined-here.rs:94:11 | LL | match e { | ^ pattern `Opt::None` not covered | note: `Opt` defined here - --> $DIR/non-exhaustive-defined-here.rs:85:5 + --> $DIR/non-exhaustive-defined-here.rs:83:6 | LL | enum Opt { - | --- + | ^^^ ... LL | None, - | ^^^^ not covered + | ---- not covered = note: the matched value is of type `Opt` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -167,7 +167,7 @@ LL + Opt::None => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:99:9 + --> $DIR/non-exhaustive-defined-here.rs:101:9 | LL | let Opt::Some(ref _x) = e; | ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered @@ -175,7 +175,7 @@ LL | let Opt::Some(ref _x) = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Opt` defined here - --> $DIR/non-exhaustive-defined-here.rs:81:6 + --> $DIR/non-exhaustive-defined-here.rs:83:6 | LL | enum Opt { | ^^^ diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr index 98e417a17f8..310049fe13e 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -18,10 +18,10 @@ LL | match x { | ^ pattern `T::A(U::C)` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match-nested.rs:1:10 + --> $DIR/non-exhaustive-match-nested.rs:1:6 | LL | enum T { A(U), B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr index e59e8885e1a..4bebd3cbbef 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -5,10 +5,10 @@ LL | match x { T::B => { } } | ^ pattern `T::A` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match.rs:3:10 + --> $DIR/non-exhaustive-match.rs:3:6 | LL | enum T { A, B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -79,10 +79,10 @@ LL | match T::A { | ^^^^ pattern `T::B` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match.rs:3:13 + --> $DIR/non-exhaustive-match.rs:3:6 | LL | enum T { A, B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr index f914b98d923..cceb1d8f65d 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr @@ -23,12 +23,12 @@ LL | match Color::Red { | ^^^^^^^^^^ pattern `Color::Red` not covered | note: `Color` defined here - --> $DIR/non-exhaustive-pattern-witness.rs:17:5 + --> $DIR/non-exhaustive-pattern-witness.rs:16:6 | LL | enum Color { - | ----- + | ^^^^^ LL | Red, - | ^^^ not covered + | --- not covered = note: the matched value is of type `Color` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -43,17 +43,17 @@ LL | match Direction::North { | ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered | note: `Direction` defined here - --> $DIR/non-exhaustive-pattern-witness.rs:32:5 + --> $DIR/non-exhaustive-pattern-witness.rs:30:6 | LL | enum Direction { - | --------- + | ^^^^^^^^^ LL | North, LL | East, - | ^^^^ not covered + | ---- not covered LL | South, - | ^^^^^ not covered + | ----- not covered LL | West, - | ^^^^ not covered + | ---- not covered = note: the matched value is of type `Direction` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -72,6 +72,17 @@ note: `ExcessiveEnum` defined here | LL | enum ExcessiveEnum { | ^^^^^^^^^^^^^ +LL | First, +LL | Second, + | ------ not covered +LL | Third, + | ----- not covered +LL | Fourth, + | ------ not covered +LL | Fifth, + | ----- not covered +LL | Sixth, + | ----- not covered = note: the matched value is of type `ExcessiveEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | @@ -86,13 +97,13 @@ LL | match Color::Red { | ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered | note: `Color` defined here - --> $DIR/non-exhaustive-pattern-witness.rs:19:5 + --> $DIR/non-exhaustive-pattern-witness.rs:16:6 | LL | enum Color { - | ----- + | ^^^^^ ... LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }, - | ^^^^^^^^^^ not covered + | ---------- not covered = note: the matched value is of type `Color` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr index f944c25a905..f75517fb791 100644 --- a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr +++ b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr @@ -5,13 +5,13 @@ LL | match UnstableEnum::Stable { | ^^^^^^^^^^^^^^^^^^^^ patterns `UnstableEnum::Stable2` and `_` not covered | note: `UnstableEnum` defined here - --> $DIR/auxiliary/unstable.rs:9:5 + --> $DIR/auxiliary/unstable.rs:5:1 | LL | pub enum UnstableEnum { - | --------------------- + | ^^^^^^^^^^^^^^^^^^^^^ ... LL | Stable2, - | ^^^^^^^ not covered + | ------- not covered = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr index 22425aa0dd4..3d2b540a9f5 100644 --- a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr +++ b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr @@ -5,12 +5,12 @@ LL | match x { | ^ pattern `A::B { x: Some(_) }` not covered | note: `A` defined here - --> $DIR/struct-like-enum-nonexhaustive.rs:2:5 + --> $DIR/struct-like-enum-nonexhaustive.rs:1:6 | LL | enum A { - | - + | ^ LL | B { x: Option<isize> }, - | ^ not covered + | - not covered = note: the matched value is of type `A` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr index d776249b231..4a4945156f7 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr +++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr @@ -5,13 +5,13 @@ LL | match UnstableEnum::Stable { | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered | note: `UnstableEnum` defined here - --> $DIR/auxiliary/unstable.rs:11:5 + --> $DIR/auxiliary/unstable.rs:5:1 | LL | pub enum UnstableEnum { - | --------------------- + | ^^^^^^^^^^^^^^^^^^^^^ ... LL | Unstable, - | ^^^^^^^^ not covered + | -------- not covered = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index de1bf8be885..7386f10a6fb 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -17,18 +17,18 @@ LL | match NonExhaustiveEnum::Unit {} | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered | note: `NonExhaustiveEnum` defined here - --> $DIR/enum_same_crate_empty_match.rs:5:5 + --> $DIR/enum_same_crate_empty_match.rs:4:10 | LL | pub enum NonExhaustiveEnum { - | ----------------- + | ^^^^^^^^^^^^^^^^^ LL | Unit, - | ^^^^ not covered + | ---- not covered LL | LL | Tuple(u32), - | ^^^^^ not covered + | ----- not covered LL | LL | Struct { field: u32 } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `NonExhaustiveEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -44,18 +44,18 @@ LL | match NormalEnum::Unit {} | ^^^^^^^^^^^^^^^^ patterns `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered | note: `NormalEnum` defined here - --> $DIR/enum_same_crate_empty_match.rs:14:5 + --> $DIR/enum_same_crate_empty_match.rs:13:10 | LL | pub enum NormalEnum { - | ---------- + | ^^^^^^^^^^ LL | Unit, - | ^^^^ not covered + | ---- not covered LL | LL | Tuple(u32), - | ^^^^^ not covered + | ----- not covered LL | LL | Struct { field: u32 } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `NormalEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr new file mode 100644 index 00000000000..9192c66143c --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.lint.stderr @@ -0,0 +1,75 @@ +error: some variants are not matched explicitly + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:15:11 + | +LL | match val { + | ^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:14:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:23:11 + | +LL | match val { + | ^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:22:27 + | +LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: the lint level must be set on the whole match + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:34:9 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ------------------------------- remove this attribute +LL | _ => {} + | ^ + | + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[deny(non_exhaustive_omitted_patterns)] +LL | match val { + | + +warning: the lint level must be set on the whole match + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:42:9 + | +LL | #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] + | ------------------------------- remove this attribute +LL | _ => {} + | ^ + | + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[deny(non_exhaustive_omitted_patterns)] +LL | match val { + | + +warning: the lint level must be set on the whole match + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:50:9 + | +LL | #[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))] + | ------------------------------- remove this attribute +LL | _ => {} + | ^ + | + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[warn(non_exhaustive_omitted_patterns)] +LL | match val { + | + +error: aborting due to 2 previous errors; 3 warnings emitted + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr new file mode 100644 index 00000000000..46093eb9fb3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.normal.stderr @@ -0,0 +1,31 @@ +error: some variants are not matched explicitly + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:15:11 + | +LL | match val { + | ^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:14:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: the lint level must be set on the whole match + --> $DIR/omitted-patterns-dont-lint-on-arm.rs:34:9 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ------------------------------- remove this attribute +LL | _ => {} + | ^ + | + = help: it no longer has any effect to set the lint level on an individual match arm +help: set the lint level on the whole match + | +LL + #[deny(non_exhaustive_omitted_patterns)] +LL | match val { + | + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs new file mode 100644 index 00000000000..33f9f56a5bb --- /dev/null +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns-dont-lint-on-arm.rs @@ -0,0 +1,53 @@ +// revisions: normal lint +// Test that putting the lint level on a match arm emits a warning, as this was previously +// meaningful and is no longer. +#![feature(non_exhaustive_omitted_patterns_lint)] + +// aux-build:enums.rs +extern crate enums; + +use enums::NonExhaustiveEnum; + +fn main() { + let val = NonExhaustiveEnum::Unit; + + #[deny(non_exhaustive_omitted_patterns)] + match val { + //~^ ERROR some variants are not matched explicitly + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } + + #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] + match val { + //[lint]~^ ERROR some variants are not matched explicitly + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } + + match val { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ WARN lint level must be set on the whole match + + match val { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + #[cfg_attr(lint, deny(non_exhaustive_omitted_patterns))] + _ => {} + } + //[lint]~^^ WARN lint level must be set on the whole match + + match val { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + #[cfg_attr(lint, warn(non_exhaustive_omitted_patterns))] + _ => {} + } + //[lint]~^^ WARN lint level must be set on the whole match +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr index a9c54af0418..c125756a646 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -62,14 +62,14 @@ LL | match x {} | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:17:23 + --> $DIR/auxiliary/uninhabited.rs:16:1 | LL | pub enum UninhabitedVariants { - | ---------------------------- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | #[non_exhaustive] Tuple(!), - | ^^^^^ not covered + | ----- not covered LL | #[non_exhaustive] Struct { x: ! } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr index ec2a2f6f055..7a12aca8520 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -43,14 +43,14 @@ LL | match x {} | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here - --> $DIR/match_same_crate.rs:16:23 + --> $DIR/match_same_crate.rs:15:10 | LL | pub enum UninhabitedVariants { - | ------------------- + | ^^^^^^^^^^^^^^^^^^^ LL | #[non_exhaustive] Tuple(!), - | ^^^^^ not covered + | ----- not covered LL | #[non_exhaustive] Struct { x: ! } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index b6b777ec56c..19e2546b0da 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -62,14 +62,14 @@ LL | match x {} | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:17:23 + --> $DIR/auxiliary/uninhabited.rs:16:1 | LL | pub enum UninhabitedVariants { - | ---------------------------- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | #[non_exhaustive] Tuple(!), - | ^^^^^ not covered + | ----- not covered LL | #[non_exhaustive] Struct { x: ! } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index 43bda49624e..1374ad935a3 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -21,14 +21,14 @@ fn call_once(f: impl FnOnce()) { } fn main() { - call(foo); //~ ERROR expected a `Fn<()>` closure, found `fn() {foo}` - call_mut(foo); //~ ERROR expected a `FnMut<()>` closure, found `fn() {foo}` - call_once(foo); //~ ERROR expected a `FnOnce<()>` closure, found `fn() {foo}` + call(foo); //~ ERROR expected a `Fn()` closure, found `fn() {foo}` + call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `fn() {foo}` + call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `fn() {foo}` call(foo_unsafe); - //~^ ERROR expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `Fn()` closure, found `unsafe fn() {foo_unsafe}` call_mut(foo_unsafe); - //~^ ERROR expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `FnMut()` closure, found `unsafe fn() {foo_unsafe}` call_once(foo_unsafe); - //~^ ERROR expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `FnOnce()` closure, found `unsafe fn() {foo_unsafe}` } diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index 4fb0d43d1b7..100f2048269 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}` +error[E0277]: expected a `Fn()` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:24:10 | LL | call(foo); - | ---- ^^^ expected an `Fn<()>` closure, found `fn() {foo}` + | ---- ^^^ expected an `Fn()` closure, found `fn() {foo}` | | | required by a bound introduced by this call | @@ -15,11 +15,11 @@ note: required by a bound in `call` LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` -error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}` +error[E0277]: expected a `FnMut()` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:25:14 | LL | call_mut(foo); - | -------- ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` + | -------- ^^^ expected an `FnMut()` closure, found `fn() {foo}` | | | required by a bound introduced by this call | @@ -32,11 +32,11 @@ note: required by a bound in `call_mut` LL | fn call_mut(f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` -error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}` +error[E0277]: expected a `FnOnce()` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:26:15 | LL | call_once(foo); - | --------- ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` + | --------- ^^^ expected an `FnOnce()` closure, found `fn() {foo}` | | | required by a bound introduced by this call | @@ -49,7 +49,7 @@ note: required by a bound in `call_once` LL | fn call_once(f: impl FnOnce()) { | ^^^^^^^^ required by this bound in `call_once` -error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `Fn()` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:28:10 | LL | call(foo_unsafe); @@ -67,7 +67,7 @@ note: required by a bound in `call` LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` -error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `FnMut()` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:30:14 | LL | call_mut(foo_unsafe); @@ -85,7 +85,7 @@ note: required by a bound in `call_mut` LL | fn call_mut(f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` -error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `FnOnce()` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:32:15 | LL | call_once(foo_unsafe); diff --git a/tests/ui/suggestions/issue-104961.fixed b/tests/ui/suggestions/issue-104961.fixed index 520d638b174..36917cf3395 100644 --- a/tests/ui/suggestions/issue-104961.fixed +++ b/tests/ui/suggestions/issue-104961.fixed @@ -2,12 +2,12 @@ fn foo(x: &str) -> bool { x.starts_with(&("hi".to_string() + " you")) - //~^ ERROR expected a `FnMut<(char,)>` closure, found `String` + //~^ ERROR expected a `FnMut(char)` closure, found `String` } fn foo2(x: &str) -> bool { x.starts_with(&"hi".to_string()) - //~^ ERROR expected a `FnMut<(char,)>` closure, found `String` + //~^ ERROR expected a `FnMut(char)` closure, found `String` } fn main() { diff --git a/tests/ui/suggestions/issue-104961.rs b/tests/ui/suggestions/issue-104961.rs index aeb787abb6f..25a8e0c45e8 100644 --- a/tests/ui/suggestions/issue-104961.rs +++ b/tests/ui/suggestions/issue-104961.rs @@ -2,12 +2,12 @@ fn foo(x: &str) -> bool { x.starts_with("hi".to_string() + " you") - //~^ ERROR expected a `FnMut<(char,)>` closure, found `String` + //~^ ERROR expected a `FnMut(char)` closure, found `String` } fn foo2(x: &str) -> bool { x.starts_with("hi".to_string()) - //~^ ERROR expected a `FnMut<(char,)>` closure, found `String` + //~^ ERROR expected a `FnMut(char)` closure, found `String` } fn main() { diff --git a/tests/ui/suggestions/issue-104961.stderr b/tests/ui/suggestions/issue-104961.stderr index 8cec6a3f827..7e795a74c90 100644 --- a/tests/ui/suggestions/issue-104961.stderr +++ b/tests/ui/suggestions/issue-104961.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnMut<(char,)>` closure, found `String` +error[E0277]: expected a `FnMut(char)` closure, found `String` --> $DIR/issue-104961.rs:4:19 | LL | x.starts_with("hi".to_string() + " you") @@ -15,7 +15,7 @@ help: consider borrowing here LL | x.starts_with(&("hi".to_string() + " you")) | ++ + -error[E0277]: expected a `FnMut<(char,)>` closure, found `String` +error[E0277]: expected a `FnMut(char)` closure, found `String` --> $DIR/issue-104961.rs:9:19 | LL | x.starts_with("hi".to_string()) diff --git a/tests/ui/suggestions/issue-62843.stderr b/tests/ui/suggestions/issue-62843.stderr index b6e271de807..ead8f18547b 100644 --- a/tests/ui/suggestions/issue-62843.stderr +++ b/tests/ui/suggestions/issue-62843.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnMut<(char,)>` closure, found `String` +error[E0277]: expected a `FnMut(char)` closure, found `String` --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); diff --git a/tests/ui/symbol-mangling-version/bad-value.bad.stderr b/tests/ui/symbol-mangling-version/bad-value.bad.stderr new file mode 100644 index 00000000000..c36c73c6069 --- /dev/null +++ b/tests/ui/symbol-mangling-version/bad-value.bad.stderr @@ -0,0 +1,2 @@ +error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected + diff --git a/tests/ui/symbol-mangling-version/bad-value.blank.stderr b/tests/ui/symbol-mangling-version/bad-value.blank.stderr new file mode 100644 index 00000000000..0e70af5b8ff --- /dev/null +++ b/tests/ui/symbol-mangling-version/bad-value.blank.stderr @@ -0,0 +1,2 @@ +error: incorrect value `` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected + diff --git a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr new file mode 100644 index 00000000000..77013b72b6c --- /dev/null +++ b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr @@ -0,0 +1,2 @@ +error: codegen option `symbol-mangling-version` requires either `legacy` or `v0` (RFC 2603) (C symbol-mangling-version=<value>) + diff --git a/tests/ui/symbol-mangling-version/bad-value.rs b/tests/ui/symbol-mangling-version/bad-value.rs new file mode 100644 index 00000000000..7623857d49e --- /dev/null +++ b/tests/ui/symbol-mangling-version/bad-value.rs @@ -0,0 +1,6 @@ +// revisions: no-value blank bad +// [no-value] compile-flags: -Csymbol-mangling-version +// [blank] compile-flags: -Csymbol-mangling-version= +// [bad] compile-flags: -Csymbol-mangling-version=bad-value + +fn main() {} diff --git a/tests/ui/symbol-mangling-version/stable.rs b/tests/ui/symbol-mangling-version/stable.rs new file mode 100644 index 00000000000..dac9bb18d1c --- /dev/null +++ b/tests/ui/symbol-mangling-version/stable.rs @@ -0,0 +1,5 @@ +// check-pass +// revisions: v0 +// [v0] compile-flags: -Csymbol-mangling-version=v0 + +fn main() {} diff --git a/tests/ui/symbol-mangling-version/unstable.legacy.stderr b/tests/ui/symbol-mangling-version/unstable.legacy.stderr new file mode 100644 index 00000000000..c5b359b41bd --- /dev/null +++ b/tests/ui/symbol-mangling-version/unstable.legacy.stderr @@ -0,0 +1,2 @@ +error: `-C symbol-mangling-version=legacy` requires `-Z unstable-options` + diff --git a/tests/ui/symbol-mangling-version/unstable.rs b/tests/ui/symbol-mangling-version/unstable.rs new file mode 100644 index 00000000000..df87a39cdfb --- /dev/null +++ b/tests/ui/symbol-mangling-version/unstable.rs @@ -0,0 +1,6 @@ +// revisions: legacy legacy-ok +// [legacy] compile-flags: -Csymbol-mangling-version=legacy +// [legacy-ok] check-pass +// [legacy-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=legacy + +fn main() {} diff --git a/tests/ui/trait-bounds/mismatch-fn-trait.stderr b/tests/ui/trait-bounds/mismatch-fn-trait.stderr index 961e6d88fbe..519aa9ea3f3 100644 --- a/tests/ui/trait-bounds/mismatch-fn-trait.stderr +++ b/tests/ui/trait-bounds/mismatch-fn-trait.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut(u32)` +error[E0277]: expected a `FnMut(i32)` closure, found `impl FnMut(u32)` --> $DIR/mismatch-fn-trait.rs:4:10 | LL | take(f) - | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut(u32)` + | ---- ^ expected an `FnMut(i32)` closure, found `impl FnMut(u32)` | | | required by a bound introduced by this call | @@ -14,11 +14,11 @@ note: required by a bound in `take` LL | fn take(_f: impl FnMut(i32)) {} | ^^^^^^^^^^ required by this bound in `take` -error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut(i32, i32)` +error[E0277]: expected a `FnMut(i32)` closure, found `impl FnMut(i32, i32)` --> $DIR/mismatch-fn-trait.rs:9:10 | LL | take(f) - | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut(i32, i32)` + | ---- ^ expected an `FnMut(i32)` closure, found `impl FnMut(i32, i32)` | | | required by a bound introduced by this call | @@ -29,11 +29,11 @@ note: required by a bound in `take` LL | fn take(_f: impl FnMut(i32)) {} | ^^^^^^^^^^ required by this bound in `take` -error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnMut()` +error[E0277]: expected a `FnMut(i32)` closure, found `impl FnMut()` --> $DIR/mismatch-fn-trait.rs:14:10 | LL | take(f) - | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnMut()` + | ---- ^ expected an `FnMut(i32)` closure, found `impl FnMut()` | | | required by a bound introduced by this call | @@ -44,11 +44,11 @@ note: required by a bound in `take` LL | fn take(_f: impl FnMut(i32)) {} | ^^^^^^^^^^ required by this bound in `take` -error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnOnce(i32)` +error[E0277]: expected a `FnMut(i32)` closure, found `impl FnOnce(i32)` --> $DIR/mismatch-fn-trait.rs:19:10 | LL | take(f) - | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnOnce(i32)` + | ---- ^ expected an `FnMut(i32)` closure, found `impl FnOnce(i32)` | | | required by a bound introduced by this call | @@ -59,11 +59,11 @@ note: required by a bound in `take` LL | fn take(_f: impl FnMut(i32)) {} | ^^^^^^^^^^ required by this bound in `take` -error[E0277]: expected a `FnMut<(i32,)>` closure, found `impl FnOnce(u32)` +error[E0277]: expected a `FnMut(i32)` closure, found `impl FnOnce(u32)` --> $DIR/mismatch-fn-trait.rs:24:10 | LL | take(f) - | ---- ^ expected an `FnMut<(i32,)>` closure, found `impl FnOnce(u32)` + | ---- ^ expected an `FnMut(i32)` closure, found `impl FnOnce(u32)` | | | required by a bound introduced by this call | diff --git a/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.fixed b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.fixed new file mode 100644 index 00000000000..b3f5ad52db5 --- /dev/null +++ b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.fixed @@ -0,0 +1,11 @@ +// run-rustfix +pub trait MyTrait { + type T; + + fn bar(self) -> Self::T; +} + +pub fn foo<A: MyTrait<T = B>, B>(a: A) -> B { + return a.bar(); //~ ERROR mismatched types +} +fn main() {} diff --git a/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.rs b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.rs new file mode 100644 index 00000000000..213abda7782 --- /dev/null +++ b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.rs @@ -0,0 +1,11 @@ +// run-rustfix +pub trait MyTrait { + type T; + + fn bar(self) -> Self::T; +} + +pub fn foo<A: MyTrait, B>(a: A) -> B { + return a.bar(); //~ ERROR mismatched types +} +fn main() {} diff --git a/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr new file mode 100644 index 00000000000..61132efc414 --- /dev/null +++ b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/restrict-assoc-type-of-generic-bound.rs:9:12 + | +LL | pub fn foo<A: MyTrait, B>(a: A) -> B { + | - - expected `B` because of return type + | | + | expected this type parameter +LL | return a.bar(); + | ^^^^^^^ expected type parameter `B`, found associated type + | + = note: expected type parameter `B` + found associated type `<A as MyTrait>::T` +help: consider further restricting this bound + | +LL | pub fn foo<A: MyTrait<T = B>, B>(a: A) -> B { + | +++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs index eb2fb6e841b..1359eb6cb87 100644 --- a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs +++ b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.rs @@ -11,5 +11,5 @@ fn f<T: for<'r> X<'r> + ?Sized>() { fn main() { f::<dyn for<'x> X<'x, F = i32>>(); - //~^ expected a `FnOnce<(&i32,)>` closure, found `i32` + //~^ expected a `FnOnce(&i32)` closure, found `i32` } diff --git a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr index 10e82c54e0f..68b9319d65c 100644 --- a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr +++ b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `FnOnce<(&i32,)>` closure, found `i32` +error[E0277]: expected a `FnOnce(&i32)` closure, found `i32` --> $DIR/check-trait-object-bounds-2.rs:13:9 | LL | f::<dyn for<'x> X<'x, F = i32>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&i32,)>` closure, found `i32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce(&i32)` closure, found `i32` | = help: the trait `for<'a> FnOnce<(&'a i32,)>` is not implemented for `i32` note: required by a bound in `f` diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs index f9a93476411..f8e3f8e968e 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs @@ -1,7 +1,7 @@ fn strip_lf(s: &str) -> &str { s.strip_suffix(b'\n').unwrap_or(s) - //~^ ERROR expected a `FnMut<(char,)>` closure, found `u8` - //~| NOTE expected an `FnMut<(char,)>` closure, found `u8` + //~^ ERROR expected a `FnMut(char)` closure, found `u8` + //~| NOTE expected an `FnMut(char)` closure, found `u8` //~| HELP the trait `FnMut<(char,)>` is not implemented for `u8` //~| HELP the following other types implement trait `Pattern<'a>`: //~| NOTE required for `u8` to implement `Pattern<'_>` diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index b1c683e4729..f30fe12b216 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `FnMut<(char,)>` closure, found `u8` +error[E0277]: expected a `FnMut(char)` closure, found `u8` --> $DIR/assoc-fn-bound-root-obligation.rs:2:7 | LL | s.strip_suffix(b'\n').unwrap_or(s) - | ^^^^^^^^^^^^ expected an `FnMut<(char,)>` closure, found `u8` + | ^^^^^^^^^^^^ expected an `FnMut(char)` closure, found `u8` | = help: the trait `FnMut<(char,)>` is not implemented for `u8` = help: the following other types implement trait `Pattern<'a>`: diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs index 0599e51d7ad..0a19e626553 100644 --- a/tests/ui/traits/new-solver/fn-trait.rs +++ b/tests/ui/traits/new-solver/fn-trait.rs @@ -18,15 +18,15 @@ fn main() { require_fn(f); require_fn(f as fn() -> i32); require_fn(f as unsafe fn() -> i32); - //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32` + //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32` //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32` require_fn(g); - //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32` require_fn(g as extern "C" fn() -> i32); - //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` + //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32` //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32` require_fn(h); - //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}` + //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32` } diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr index ff6903c5dbf..e33487235e6 100644 --- a/tests/ui/traits/new-solver/fn-trait.stderr +++ b/tests/ui/traits/new-solver/fn-trait.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32` +error[E0277]: expected a `Fn()` closure, found `unsafe fn() -> i32` --> $DIR/fn-trait.rs:20:16 | LL | require_fn(f as unsafe fn() -> i32); @@ -29,11 +29,11 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^ required by this bound in `require_fn` -error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` +error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` --> $DIR/fn-trait.rs:23:16 | LL | require_fn(g); - | ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + | ---------- ^ expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` | | | required by a bound introduced by this call | @@ -59,11 +59,11 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^ required by this bound in `require_fn` -error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` +error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32` --> $DIR/fn-trait.rs:26:16 | LL | require_fn(g as extern "C" fn() -> i32); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `extern "C" fn() -> i32` | | | required by a bound introduced by this call | @@ -89,7 +89,7 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^ required by this bound in `require_fn` -error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}` +error[E0277]: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` --> $DIR/fn-trait.rs:29:16 | LL | require_fn(h); diff --git a/tests/ui/traits/new-solver/specialization-transmute.rs b/tests/ui/traits/new-solver/specialization-transmute.rs index 7523b828321..f6b19e7adf5 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.rs +++ b/tests/ui/traits/new-solver/specialization-transmute.rs @@ -10,7 +10,7 @@ trait Default { } impl<T> Default for T { - default type Id = T; //~ ERROR: type annotations needed + default type Id = T; // This will be fixed by #111994 fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed self diff --git a/tests/ui/traits/new-solver/specialization-transmute.stderr b/tests/ui/traits/new-solver/specialization-transmute.stderr index 18965a465b3..09b1405fefb 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.stderr +++ b/tests/ui/traits/new-solver/specialization-transmute.stderr @@ -16,13 +16,6 @@ LL | fn intu(&self) -> &Self::Id { | = note: cannot satisfy `<T as Default>::Id == _` -error[E0282]: type annotations needed - --> $DIR/specialization-transmute.rs:13:23 - | -LL | default type Id = T; - | ^ cannot infer type for associated type `<T as Default>::Id` - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0282, E0284. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.rs b/tests/ui/traits/new-solver/specialization-unconstrained.rs index 7fd753109be..02150689ee5 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/new-solver/specialization-unconstrained.rs @@ -11,7 +11,7 @@ trait Default { } impl<T> Default for T { - default type Id = T; //~ ERROR type annotations needed + default type Id = T; } fn test<T: Default<Id = U>, U>() {} diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr index ed4dafa1484..910925cbaeb 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr @@ -20,13 +20,6 @@ note: required by a bound in `test` LL | fn test<T: Default<Id = U>, U>() {} | ^^^^^^ required by this bound in `test` -error[E0282]: type annotations needed - --> $DIR/specialization-unconstrained.rs:14:22 - | -LL | default type Id = T; - | ^ cannot infer type for associated type `<T as Default>::Id` - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0282, E0284. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed index 7a8433f9057..d03d733c76d 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.fixed +++ b/tests/ui/traits/suggest-dereferences/root-obligation.fixed @@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize { string .chars() .filter(|c| "aeiou".contains(*c)) - //~^ ERROR expected a `Fn<(char,)>` closure, found `char` + //~^ ERROR expected a `Fn(char)` closure, found `char` .count() } diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs index 51bac2107e3..9d9ffb3f55e 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.rs +++ b/tests/ui/traits/suggest-dereferences/root-obligation.rs @@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize { string .chars() .filter(|c| "aeiou".contains(c)) - //~^ ERROR expected a `Fn<(char,)>` closure, found `char` + //~^ ERROR expected a `Fn(char)` closure, found `char` .count() } diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index 1363fb8c47a..a19708e46bb 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<(char,)>` closure, found `char` +error[E0277]: expected a `Fn(char)` closure, found `char` --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) - | -------- ^ expected an `Fn<(char,)>` closure, found `char` + | -------- ^ expected an `Fn(char)` closure, found `char` | | | required by a bound introduced by this call | diff --git a/tests/ui/type-alias-impl-trait/issue-63279.rs b/tests/ui/type-alias-impl-trait/issue-63279.rs index 0e46745c65c..02f2111468a 100644 --- a/tests/ui/type-alias-impl-trait/issue-63279.rs +++ b/tests/ui/type-alias-impl-trait/issue-63279.rs @@ -3,11 +3,11 @@ type Closure = impl FnOnce(); fn c() -> Closure { - //~^ ERROR: expected a `FnOnce<()>` closure, found `()` + //~^ ERROR: expected a `FnOnce()` closure, found `()` || -> Closure { || () } //~^ ERROR: mismatched types //~| ERROR: mismatched types - //~| ERROR: expected a `FnOnce<()>` closure, found `()` + //~| ERROR: expected a `FnOnce()` closure, found `()` } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-63279.stderr b/tests/ui/type-alias-impl-trait/issue-63279.stderr index a868562479e..58cafd21ca8 100644 --- a/tests/ui/type-alias-impl-trait/issue-63279.stderr +++ b/tests/ui/type-alias-impl-trait/issue-63279.stderr @@ -1,17 +1,17 @@ -error[E0277]: expected a `FnOnce<()>` closure, found `()` +error[E0277]: expected a `FnOnce()` closure, found `()` --> $DIR/issue-63279.rs:5:11 | LL | fn c() -> Closure { - | ^^^^^^^ expected an `FnOnce<()>` closure, found `()` + | ^^^^^^^ expected an `FnOnce()` closure, found `()` | = help: the trait `FnOnce<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` -error[E0277]: expected a `FnOnce<()>` closure, found `()` +error[E0277]: expected a `FnOnce()` closure, found `()` --> $DIR/issue-63279.rs:7:11 | LL | || -> Closure { || () } - | ^^^^^^^ expected an `FnOnce<()>` closure, found `()` + | ^^^^^^^ expected an `FnOnce()` closure, found `()` | = help: the trait `FnOnce<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` diff --git a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr index 0ea1c1dcd5b..ce4d0fe25f5 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<(isize,)>` closure, found `S` +error[E0277]: expected a `Fn(isize)` closure, found `S` --> $DIR/unboxed-closures-fnmut-as-fn.rs:27:21 | LL | let x = call_it(&S, 22); - | ------- ^^ expected an `Fn<(isize,)>` closure, found `S` + | ------- ^^ expected an `Fn(isize)` closure, found `S` | | | required by a bound introduced by this call | diff --git a/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index 802696e1b2f..d836af2b014 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` +error[E0277]: expected a `Fn(&isize)` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 | LL | let x = call_it(&square, 22); @@ -14,7 +14,7 @@ note: required by a bound in `call_it` LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` -error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` +error[E0277]: expected a `FnMut(&isize)` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 | LL | let y = call_it_mut(&mut square, 22); @@ -30,7 +30,7 @@ note: required by a bound in `call_it_mut` LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` -error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` +error[E0277]: expected a `FnOnce(&isize)` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 | LL | let z = call_it_once(square, 22); diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr index 0bbb9836c58..c0dcf83a5bb 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -1,8 +1,8 @@ -error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` +error[E0277]: expected a `Fn(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:20:21 | LL | let x = call_it(&square, 22); - | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + | ------- ^^^^^^^ expected an `Fn(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` | | | required by a bound introduced by this call | @@ -13,11 +13,11 @@ note: required by a bound in `call_it` LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` -error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` +error[E0277]: expected a `FnMut(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:25:25 | LL | let y = call_it_mut(&mut square, 22); - | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + | ----------- ^^^^^^^^^^^ expected an `FnMut(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` | | | required by a bound introduced by this call | @@ -28,11 +28,11 @@ note: required by a bound in `call_it_mut` LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` -error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` +error[E0277]: expected a `FnOnce(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:30:26 | LL | let z = call_it_once(square, 22); - | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` + | ------------ ^^^^^^ expected an `FnOnce(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` | | | required by a bound introduced by this call | diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 31a66790ce0..d261c38f50c 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `Fn(&isize)` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 | LL | let x = call_it(&square, 22); @@ -14,7 +14,7 @@ note: required by a bound in `call_it` LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` -error[E0277]: expected a `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `FnMut(&isize)` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 | LL | let y = call_it_mut(&mut square, 22); @@ -30,7 +30,7 @@ note: required by a bound in `call_it_mut` LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` -error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `FnOnce(&isize)` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 | LL | let z = call_it_once(square, 22); diff --git a/tests/ui/unsafe/initializing-ranged-via-ctor.stderr b/tests/ui/unsafe/initializing-ranged-via-ctor.stderr index d34554c6641..13438fd31d0 100644 --- a/tests/ui/unsafe/initializing-ranged-via-ctor.stderr +++ b/tests/ui/unsafe/initializing-ranged-via-ctor.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce<({integer},)>` closure, found `unsafe fn(u8) -> NonZeroAndOneU8 {NonZeroAndOneU8}` +error[E0277]: expected a `FnOnce({integer})` closure, found `unsafe fn(u8) -> NonZeroAndOneU8 {NonZeroAndOneU8}` --> $DIR/initializing-ranged-via-ctor.rs:9:34 | LL | println!("{:?}", Some(1).map(NonZeroAndOneU8).unwrap()); diff --git a/tests/ui/unsized/unsize-coerce-multiple-adt-params.rs b/tests/ui/unsized/unsize-coerce-multiple-adt-params.rs new file mode 100644 index 00000000000..eba341ff284 --- /dev/null +++ b/tests/ui/unsized/unsize-coerce-multiple-adt-params.rs @@ -0,0 +1,29 @@ +// check-pass + +struct Foo<T, U> +where + (T, U): Trait, +{ + f: <(T, U) as Trait>::Assoc, +} + +trait Trait { + type Assoc: ?Sized; +} + +struct Count<const N: usize>; + +impl<const N: usize> Trait for (i32, Count<N>) { + type Assoc = [(); N]; +} + +impl<'a> Trait for (u32, ()) { + type Assoc = [()]; +} + +// Test that we can unsize several trait params in creative ways. +fn unsize<const N: usize>(x: &Foo<i32, Count<N>>) -> &Foo<u32, ()> { + x +} + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index d40ae9cb020..b846edca98b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -415,7 +415,7 @@ Issue #{number} "{title}" has been added. """ [no-merges] -exclude_titles = ["Rollup of", "subtree update"] +exclude_titles = ["Rollup of", "subtree update", "Subtree update"] labels = ["has-merge-commits", "S-waiting-on-author"] [github-releases] @@ -608,7 +608,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "jackh726", "WaffleLapkin"] +users_on_vacation = ["jyn514", "jackh726", "WaffleLapkin", "oli-obk"] [assign.adhoc_groups] compiler-team = [ |
