diff --git a/Cargo.lock b/Cargo.lock index 979198cece80..04bb96be369d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1859,7 +1859,6 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", - "rustc-rayon", "serde", ] @@ -3240,11 +3239,12 @@ dependencies = [ [[package]] name = "rustc-rayon" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710" +checksum = "2cd9fb077db982d7ceb42a90471e5a69a990b58f71e06f0d8340bb2cf35eb751" dependencies = [ "either", + "indexmap", "rustc-rayon-core", ] diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 90d12ea83285..475897d8f3e3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -310,7 +310,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); - type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?; + type_op_ascribe_user_type_with_span(&ocx, key, cause.span).ok()?; let diag = try_extract_error_from_fulfill_cx( &ocx, mbcx.mir_def_id(), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 91dc76f597ad..decfab502bb5 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1284,15 +1284,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ); } - &Rvalue::RawPtr(mutability, place) => { - let access_kind = match mutability { - Mutability::Mut => ( + &Rvalue::RawPtr(kind, place) => { + let access_kind = match kind { + RawPtrKind::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: MutBorrowKind::Default, })), ), - Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), + RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), + RawPtrKind::FakeForPtrMetadata => { + (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy)) + } }; self.access_place( diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index cbcfab1dc3e1..f79bcf5af556 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -3,11 +3,7 @@ use std::ops::ControlFlow; use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::bug; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ - self, BasicBlock, Body, BorrowKind, FakeBorrowKind, InlineAsmOperand, Location, Mutability, - NonDivergingIntrinsic, Operand, Place, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, -}; +use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::debug; @@ -60,7 +56,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { self.consume_operand(location, op); } - StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count, @@ -273,15 +269,18 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); } - &Rvalue::RawPtr(mutability, place) => { - let access_kind = match mutability { - Mutability::Mut => ( + &Rvalue::RawPtr(kind, place) => { + let access_kind = match kind { + RawPtrKind::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - kind: mir::MutBorrowKind::Default, + kind: MutBorrowKind::Default, })), ), - Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), + RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), + RawPtrKind::FakeForPtrMetadata => { + (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy)) + } }; self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e0196d55f20a..a2ef5588f48f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -349,8 +349,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let tcx = self.tcx(); let maybe_uneval = match constant.const_ { Const::Ty(_, ct) => match ct.kind() { - ty::ConstKind::Unevaluated(_) => { - bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) + ty::ConstKind::Unevaluated(uv) => { + Some(UnevaluatedConst { def: uv.def, args: uv.args, promoted: None }) } _ => None, }, diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 2c99597922e8..fdcd9caf4ac8 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -126,7 +126,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { &mut self, name: &str, params: Vec, - returns: Vec, + mut returns: Vec, args: &[Value], ) -> Cow<'_, [Value]> { // Pass i128 arguments by-ref on Windows. @@ -150,15 +150,19 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { (params, args.into()) }; - // Return i128 using a return area pointer on Windows and s390x. - let adjust_ret_param = - if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" { - returns.len() == 1 && returns[0].value_type == types::I128 - } else { - false - }; + let ret_single_i128 = returns.len() == 1 && returns[0].value_type == types::I128; + if ret_single_i128 && self.tcx.sess.target.is_like_windows { + // Return i128 using the vector ABI on Windows + returns[0].value_type = types::I64X2; - if adjust_ret_param { + let ret = self.lib_call_unadjusted(name, params, returns, &args)[0]; + + // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 + let ret_ptr = self.create_stack_slot(16, 16); + ret_ptr.store(self, ret, MemFlags::trusted()); + Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]) + } else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" { + // Return i128 using a return area pointer on s390x. let mut params = params; let mut args = args.to_vec(); diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs index 0b5cb1547fc6..4463631c524b 100644 --- a/compiler/rustc_codegen_cranelift/src/cast.rs +++ b/compiler/rustc_codegen_cranelift/src/cast.rs @@ -96,25 +96,9 @@ pub(crate) fn clif_int_or_float_cast( }, ); - if fx.tcx.sess.target.is_like_windows { - let ret = fx.lib_call( - &name, - vec![AbiParam::new(from_ty)], - vec![AbiParam::new(types::I64X2)], - &[from], - )[0]; - // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 - let ret_ptr = fx.create_stack_slot(16, 16); - ret_ptr.store(fx, ret, MemFlags::trusted()); - ret_ptr.load(fx, types::I128, MemFlags::trusted()) - } else { - fx.lib_call( - &name, - vec![AbiParam::new(from_ty)], - vec![AbiParam::new(types::I128)], - &[from], - )[0] - } + fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(types::I128)], &[ + from, + ])[0] } else if to_ty == types::I8 || to_ty == types::I16 { // FIXME implement fcvt_to_*int_sat.i8/i16 let val = if to_signed { diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index dcfd7ddabbc4..df5a79086fa3 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -33,28 +33,14 @@ pub(crate) fn maybe_codegen<'tcx>( (BinOp::Rem, true) => "__modti3", _ => unreachable!(), }; - if fx.tcx.sess.target.is_like_windows { - let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; - let ret = fx.lib_call( - name, - vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], - vec![AbiParam::new(types::I64X2)], - &args, - )[0]; - // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 - let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); - ret_place.to_ptr().store(fx, ret, MemFlags::trusted()); - Some(ret_place.to_cvalue(fx)) - } else { - let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; - let ret_val = fx.lib_call( - name, - vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], - vec![AbiParam::new(types::I128)], - &args, - )[0]; - Some(CValue::by_val(ret_val, lhs.layout())) - } + let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; + let ret_val = fx.lib_call( + name, + vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], + vec![AbiParam::new(types::I128)], + &args, + )[0]; + Some(CValue::by_val(ret_val, lhs.layout())) } BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None, BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e775d219c7b4..d7fc5e8e673f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -612,9 +612,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::CopyForDeref(place) => { self.codegen_operand(bx, &mir::Operand::Copy(place)) } - mir::Rvalue::RawPtr(mutability, place) => { - let mk_ptr = - move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability); + mir::Rvalue::RawPtr(kind, place) => { + let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { + Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy()) + }; self.codegen_place_to_pointer(bx, place, mk_ptr) } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 485c8696342a..d600d223bffd 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -403,7 +403,7 @@ const_eval_uninhabited_enum_variant_read = const_eval_uninhabited_enum_variant_written = writing discriminant of an uninhabited enum variant -const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable +const_eval_unmarked_const_item_exposed = `{$def_path}` cannot be (indirectly) exposed to stable .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval) @@ -414,6 +414,7 @@ const_eval_unreachable_unwind = const_eval_unsized_local = unsized locals are not supported const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn +const_eval_unstable_const_trait = `{$def_path}` is not yet stable as a const trait const_eval_unstable_in_stable_exposed = const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]` .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ed34996a7a7d..16ead1b97854 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -8,6 +8,7 @@ use std::ops::Deref; use rustc_attr_parsing::{ConstStability, StabilityLevel}; use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_index::bit_set::DenseBitSet; @@ -29,7 +30,7 @@ use super::ops::{self, NonConstOp, Status}; use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; -use crate::check_consts::is_safe_to_expose_on_stable_const_fn; +use crate::check_consts::is_fn_or_trait_safe_to_expose_on_stable; use crate::errors; type QualifResults<'mir, 'tcx, Q> = @@ -470,6 +471,88 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id)) }) } + + /// Check the const stability of the given item (fn or trait). + fn check_callee_stability(&mut self, def_id: DefId) { + match self.tcx.lookup_const_stability(def_id) { + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + // All good. + } + None => { + // This doesn't need a separate const-stability check -- const-stability equals + // regular stability, and regular stability is checked separately. + // However, we *do* have to worry about *recursive* const stability. + if self.enforce_recursive_const_stability() + && !is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id) + { + self.dcx().emit_err(errors::UnmarkedConstItemExposed { + span: self.span, + def_path: self.tcx.def_path_str(def_id), + }); + } + } + Some(ConstStability { + level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, + feature, + .. + }) => { + // An unstable const fn/trait with a feature gate. + let callee_safe_to_expose_on_stable = + is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id); + + // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if + // the callee is safe to expose, to avoid bypassing recursive stability. + // This is not ideal since it means the user sees an error, not the macro + // author, but that's also the case if one forgets to set + // `#[allow_internal_unstable]` in the first place. Note that this cannot be + // integrated in the check below since we want to enforce + // `callee_safe_to_expose_on_stable` even if + // `!self.enforce_recursive_const_stability()`. + if (self.span.allows_unstable(feature) + || implied_feature.is_some_and(|f| self.span.allows_unstable(f))) + && callee_safe_to_expose_on_stable + { + return; + } + + // We can't use `check_op` to check whether the feature is enabled because + // the logic is a bit different than elsewhere: local functions don't need + // the feature gate, and there might be an "implied" gate that also suffices + // to allow this. + let feature_enabled = def_id.is_local() + || self.tcx.features().enabled(feature) + || implied_feature.is_some_and(|f| self.tcx.features().enabled(f)) + || { + // When we're compiling the compiler itself we may pull in + // crates from crates.io, but those crates may depend on other + // crates also pulled in from crates.io. We want to ideally be + // able to compile everything without requiring upstream + // modifications, so in the case that this looks like a + // `rustc_private` crate (e.g., a compiler crate) and we also have + // the `-Z force-unstable-if-unmarked` flag present (we're + // compiling a compiler crate), then let this missing feature + // annotation slide. + // This matches what we do in `eval_stability_allow_unstable` for + // regular stability. + feature == sym::rustc_private + && issue == NonZero::new(27812) + && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked + }; + // Even if the feature is enabled, we still need check_op to double-check + // this if the callee is not safe to expose on stable. + if !feature_enabled || !callee_safe_to_expose_on_stable { + self.check_op(ops::CallUnstable { + def_id, + feature, + feature_enabled, + safe_to_expose_on_stable: callee_safe_to_expose_on_stable, + suggestion_span: self.crate_inject_span(), + is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait, + }); + } + } + } + } } impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { @@ -518,7 +601,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::Ref(_, BorrowKind::Mut { .. }, place) - | Rvalue::RawPtr(Mutability::Mut, place) => { + | Rvalue::RawPtr(RawPtrKind::Mut, place) => { // Inside mutable statics, we allow arbitrary mutable references. // We've allowed `static mut FOO = &mut [elements];` for a long time (the exact // reasons why are lost to history), and there is no reason to restrict that to @@ -536,7 +619,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place) - | Rvalue::RawPtr(Mutability::Not, place) => { + | Rvalue::RawPtr(RawPtrKind::Const, place) => { let borrowed_place_has_mut_interior = qualifs::in_place::( self.ccx, &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), @@ -548,6 +631,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } + Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => { + // These are only inserted for slice length, so the place must already be indirect. + // This implies we do not have to worry about whether the borrow escapes. + assert!(place.is_indirect(), "fake borrows are always indirect"); + } + Rvalue::Cast( CastKind::PointerCoercion( PointerCoercion::MutToConstPointer @@ -586,12 +675,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ) => {} Rvalue::ShallowInitBox(_, _) => {} - Rvalue::UnaryOp(_, operand) => { + Rvalue::UnaryOp(op, operand) => { let ty = operand.ty(self.body, self.tcx); - if is_int_bool_float_or_char(ty) { - // Int, bool, float, and char operations are fine. - } else { - span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); + match op { + UnOp::Not | UnOp::Neg => { + if is_int_bool_float_or_char(ty) { + // Int, bool, float, and char operations are fine. + } else { + span_bug!( + self.span, + "non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}", + ); + } + } + UnOp::PtrMetadata => { + // Getting the metadata from a pointer is always const. + // We already validated the type is valid in the validator. + } } } @@ -716,8 +816,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { span: *fn_span, call_source, }); - // FIXME(const_trait_impl): do a more fine-grained check whether this - // particular trait can be const-stably called. + self.check_callee_stability(trait_did); } else { // Not even a const trait. self.check_op(ops::FnCallNonConst { @@ -793,7 +892,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // fallback body is safe to expose on stable. let is_const_stable = intrinsic.const_stable || (!intrinsic.must_be_overridden - && is_safe_to_expose_on_stable_const_fn(tcx, callee)); + && is_fn_or_trait_safe_to_expose_on_stable(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { // This doesn't need a separate const-stability check -- const-stability equals @@ -842,83 +941,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } // Finally, stability for regular function calls -- this is the big one. - match tcx.lookup_const_stability(callee) { - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { - // All good. - } - None => { - // This doesn't need a separate const-stability check -- const-stability equals - // regular stability, and regular stability is checked separately. - // However, we *do* have to worry about *recursive* const stability. - if self.enforce_recursive_const_stability() - && !is_safe_to_expose_on_stable_const_fn(tcx, callee) - { - self.dcx().emit_err(errors::UnmarkedConstFnExposed { - span: self.span, - def_path: self.tcx.def_path_str(callee), - }); - } - } - Some(ConstStability { - level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, - feature, - .. - }) => { - // An unstable const fn with a feature gate. - let callee_safe_to_expose_on_stable = - is_safe_to_expose_on_stable_const_fn(tcx, callee); - - // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if - // the callee is safe to expose, to avoid bypassing recursive stability. - // This is not ideal since it means the user sees an error, not the macro - // author, but that's also the case if one forgets to set - // `#[allow_internal_unstable]` in the first place. Note that this cannot be - // integrated in the check below since we want to enforce - // `callee_safe_to_expose_on_stable` even if - // `!self.enforce_recursive_const_stability()`. - if (self.span.allows_unstable(feature) - || implied_feature.is_some_and(|f| self.span.allows_unstable(f))) - && callee_safe_to_expose_on_stable - { - return; - } - - // We can't use `check_op` to check whether the feature is enabled because - // the logic is a bit different than elsewhere: local functions don't need - // the feature gate, and there might be an "implied" gate that also suffices - // to allow this. - let feature_enabled = callee.is_local() - || tcx.features().enabled(feature) - || implied_feature.is_some_and(|f| tcx.features().enabled(f)) - || { - // When we're compiling the compiler itself we may pull in - // crates from crates.io, but those crates may depend on other - // crates also pulled in from crates.io. We want to ideally be - // able to compile everything without requiring upstream - // modifications, so in the case that this looks like a - // `rustc_private` crate (e.g., a compiler crate) and we also have - // the `-Z force-unstable-if-unmarked` flag present (we're - // compiling a compiler crate), then let this missing feature - // annotation slide. - // This matches what we do in `eval_stability_allow_unstable` for - // regular stability. - feature == sym::rustc_private - && issue == NonZero::new(27812) - && tcx.sess.opts.unstable_opts.force_unstable_if_unmarked - }; - // Even if the feature is enabled, we still need check_op to double-check - // this if the callee is not safe to expose on stable. - if !feature_enabled || !callee_safe_to_expose_on_stable { - self.check_op(ops::FnCallUnstable { - def_id: callee, - feature, - feature_enabled, - safe_to_expose_on_stable: callee_safe_to_expose_on_stable, - suggestion_span: self.crate_inject_span(), - }); - } - } - } + self.check_callee_stability(callee); } // Forbid all `Drop` terminators unless the place being dropped is a local with no diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index ab68691f1b97..bfa0a0319c34 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -56,7 +56,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { self.const_kind == Some(hir::ConstContext::ConstFn) && (self.tcx.features().staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked) - && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id()) + && is_fn_or_trait_safe_to_expose_on_stable(self.tcx, self.def_id().to_def_id()) } fn is_async(&self) -> bool { @@ -84,28 +84,14 @@ pub fn rustc_allow_const_fn_unstable( attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) } -/// Returns `true` if the given `const fn` is "safe to expose on stable". -/// -/// Panics if the given `DefId` does not refer to a `const fn`. +/// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable". /// /// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable /// const features *recursively* taints the functions that use them. This is to avoid accidentally /// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the /// world into two functions: those that are safe to expose on stable (and hence may not use /// unstable features, not even recursively), and those that are not. -pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is not const-stable because const trait fns currently - // cannot be const-stable. These functions can't be called from anything stable, so we shouldn't - // restrict them to only call const-stable functions. - if tcx.is_const_default_method(def_id) { - // FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable. - // They should probably behave like regular `const fn` for that... - return false; - } - - // Const-stability is only relevant for `const fn`. - assert!(tcx.is_const_fn(def_id)); - +pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { match tcx.lookup_const_stability(def_id) { None => { // In a `staged_api` crate, we do enforce recursive const stability for all unmarked diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 3c83a7b92cdc..7756e51c4c5f 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -377,11 +377,11 @@ fn build_error_for_const_call<'tcx>( err } -/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. +/// A call to an `#[unstable]` const fn, `#[rustc_const_unstable]` function or trait. /// -/// Contains the name of the feature that would allow the use of this function. +/// Contains the name of the feature that would allow the use of this function/trait. #[derive(Debug)] -pub(crate) struct FnCallUnstable { +pub(crate) struct CallUnstable { pub def_id: DefId, pub feature: Symbol, /// If this is true, then the feature is enabled, but we need to still check if it is safe to @@ -389,24 +389,33 @@ pub(crate) struct FnCallUnstable { pub feature_enabled: bool, pub safe_to_expose_on_stable: bool, pub suggestion_span: Option, + /// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait. + pub is_function_call: bool, } -impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { +impl<'tcx> NonConstOp<'tcx> for CallUnstable { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable { gate: self.feature, gate_already_checked: self.feature_enabled, safe_to_expose_on_stable: self.safe_to_expose_on_stable, - is_function_call: true, + is_function_call: self.is_function_call, } } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { assert!(!self.feature_enabled); - let mut err = ccx.dcx().create_err(errors::UnstableConstFn { - span, - def_path: ccx.tcx.def_path_str(self.def_id), - }); + let mut err = if self.is_function_call { + ccx.dcx().create_err(errors::UnstableConstFn { + span, + def_path: ccx.tcx.def_path_str(self.def_id), + }) + } else { + ccx.dcx().create_err(errors::UnstableConstTrait { + span, + def_path: ccx.tcx.def_path_str(self.def_id), + }) + }; // FIXME: make this translatable let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature); #[allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 1ee9214c4b2a..a2635885098e 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -121,6 +121,14 @@ pub(crate) struct UnstableConstFn { pub def_path: String, } +#[derive(Diagnostic)] +#[diag(const_eval_unstable_const_trait)] +pub(crate) struct UnstableConstTrait { + #[primary_span] + pub span: Span, + pub def_path: String, +} + #[derive(Diagnostic)] #[diag(const_eval_unstable_intrinsic)] pub(crate) struct UnstableIntrinsic { @@ -139,9 +147,9 @@ pub(crate) struct UnstableIntrinsic { } #[derive(Diagnostic)] -#[diag(const_eval_unmarked_const_fn_exposed)] +#[diag(const_eval_unmarked_const_item_exposed)] #[help] -pub(crate) struct UnmarkedConstFnExposed { +pub(crate) struct UnmarkedConstItemExposed { #[primary_span] pub span: Span, pub def_path: String, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index b61865be6678..d9c0ff5acd11 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -237,7 +237,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_immediate(*val, &dest)?; } - RawPtr(_, place) => { + RawPtr(kind, place) => { // Figure out whether this is an addr_of of an already raw place. let place_base_raw = if place.is_indirect_first_projection() { let ty = self.frame().body.local_decls[place.local].ty; @@ -250,8 +250,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let src = self.eval_place(place)?; let place = self.force_allocation(&src)?; let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); - if !place_base_raw { - // If this was not already raw, it needs retagging. + if !place_base_raw && !kind.is_fake() { + // If this was not already raw, it needs retagging -- except for "fake" + // raw borrows whose defining property is that they do not get retagged. val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?; } self.write_immediate(*val, &dest)?; diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 889a8299c18f..8e5af33d8b67 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -10,11 +10,11 @@ bitflags = "2.4.1" either = "1.0" elsa = "=1.7.1" ena = "0.14.3" -indexmap = { version = "2.4.0", features = ["rustc-rayon"] } +indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "11" rustc-hash = "2.0.0" -rustc-rayon = "0.5.0" +rustc-rayon = { version = "0.5.1", features = ["indexmap"] } rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b8652d82d91b..4dcc83d0aefb 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -296,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Given the expected type, figures out what it can about this closure we /// are about to type check: - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn deduce_closure_signature( &self, expected_ty: Ty<'tcx>, @@ -378,6 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_predicate.rebind(proj_predicate), ), ); + // Make sure that we didn't infer a signature that mentions itself. // This can happen when we elaborate certain supertrait bounds that // mention projections containing the `Self` type. See #105401. @@ -395,8 +396,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { - expected_sig = inferred_sig; + + // Don't infer a closure signature from a goal that names the closure type as this will + // (almost always) lead to occurs check errors later in type checking. + if self.next_trait_solver() + && let Some(inferred_sig) = inferred_sig + { + // In the new solver it is difficult to explicitly normalize the inferred signature as we + // would have to manually handle universes and rewriting bound vars and placeholders back + // and forth. + // + // Instead we take advantage of the fact that we relating an inference variable with an alias + // will only instantiate the variable if the alias is rigid(*not quite). Concretely we: + // - Create some new variable `?sig` + // - Equate `?sig` with the unnormalized signature, e.g. `fn( as Trait>::Assoc)` + // - Depending on whether ` as Trait>::Assoc` is rigid, ambiguous or normalizeable, + // we will either wind up with `?sig= as Trait>::Assoc/?y/ConcreteTy` respectively. + // + // *: In cases where there are ambiguous aliases in the signature that make use of bound vars + // they will wind up present in `?sig` even though they are non-rigid. + // + // This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty` + // even though the normalized form may not name `expected_ty`. However, this matches the existing + // behaviour of the old solver and would be technically a breaking change to fix. + let generalized_fnptr_sig = self.next_ty_var(span); + let inferred_fnptr_sig = Ty::new_fn_ptr(self.tcx, inferred_sig.sig); + self.demand_eqtype(span, inferred_fnptr_sig, generalized_fnptr_sig); + + let resolved_sig = self.resolve_vars_if_possible(generalized_fnptr_sig); + + if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { + expected_sig = Some(ExpectedSig { + cause_span: inferred_sig.cause_span, + sig: resolved_sig.fn_sig(self.tcx), + }); + } + } else { + if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { + expected_sig = inferred_sig; + } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index eb5fe3a86e4c..dc10b53fd839 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -7,6 +7,7 @@ use rustc_span::Span; use rustc_trait_selection::solve::inspect::{ InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor, }; +use rustc_type_ir::solve::GoalSource; use tracing::{debug, instrument, trace}; use crate::FnCtxt; @@ -119,7 +120,21 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { let tcx = self.fcx.tcx; let goal = inspect_goal.goal(); - if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) { + if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) + // We do not push the instantiated forms of goals as it would cause any + // aliases referencing bound vars to go from having escaping bound vars to + // being able to be normalized to an inference variable. + // + // This is mostly just a hack as arbitrary nested goals could still contain + // such aliases while having a different `GoalSource`. Closure signature inference + // however can't really handle *every* higher ranked `Fn` goal also being present + // in the form of `?c: Fn<(>::Assoc)`. + // + // This also just better matches the behaviour of the old solver where we do not + // encounter instantiated forms of goals, only nested goals that referred to bound + // vars from instantiated goals. + && !matches!(inspect_goal.source(), GoalSource::InstantiateHigherRanked) + { self.obligations_for_self_ty.push(traits::Obligation::new( tcx, self.root_cause.clone(), diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 74d02ac22276..9495030f124b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -797,7 +797,6 @@ fn test_unstable_options_tracking_hash() { tracked!(function_sections, Some(false)); tracked!(human_readable_cgu_names, true); tracked!(incremental_ignore_spans, true); - tracked!(inline_in_all_cgus, Some(true)); tracked!(inline_mir, Some(true)); tracked!(inline_mir_hint_threshold, Some(123)); tracked!(inline_mir_threshold, Some(123)); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 3eccf56d8c4d..6fa3fa2432de 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -91,13 +91,8 @@ impl<'tcx> MonoItem<'tcx> { } pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let generate_cgu_internal_copies = tcx - .sess - .opts - .unstable_opts - .inline_in_all_cgus - .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.link_dead_code(); + let generate_cgu_internal_copies = + (tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code(); match *self { MonoItem::Fn(ref instance) => { @@ -121,8 +116,8 @@ impl<'tcx> MonoItem<'tcx> { } // At this point we don't have explicit linkage and we're an - // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU. + // inlined function. If this crate's build settings permit, + // we'll be creating a local copy per CGU. if generate_cgu_internal_copies { return InstantiationMode::LocalCopy; } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 29ae2e1bd6bc..5868b64f6b5c 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -180,6 +180,59 @@ pub enum BorrowKind { Mut { kind: MutBorrowKind }, } +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum RawPtrKind { + Mut, + Const, + /// Creates a raw pointer to a place that will only be used to access its metadata, + /// not the data behind the pointer. Note that this limitation is *not* enforced + /// by the validator. + /// + /// The borrow checker allows overlap of these raw pointers with references to the + /// data. This is sound even if the pointer is "misused" since any such use is anyway + /// unsafe. In terms of the operational semantics (i.e., Miri), this is equivalent + /// to `RawPtrKind::Mut`, but will never incur a retag. + FakeForPtrMetadata, +} + +impl From for RawPtrKind { + fn from(other: Mutability) -> Self { + match other { + Mutability::Mut => RawPtrKind::Mut, + Mutability::Not => RawPtrKind::Const, + } + } +} + +impl RawPtrKind { + pub fn is_fake(self) -> bool { + match self { + RawPtrKind::Mut | RawPtrKind::Const => false, + RawPtrKind::FakeForPtrMetadata => true, + } + } + + pub fn to_mutbl_lossy(self) -> Mutability { + match self { + RawPtrKind::Mut => Mutability::Mut, + RawPtrKind::Const => Mutability::Not, + + // We have no type corresponding to a fake borrow, so use + // `*const` as an approximation. + RawPtrKind::FakeForPtrMetadata => Mutability::Not, + } + } + + pub fn ptr_str(self) -> &'static str { + match self { + RawPtrKind::Mut => "mut", + RawPtrKind::Const => "const", + RawPtrKind::FakeForPtrMetadata => "const (fake)", + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] pub enum MutBorrowKind { @@ -1356,7 +1409,7 @@ pub enum Rvalue<'tcx> { /// /// Like with references, the semantics of this operation are heavily dependent on the aliasing /// model. - RawPtr(Mutability, Place<'tcx>), + RawPtr(RawPtrKind, Place<'tcx>), /// Yields the length of the place, as a `usize`. /// diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index db77017310af..4d11492e94d3 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -206,9 +206,9 @@ impl<'tcx> Rvalue<'tcx> { let place_ty = place.ty(local_decls, tcx).ty; Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy()) } - Rvalue::RawPtr(mutability, ref place) => { + Rvalue::RawPtr(kind, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; - Ty::new_ptr(tcx, place_ty, mutability) + Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy()) } Rvalue::Len(..) => tcx.types.usize, Rvalue::Cast(.., ty) => ty, diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index b798f0788007..b59b9e55fe8a 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -15,6 +15,7 @@ TrivialTypeTraversalImpls! { SourceScopeLocalData, UserTypeAnnotationIndex, BorrowKind, + RawPtrKind, CastKind, BasicBlock, SwitchTargets, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 058acbd4024d..95de08ce9c87 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -685,12 +685,15 @@ macro_rules! make_mir_visitor { Rvalue::RawPtr(m, path) => { let ctx = match m { - Mutability::Mut => PlaceContext::MutatingUse( + RawPtrKind::Mut => PlaceContext::MutatingUse( MutatingUseContext::RawBorrow ), - Mutability::Not => PlaceContext::NonMutatingUse( + RawPtrKind::Const => PlaceContext::NonMutatingUse( NonMutatingUseContext::RawBorrow ), + RawPtrKind::FakeForPtrMetadata => PlaceContext::NonMutatingUse( + NonMutatingUseContext::Inspect + ), }; self.visit_place(path, ctx, location); } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 59f440432ebc..eab414e150fa 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -253,7 +253,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) ), ExprKind::RawBorrow { mutability, arg } => Ok( - Rvalue::RawPtr(*mutability, self.parse_place(*arg)?) + Rvalue::RawPtr((*mutability).into(), self.parse_place(*arg)?) ), ExprKind::Binary { op, lhs, rhs } => Ok( Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index b1851e79d5c6..0086775e9f46 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -630,6 +630,69 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(base_place.index(idx)) } + /// Given a place that's either an array or a slice, returns an operand + /// with the length of the array/slice. + /// + /// For arrays it'll be `Operand::Constant` with the actual length; + /// For slices it'll be `Operand::Move` of a local using `PtrMetadata`. + fn len_of_slice_or_array( + &mut self, + block: BasicBlock, + place: Place<'tcx>, + span: Span, + source_info: SourceInfo, + ) -> Operand<'tcx> { + let place_ty = place.ty(&self.local_decls, self.tcx).ty; + match place_ty.kind() { + ty::Array(_elem_ty, len_const) => { + // We know how long an array is, so just use that as a constant + // directly -- no locals needed. We do need one statement so + // that borrow- and initialization-checking consider it used, + // though. FIXME: Do we really *need* to count this as a use? + // Could partial array tracking work off something else instead? + self.cfg.push_fake_read(block, source_info, FakeReadCause::ForIndex, place); + let const_ = Const::Ty(self.tcx.types.usize, *len_const); + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ })) + } + ty::Slice(_elem_ty) => { + let ptr_or_ref = if let [PlaceElem::Deref] = place.projection[..] + && let local_ty = self.local_decls[place.local].ty + && local_ty.is_trivially_pure_clone_copy() + { + // It's extremely common that we have something that can be + // directly passed to `PtrMetadata`, so avoid an unnecessary + // temporary and statement in those cases. Note that we can + // only do that for `Copy` types -- not `&mut [_]` -- because + // the MIR we're building here needs to pass NLL later. + Operand::Copy(Place::from(place.local)) + } else { + let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty); + let slice_ptr = self.temp(ptr_ty, span); + self.cfg.push_assign( + block, + source_info, + slice_ptr, + Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place), + ); + Operand::Move(slice_ptr) + }; + + let len = self.temp(self.tcx.types.usize, span); + self.cfg.push_assign( + block, + source_info, + len, + Rvalue::UnaryOp(UnOp::PtrMetadata, ptr_or_ref), + ); + + Operand::Move(len) + } + _ => { + span_bug!(span, "len called on place of type {place_ty:?}") + } + } + } + fn bounds_check( &mut self, block: BasicBlock, @@ -638,25 +701,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span: Span, source_info: SourceInfo, ) -> BasicBlock { - let usize_ty = self.tcx.types.usize; - let bool_ty = self.tcx.types.bool; - // bounds check: - let len = self.temp(usize_ty, expr_span); - let lt = self.temp(bool_ty, expr_span); + let slice = slice.to_place(self); // len = len(slice) - self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self))); + let len = self.len_of_slice_or_array(block, slice, expr_span, source_info); + // lt = idx < len + let bool_ty = self.tcx.types.bool; + let lt = self.temp(bool_ty, expr_span); self.cfg.push_assign( block, source_info, lt, Rvalue::BinaryOp( BinOp::Lt, - Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))), + Box::new((Operand::Copy(Place::from(index)), len.to_copy())), ), ); - let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) }; + let msg = BoundsCheck { len, index: Operand::Copy(Place::from(index)) }; + // assert!(lt, "...") self.assert(block, Operand::Move(lt), true, msg, expr_span) } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 88f63d4e22cb..928156572d50 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { hir::Mutability::Not => this.as_read_only_place(block, arg), hir::Mutability::Mut => this.as_place(block, arg), }; - let address_of = Rvalue::RawPtr(mutability, unpack!(block = place)); + let address_of = Rvalue::RawPtr(mutability.into(), unpack!(block = place)); this.cfg.push_assign(block, source_info, destination, address_of); block.unit() } diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index f8a846749475..74b0e84068c6 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -700,7 +700,7 @@ where statements: vec![ self.assign( ptr, - Rvalue::RawPtr(Mutability::Mut, tcx.mk_place_index(self.place, cur)), + Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)), ), self.assign( cur.into(), @@ -816,7 +816,7 @@ where let mut delegate_block = BasicBlockData { statements: vec![ - self.assign(Place::from(array_ptr), Rvalue::RawPtr(Mutability::Mut, self.place)), + self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)), self.assign( Place::from(slice_ptr), Rvalue::Cast( diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 1c2c82d4cd57..16e15fa12e07 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -192,7 +192,7 @@ enum AggregateTy<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] enum AddressKind { Ref(BorrowKind), - Address(Mutability), + Address(RawPtrKind), } #[derive(Debug, PartialEq, Eq, Hash)] @@ -504,7 +504,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { mplace.layout.ty, bk.to_mutbl_lossy(), ), - AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl), + AddressKind::Address(mutbl) => { + Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl.to_mutbl_lossy()) + } }; let layout = self.ecx.layout_of(ty).ok()?; ImmTy::from_immediate(pointer, layout).into() diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 4b9ebd40b857..3dc4edaaa5ae 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -46,7 +46,6 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { } ctx.simplify_bool_cmp(rvalue); ctx.simplify_ref_deref(rvalue); - ctx.simplify_len(rvalue); ctx.simplify_ptr_aggregate(rvalue); ctx.simplify_cast(rvalue); ctx.simplify_repeated_aggregate(rvalue); @@ -166,18 +165,6 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } } - /// Transform `Len([_; N])` ==> `N`. - fn simplify_len(&self, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(self.local_decls, self.tcx).ty; - if let ty::Array(_, len) = *place_ty.kind() { - let const_ = Const::Ty(self.tcx.types.usize, len); - let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; - *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); - } - } - } - /// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`. fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::Aggregate(box AggregateKind::RawPtr(pointee_ty, mutability), fields) = rvalue diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index e201763468b3..1e546bfbeb30 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -125,7 +125,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { source_info, kind: StatementKind::Assign(Box::new(( dst, - Rvalue::RawPtr(Mutability::Mut, *lhs), + Rvalue::RawPtr(RawPtrKind::Mut, *lhs), ))), }; @@ -146,7 +146,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { source_info, kind: StatementKind::Assign(Box::new(( src, - Rvalue::RawPtr(Mutability::Not, *rhs), + Rvalue::RawPtr(RawPtrKind::Const, *rhs), ))), }; diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index f01bab75c4a1..1d53440cf0ba 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -2,17 +2,11 @@ use std::iter; use itertools::Itertools; use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_ast::Mutability; use rustc_const_eval::interpret; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_index::{Idx, IndexVec}; -use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, CallSource, CastKind, CoercionSource, Const, ConstOperand, - ConstValue, Local, LocalDecl, MirSource, Operand, Place, PlaceElem, RETURN_PLACE, Rvalue, - SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnwindAction, - UnwindTerminateReason, -}; +use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::util::{AsyncDropGlueMorphology, Discr}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -345,7 +339,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { .tcx .mk_place_elems(&[PlaceElem::Deref, PlaceElem::Field(field, field_ty)]), }; - self.put_temp_rvalue(Rvalue::RawPtr(Mutability::Mut, place)) + self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place)) } /// If given Self is an enum puts `to_drop: *mut FieldTy` on top of @@ -365,7 +359,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { PlaceElem::Field(field, field_ty), ]), }; - self.put_temp_rvalue(Rvalue::RawPtr(Mutability::Mut, place)) + self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place)) } /// If given Self is an enum puts `to_drop: *mut FieldTy` on top of diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 026923ad786b..5881264cba52 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1128,14 +1128,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } UnOp::PtrMetadata => { - if !matches!(self.body.phase, MirPhase::Runtime(_)) { - // It would probably be fine to support this in earlier phases, but at - // the time of writing it's only ever introduced from intrinsic - // lowering or other runtime-phase optimization passes, so earlier - // things can just `bug!` on it. - self.fail(location, "PtrMetadata should be in runtime MIR only"); - } - check_kinds!( a, "Cannot PtrMetadata non-pointer non-reference type {:?}", diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 50287b706ce8..2373ab67d42e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2830,9 +2830,10 @@ pub(crate) struct DynAfterMut { pub(crate) struct FnPointerCannotBeConst { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] #[label] pub qualifier: Span, + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -2840,9 +2841,10 @@ pub(crate) struct FnPointerCannotBeConst { pub(crate) struct FnPointerCannotBeAsync { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] #[label] pub qualifier: Span, + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6497d19a173c..dc5919b3630c 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -609,16 +609,58 @@ impl<'a> Parser<'a> { let span_start = self.token.span; let ast::FnHeader { ext, safety, constness, coroutine_kind } = self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?; + let fn_start_lo = self.prev_token.span.lo(); if self.may_recover() && self.token == TokenKind::Lt { self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?; } let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; let whole_span = lo.to(self.prev_token.span); - if let ast::Const::Yes(span) = constness { - self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span }); + + // Order/parsing of "front matter" follows: + // ` fn()` + // ^ ^ ^ ^ ^ + // | | | | fn_start_lo + // | | | ext_sp.lo + // | | safety_sp.lo + // | coroutine_sp.lo + // const_sp.lo + if let ast::Const::Yes(const_span) = constness { + let next_token_lo = if let Some( + ast::CoroutineKind::Async { span, .. } + | ast::CoroutineKind::Gen { span, .. } + | ast::CoroutineKind::AsyncGen { span, .. }, + ) = coroutine_kind + { + span.lo() + } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety { + span.lo() + } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext { + span.lo() + } else { + fn_start_lo + }; + let sugg_span = const_span.with_hi(next_token_lo); + self.dcx().emit_err(FnPointerCannotBeConst { + span: whole_span, + qualifier: const_span, + suggestion: sugg_span, + }); } - if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind { - self.dcx().emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span }); + if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind { + let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety + { + span.lo() + } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext { + span.lo() + } else { + fn_start_lo + }; + let sugg_span = async_span.with_hi(next_token_lo); + self.dcx().emit_err(FnPointerCannotBeAsync { + span: whole_span, + qualifier: async_span, + suggestion: sugg_span, + }); } // FIXME(gen_blocks): emit a similar error for `gen fn()` let decl_span = span_start.to(self.prev_token.span); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 63aaa3abc8e5..4ce638251297 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1870,8 +1870,6 @@ options! { "verify extended properties for incr. comp. (default: no): - hashes of green query instances - hash collisions of query keys"), - inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], - "control whether `#[inline]` functions are in all CGUs"), inline_llvm: bool = (true, parse_bool, [TRACKED], "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index a5a17b4b5730..aee98d7d410e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -232,6 +232,18 @@ impl<'tcx> Stable<'tcx> for mir::Mutability { } } +impl<'tcx> Stable<'tcx> for mir::RawPtrKind { + type T = stable_mir::mir::RawPtrKind; + fn stable(&self, _: &mut Tables<'_>) -> Self::T { + use mir::RawPtrKind::*; + match *self { + Const => stable_mir::mir::RawPtrKind::Const, + Mut => stable_mir::mir::RawPtrKind::Mut, + FakeForPtrMetadata => stable_mir::mir::RawPtrKind::FakeForPtrMetadata, + } + } +} + impl<'tcx> Stable<'tcx> for mir::BorrowKind { type T = stable_mir::mir::BorrowKind; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1fb15fe98000..6f1d3a74a816 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2184,8 +2184,10 @@ symbols! { vec_macro, vec_new, vec_pop, + vec_reserve, vec_with_capacity, vecdeque_iter, + vecdeque_reserve, vector, version, vfp2, diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 0944bda26875..816564d2fed8 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -1,4 +1,4 @@ -use rustc_abi::{BackendRepr, Float, Primitive}; +use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size}; use crate::abi::call::{ArgAbi, FnAbi, Reg}; use crate::spec::HasTargetSpec; @@ -6,7 +6,7 @@ use crate::spec::HasTargetSpec; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { - let fixup = |a: &mut ArgAbi<'_, Ty>| { + let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| { match a.layout.backend_repr { BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {} BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { @@ -23,11 +23,16 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi< // (probably what clang calls "illegal vectors"). } BackendRepr::Scalar(scalar) => { - // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up - // with what LLVM expects. - if a.layout.size.bytes() > 8 + if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) { + // `i128` is returned in xmm0 by Clang and GCC + // FIXME(#134288): This may change for the `-msvc` targets in the future. + let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) }; + a.cast_to(reg); + } else if a.layout.size.bytes() > 8 && !matches!(scalar.primitive(), Primitive::Float(Float::F128)) { + // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up + // with what LLVM expects. a.make_indirect(); } else { a.extend_integer_width_to(32); @@ -37,8 +42,9 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi< }; if !fn_abi.ret.is_ignore() { - fixup(&mut fn_abi.ret); + fixup(&mut fn_abi.ret, true); } + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() && arg.layout.is_zst() { // Windows ABIs do not talk about ZST since such types do not exist in MSVC. @@ -49,7 +55,7 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi< arg.make_indirect_from_ignore(); continue; } - fixup(arg); + fixup(arg, false); } // FIXME: We should likely also do something about ZST return types, similar to above. // However, that's non-trivial due to `()`. 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 26ba1511b540..92098e204487 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -6,7 +6,8 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use crate::traits::query::NoSolution; -use crate::traits::{ObligationCause, ObligationCtxt}; +use crate::traits::query::normalize::QueryNormalizeExt; +use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -90,6 +91,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { pub fn compute_dropck_outlives_inner<'tcx>( ocx: &ObligationCtxt<'_, 'tcx>, goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, + span: Span, ) -> Result, NoSolution> { let tcx = ocx.infcx.tcx; let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal; @@ -135,7 +137,7 @@ pub fn compute_dropck_outlives_inner<'tcx>( // Set used to detect infinite recursion. let mut ty_set = FxHashSet::default(); - let cause = ObligationCause::dummy(); + let cause = ObligationCause::dummy_with_span(span); let mut constraints = DropckConstraint::empty(); while let Some((ty, depth)) = ty_stack.pop() { debug!( @@ -171,18 +173,13 @@ pub fn compute_dropck_outlives_inner<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - let normalized_ty = ocx.normalize(&cause, param_env, ty); + let Normalized { value: ty, obligations } = + ocx.infcx.at(&cause, param_env).query_normalize(ty)?; + ocx.register_obligations(obligations); - let errors = ocx.select_where_possible(); - if !errors.is_empty() { - debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}"); - return Err(NoSolution); - } + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - let normalized_ty = ocx.infcx.resolve_vars_if_possible(normalized_ty); - debug!("dropck_outlives: ty from dtorck_types = {:?}", normalized_ty); - - match normalized_ty.kind() { + match ty.kind() { // All parameters live for the duration of the // function. ty::Param(..) => {} @@ -190,12 +187,12 @@ pub fn compute_dropck_outlives_inner<'tcx>( // A projection that we couldn't resolve - it // might have a destructor. ty::Alias(..) => { - result.kinds.push(normalized_ty.into()); + result.kinds.push(ty.into()); } _ => { - if ty_set.insert(normalized_ty) { - ty_stack.push((normalized_ty, depth + 1)); + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); } } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 254dee794f1b..4eecde00eaa1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -30,8 +30,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, + span: Span, ) -> Result { - type_op_ascribe_user_type_with_span(ocx, key, None) + type_op_ascribe_user_type_with_span(ocx, key, span) } } @@ -41,11 +42,10 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { pub fn type_op_ascribe_user_type_with_span<'tcx>( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, - span: Option, + span: Span, ) -> Result<(), NoSolution> { let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); - let span = span.unwrap_or(DUMMY_SP); match user_ty.kind { UserTypeKind::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, UserTypeKind::TypeOf(def_id, user_args) => { 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 fe47e837dfb5..1339739ce7f5 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 @@ -5,7 +5,7 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; -use rustc_span::DUMMY_SP; +use rustc_span::Span; use rustc_span::def_id::CRATE_DEF_ID; use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::{SmallVec, smallvec}; @@ -45,11 +45,12 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, + span: Span, ) -> Result { if ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat { - compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty) + compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span) } else { - compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty) + compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty, span) } } } @@ -58,13 +59,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( ocx: &ObligationCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, + span: Span, ) -> Result>, NoSolution> { let normalize_op = |ty| -> Result<_, NoSolution> { // We must normalize the type so we can compute the right outlives components. // for example, if we have some constrained param type like `T: Trait`, // and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`. let ty = ocx - .deeply_normalize(&ObligationCause::dummy(), param_env, ty) + .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty) .map_err(|_| NoSolution)?; if !ocx.select_all_or_error().is_empty() { return Err(NoSolution); @@ -142,6 +144,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( ocx: &ObligationCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, + span: Span, ) -> Result>, NoSolution> { let tcx = ocx.infcx.tcx; @@ -171,8 +174,8 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( // FIXME(@lcnr): It's not really "always fine", having fewer implied // bounds can be backward incompatible, e.g. #101951 was caused by // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); + let obligations = + wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, span).unwrap_or_default(); for obligation in obligations { debug!(?obligation); @@ -255,7 +258,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( // Need to manually normalize in the new solver as `wf::obligations` does not. if ocx.infcx.next_trait_solver() { ty_a = ocx - .deeply_normalize(&ObligationCause::dummy(), param_env, ty_a) + .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty_a) .map_err(|_| NoSolution)?; } let mut components = smallvec![]; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 54fce914bb65..68feb19c55b8 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -92,6 +92,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable> + 't fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, + span: Span, ) -> Result; fn fully_perform_into( @@ -152,7 +153,7 @@ where if infcx.next_trait_solver() { return Ok(scrape_region_constraints( infcx, - |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self), + |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span), "query type op", span, )? diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 94df222932ef..e8c2528aa6ee 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -5,6 +5,7 @@ use rustc_middle::traits::query::NoSolution; pub use rustc_middle::traits::query::type_op::Normalize; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; use crate::traits::ObligationCtxt; @@ -29,9 +30,10 @@ where fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, + span: Span, ) -> Result { // FIXME(-Znext-solver): shouldn't be using old normalizer - Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value)) + Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value)) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index fa05f901f663..99a2779aa821 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -1,5 +1,6 @@ use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution}; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use rustc_span::Span; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; use crate::traits::ObligationCtxt; @@ -28,7 +29,8 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, + span: Span, ) -> Result { - compute_dropck_outlives_inner(ocx, key.param_env.and(key.value)) + compute_dropck_outlives_inner(ocx, key.param_env.and(key.value), span) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index b2dab379262f..4f9e2e79d624 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -4,6 +4,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; pub use rustc_middle::traits::query::type_op::ProvePredicate; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; +use rustc_span::Span; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; use crate::traits::ObligationCtxt; @@ -57,10 +58,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, + span: Span, ) -> Result { ocx.register_obligation(Obligation::new( ocx.infcx.tcx, - ObligationCause::dummy(), + ObligationCause::dummy_with_span(span), key.param_env, key.value.predicate, )); diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 51e4dbe81b3d..b3377e15aa79 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -6,6 +6,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::{self, GenericArgs, TyCtxt}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::dropck_outlives::{ compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, @@ -24,7 +25,7 @@ fn dropck_outlives<'tcx>( debug!("dropck_outlives(goal={:#?})", canonical_goal); tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| { - compute_dropck_outlives_inner(ocx, goal) + compute_dropck_outlives_inner(ocx, goal, DUMMY_SP) }) } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index a51eefd908cc..5f75e242a50f 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -8,6 +8,7 @@ use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{ compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner, @@ -28,7 +29,7 @@ fn implied_outlives_bounds_compat<'tcx>( > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts(); - compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty) + compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty, DUMMY_SP) }) } @@ -41,6 +42,6 @@ fn implied_outlives_bounds<'tcx>( > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts(); - compute_implied_outlives_bounds_inner(ocx, param_env, ty) + compute_implied_outlives_bounds_inner(ocx, param_env, ty, DUMMY_SP) }) } diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 5d041c2623aa..e58ad639d206 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -5,13 +5,15 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalQueryInput, QueryRespons use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{ AscribeUserType, type_op_ascribe_user_type_with_span, }; use rustc_trait_selection::traits::query::type_op::normalize::Normalize; use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; -use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { @@ -30,7 +32,7 @@ fn type_op_ascribe_user_type<'tcx>( canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { - type_op_ascribe_user_type_with_span(ocx, key, None) + type_op_ascribe_user_type_with_span(ocx, key, DUMMY_SP) }) } @@ -42,7 +44,10 @@ where T: fmt::Debug + TypeFoldable>, { let (param_env, Normalize { value }) = key.into_parts(); - Ok(ocx.normalize(&ObligationCause::dummy(), param_env, value)) + let Normalized { value, obligations } = + ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?; + ocx.register_obligations(obligations); + Ok(value) } fn type_op_normalize_ty<'tcx>( diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index dfd090b39563..8686169c15d6 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -457,7 +457,7 @@ pub enum Rvalue { /// /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like /// `&raw v` or `addr_of!(v)`. - AddressOf(Mutability, Place), + AddressOf(RawPtrKind, Place), /// Creates an aggregate value, like a tuple or struct. /// @@ -577,7 +577,7 @@ impl Rvalue { } Rvalue::AddressOf(mutability, place) => { let place_ty = place.ty(locals)?; - Ok(Ty::new_ptr(place_ty, *mutability)) + Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy())) } Rvalue::Len(..) => Ok(Ty::usize_ty()), Rvalue::Cast(.., ty) => Ok(*ty), @@ -903,6 +903,24 @@ impl BorrowKind { } } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum RawPtrKind { + Mut, + Const, + FakeForPtrMetadata, +} + +impl RawPtrKind { + pub fn to_mutable_lossy(self) -> Mutability { + match self { + RawPtrKind::Mut { .. } => Mutability::Mut, + RawPtrKind::Const => Mutability::Not, + // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. + RawPtrKind::FakeForPtrMetadata => Mutability::Not, + } + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum MutBorrowKind { Default, diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 93ed32e258a8..81981bce2026 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -6,7 +6,9 @@ use std::{fmt, io, iter}; use fmt::{Display, Formatter}; use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind}; -use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents}; +use crate::mir::{ + Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents, +}; use crate::ty::{AdtKind, IndexedVal, MirConst, Ty, TyConst}; use crate::{Body, CrateDef, Mutability, with}; @@ -325,7 +327,7 @@ fn pretty_ty_const(ct: &TyConst) -> String { fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { match rval { Rvalue::AddressOf(mutability, place) => { - write!(writer, "&raw {} {:?}", pretty_mut(*mutability), place) + write!(writer, "&raw {} {:?}", pretty_raw_ptr_kind(*mutability), place) } Rvalue::Aggregate(aggregate_kind, operands) => { // FIXME: Add pretty_aggregate function that returns a pretty string @@ -437,3 +439,11 @@ fn pretty_mut(mutability: Mutability) -> &'static str { Mutability::Mut => "mut ", } } + +fn pretty_raw_ptr_kind(kind: RawPtrKind) -> &'static str { + match kind { + RawPtrKind::Const => "const", + RawPtrKind::Mut => "mut", + RawPtrKind::FakeForPtrMetadata => "const (fake)", + } +} diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index d73e79c48937..79efb83cebde 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -308,7 +308,7 @@ pub trait MirVisitor { fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) { match rvalue { Rvalue::AddressOf(mutability, place) => { - let pcx = PlaceContext { is_mut: *mutability == Mutability::Mut }; + let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; self.visit_place(place, pcx, location); } Rvalue::Aggregate(_, operands) => { diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1b5e44a91346..8b38e6fc259a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1115,6 +1115,8 @@ impl Box { /// memory problems. For example, a double-free may occur if the /// function is called twice on the same `NonNull` pointer. /// + /// The non-null pointer must point to a block of memory allocated by the global allocator. + /// /// The safety conditions are described in the [memory layout] section. /// /// # Examples @@ -1170,7 +1172,7 @@ impl Box { /// memory problems. For example, a double-free may occur if the /// function is called twice on the same raw pointer. /// - /// The raw pointer must point to a block of memory allocated by `alloc` + /// The raw pointer must point to a block of memory allocated by `alloc`. /// /// # Examples /// @@ -1225,6 +1227,7 @@ impl Box { /// memory problems. For example, a double-free may occur if the /// function is called twice on the same raw pointer. /// + /// The non-null pointer must point to a block of memory allocated by `alloc`. /// /// # Examples /// diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index d137d2721ee4..091376d5d685 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -16,7 +16,7 @@ impl Root { /// a `BTreeMap`, both iterators should produce keys in strictly ascending /// order, each greater than all keys in the tree, including any keys /// already in the tree upon entry. - pub fn append_from_sorted_iters( + pub(super) fn append_from_sorted_iters( &mut self, left: I, right: I, @@ -36,8 +36,12 @@ impl Root { /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. - pub fn bulk_push(&mut self, iter: I, length: &mut usize, alloc: A) - where + pub(super) fn bulk_push( + &mut self, + iter: I, + length: &mut usize, + alloc: A, + ) where I: Iterator, { let mut cur_node = self.borrow_mut().last_leaf_edge().into_node(); diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs index 000b9bd0fab4..e848ac3f2d19 100644 --- a/library/alloc/src/collections/btree/borrow.rs +++ b/library/alloc/src/collections/btree/borrow.rs @@ -11,7 +11,7 @@ use core::ptr::NonNull; /// the compiler to follow. A `DormantMutRef` allows you to check borrowing /// yourself, while still expressing its stacked nature, and encapsulating /// the raw pointer code needed to do this without undefined behavior. -pub struct DormantMutRef<'a, T> { +pub(super) struct DormantMutRef<'a, T> { ptr: NonNull, _marker: PhantomData<&'a mut T>, } @@ -23,7 +23,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// Capture a unique borrow, and immediately reborrow it. For the compiler, /// the lifetime of the new reference is the same as the lifetime of the /// original reference, but you promise to use it for a shorter period. - pub fn new(t: &'a mut T) -> (&'a mut T, Self) { + pub(super) fn new(t: &'a mut T) -> (&'a mut T, Self) { let ptr = NonNull::from(t); // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose // only this reference, so it is unique. @@ -37,7 +37,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn awaken(self) -> &'a mut T { + pub(super) unsafe fn awaken(self) -> &'a mut T { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &mut *self.ptr.as_ptr() } } @@ -48,7 +48,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn reborrow(&mut self) -> &'a mut T { + pub(super) unsafe fn reborrow(&mut self) -> &'a mut T { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &mut *self.ptr.as_ptr() } } @@ -59,7 +59,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn reborrow_shared(&self) -> &'a T { + pub(super) unsafe fn reborrow_shared(&self) -> &'a T { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &*self.ptr.as_ptr() } } diff --git a/library/alloc/src/collections/btree/dedup_sorted_iter.rs b/library/alloc/src/collections/btree/dedup_sorted_iter.rs index cd6a88f32912..6bcf0bca519a 100644 --- a/library/alloc/src/collections/btree/dedup_sorted_iter.rs +++ b/library/alloc/src/collections/btree/dedup_sorted_iter.rs @@ -6,7 +6,7 @@ use core::iter::Peekable; /// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1]. /// /// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter -pub struct DedupSortedIter +pub(super) struct DedupSortedIter where I: Iterator, { @@ -17,7 +17,7 @@ impl DedupSortedIter where I: Iterator, { - pub fn new(iter: I) -> Self { + pub(super) fn new(iter: I) -> Self { Self { iter: iter.peekable() } } } diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs index 09edea3555ad..b0c675979469 100644 --- a/library/alloc/src/collections/btree/fix.rs +++ b/library/alloc/src/collections/btree/fix.rs @@ -57,7 +57,10 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// /// This method does not expect ancestors to already be underfull upon entry /// and panics if it encounters an empty ancestor. - pub fn fix_node_and_affected_ancestors(mut self, alloc: A) -> bool { + pub(super) fn fix_node_and_affected_ancestors( + mut self, + alloc: A, + ) -> bool { loop { match self.fix_node_through_parent(alloc.clone()) { Ok(Some(parent)) => self = parent.forget_type(), @@ -70,7 +73,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { impl Root { /// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty. - pub fn fix_top(&mut self, alloc: A) { + pub(super) fn fix_top(&mut self, alloc: A) { while self.height() > 0 && self.len() == 0 { self.pop_internal_level(alloc.clone()); } @@ -79,7 +82,7 @@ impl Root { /// Stocks up or merge away any underfull nodes on the right border of the /// tree. The other nodes, those that are not the root nor a rightmost edge, /// must already have at least MIN_LEN elements. - pub fn fix_right_border(&mut self, alloc: A) { + pub(super) fn fix_right_border(&mut self, alloc: A) { self.fix_top(alloc.clone()); if self.len() > 0 { self.borrow_mut().last_kv().fix_right_border_of_right_edge(alloc.clone()); @@ -88,7 +91,7 @@ impl Root { } /// The symmetric clone of `fix_right_border`. - pub fn fix_left_border(&mut self, alloc: A) { + pub(super) fn fix_left_border(&mut self, alloc: A) { self.fix_top(alloc.clone()); if self.len() > 0 { self.borrow_mut().first_kv().fix_left_border_of_left_edge(alloc.clone()); @@ -99,7 +102,7 @@ impl Root { /// Stocks up any underfull nodes on the right border of the tree. /// The other nodes, those that are neither the root nor a rightmost edge, /// must be prepared to have up to MIN_LEN elements stolen. - pub fn fix_right_border_of_plentiful(&mut self) { + pub(super) fn fix_right_border_of_plentiful(&mut self) { let mut cur_node = self.borrow_mut(); while let Internal(internal) = cur_node.force() { // Check if rightmost child is underfull. diff --git a/library/alloc/src/collections/btree/mem.rs b/library/alloc/src/collections/btree/mem.rs index d738c5c47b4c..4643c4133d55 100644 --- a/library/alloc/src/collections/btree/mem.rs +++ b/library/alloc/src/collections/btree/mem.rs @@ -6,7 +6,7 @@ use core::{intrinsics, mem, ptr}; /// If a panic occurs in the `change` closure, the entire process will be aborted. #[allow(dead_code)] // keep as illustration and for future use #[inline] -pub fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { +pub(super) fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { replace(v, |value| (change(value), ())) } @@ -15,7 +15,7 @@ pub fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { /// /// If a panic occurs in the `change` closure, the entire process will be aborted. #[inline] -pub fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { +pub(super) fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { struct PanicGuard; impl Drop for PanicGuard { fn drop(&mut self) { diff --git a/library/alloc/src/collections/btree/merge_iter.rs b/library/alloc/src/collections/btree/merge_iter.rs index 7f23d93b990f..c5b93d30a118 100644 --- a/library/alloc/src/collections/btree/merge_iter.rs +++ b/library/alloc/src/collections/btree/merge_iter.rs @@ -4,7 +4,7 @@ use core::iter::FusedIterator; /// Core of an iterator that merges the output of two strictly ascending iterators, /// for instance a union or a symmetric difference. -pub struct MergeIterInner { +pub(super) struct MergeIterInner { a: I, b: I, peeked: Option>, @@ -40,7 +40,7 @@ where impl MergeIterInner { /// Creates a new core for an iterator merging a pair of sources. - pub fn new(a: I, b: I) -> Self { + pub(super) fn new(a: I, b: I) -> Self { MergeIterInner { a, b, peeked: None } } @@ -51,7 +51,7 @@ impl MergeIterInner { /// the sources are not strictly ascending). If neither returned option /// contains a value, iteration has finished and subsequent calls will /// return the same empty pair. - pub fn nexts Ordering>( + pub(super) fn nexts Ordering>( &mut self, cmp: Cmp, ) -> (Option, Option) @@ -85,7 +85,7 @@ impl MergeIterInner { } /// Returns a pair of upper bounds for the `size_hint` of the final iterator. - pub fn lens(&self) -> (usize, usize) + pub(super) fn lens(&self) -> (usize, usize) where I: ExactSizeIterator, { diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index b8667d09c33b..665148066739 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -2,13 +2,13 @@ mod append; mod borrow; mod dedup_sorted_iter; mod fix; -pub mod map; +pub(super) mod map; mod mem; mod merge_iter; mod navigate; mod node; mod remove; mod search; -pub mod set; +pub(super) mod set; mod set_val; mod split; diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 14b7d4ad71f8..b2a7de74875d 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -7,7 +7,7 @@ use super::node::{Handle, NodeRef, marker}; use super::search::SearchBound; use crate::alloc::Allocator; // `front` and `back` are always both `None` or both `Some`. -pub struct LeafRange { +pub(super) struct LeafRange { front: Option, marker::Edge>>, back: Option, marker::Edge>>, } @@ -25,7 +25,7 @@ impl Default for LeafRange { } impl LeafRange { - pub fn none() -> Self { + pub(super) fn none() -> Self { LeafRange { front: None, back: None } } @@ -34,7 +34,7 @@ impl LeafRange { } /// Temporarily takes out another, immutable equivalent of the same range. - pub fn reborrow(&self) -> LeafRange, K, V> { + pub(super) fn reborrow(&self) -> LeafRange, K, V> { LeafRange { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), @@ -44,24 +44,24 @@ impl LeafRange { impl<'a, K, V> LeafRange, K, V> { #[inline] - pub fn next_checked(&mut self) -> Option<(&'a K, &'a V)> { + pub(super) fn next_checked(&mut self) -> Option<(&'a K, &'a V)> { self.perform_next_checked(|kv| kv.into_kv()) } #[inline] - pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> { + pub(super) fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> { self.perform_next_back_checked(|kv| kv.into_kv()) } } impl<'a, K, V> LeafRange, K, V> { #[inline] - pub fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> { + pub(super) fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> { self.perform_next_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut()) } #[inline] - pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> { + pub(super) fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> { self.perform_next_back_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut()) } } @@ -124,7 +124,7 @@ impl LazyLeafHandle { } // `front` and `back` are always both `None` or both `Some`. -pub struct LazyLeafRange { +pub(super) struct LazyLeafRange { front: Option>, back: Option>, } @@ -142,12 +142,12 @@ impl<'a, K: 'a, V: 'a> Clone for LazyLeafRange, K, V> { } impl LazyLeafRange { - pub fn none() -> Self { + pub(super) fn none() -> Self { LazyLeafRange { front: None, back: None } } /// Temporarily takes out another, immutable equivalent of the same range. - pub fn reborrow(&self) -> LazyLeafRange, K, V> { + pub(super) fn reborrow(&self) -> LazyLeafRange, K, V> { LazyLeafRange { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), @@ -157,24 +157,24 @@ impl LazyLeafRange { impl<'a, K, V> LazyLeafRange, K, V> { #[inline] - pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { + pub(super) unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { unsafe { self.init_front().unwrap().next_unchecked() } } #[inline] - pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { + pub(super) unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { unsafe { self.init_back().unwrap().next_back_unchecked() } } } impl<'a, K, V> LazyLeafRange, K, V> { #[inline] - pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { + pub(super) unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { self.init_front().unwrap().next_unchecked() } } #[inline] - pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { + pub(super) unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { self.init_back().unwrap().next_back_unchecked() } } } @@ -190,7 +190,7 @@ impl LazyLeafRange { } #[inline] - pub unsafe fn deallocating_next_unchecked( + pub(super) unsafe fn deallocating_next_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -200,7 +200,7 @@ impl LazyLeafRange { } #[inline] - pub unsafe fn deallocating_next_back_unchecked( + pub(super) unsafe fn deallocating_next_back_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -210,7 +210,7 @@ impl LazyLeafRange { } #[inline] - pub fn deallocating_end(&mut self, alloc: A) { + pub(super) fn deallocating_end(&mut self, alloc: A) { if let Some(front) = self.take_front() { front.deallocating_end(alloc) } @@ -313,7 +313,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// /// The result is meaningful only if the tree is ordered by key, like the tree /// in a `BTreeMap` is. - pub fn range_search(self, range: R) -> LeafRange, K, V> + pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, K: Borrow, @@ -324,7 +324,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } /// Finds the pair of leaf edges delimiting an entire tree. - pub fn full_range(self) -> LazyLeafRange, K, V> { + pub(super) fn full_range(self) -> LazyLeafRange, K, V> { full_range(self, self) } } @@ -339,7 +339,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// /// # Safety /// Do not use the duplicate handles to visit the same KV twice. - pub fn range_search(self, range: R) -> LeafRange, K, V> + pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, K: Borrow, @@ -351,7 +351,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. /// The results are non-unique references allowing mutation (of values only), so must be used /// with care. - pub fn full_range(self) -> LazyLeafRange, K, V> { + pub(super) fn full_range(self) -> LazyLeafRange, K, V> { // We duplicate the root NodeRef here -- we will never visit the same KV // twice, and never end up with overlapping value references. let self2 = unsafe { ptr::read(&self) }; @@ -363,7 +363,7 @@ impl NodeRef { /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. /// The results are non-unique references allowing massively destructive mutation, so must be /// used with the utmost care. - pub fn full_range(self) -> LazyLeafRange { + pub(super) fn full_range(self) -> LazyLeafRange { // We duplicate the root NodeRef here -- we will never access it in a way // that overlaps references obtained from the root. let self2 = unsafe { ptr::read(&self) }; @@ -377,7 +377,7 @@ impl /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the right side, which is either in the same leaf node or in an ancestor node. /// If the leaf edge is the last one in the tree, returns [`Result::Err`] with the root node. - pub fn next_kv( + pub(super) fn next_kv( self, ) -> Result< Handle, marker::KV>, @@ -398,7 +398,7 @@ impl /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the left side, which is either in the same leaf node or in an ancestor node. /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node. - pub fn next_back_kv( + pub(super) fn next_back_kv( self, ) -> Result< Handle, marker::KV>, @@ -627,7 +627,9 @@ impl NodeRef Handle, marker::Edge> { + pub(super) fn first_leaf_edge( + self, + ) -> Handle, marker::Edge> { let mut node = self; loop { match node.force() { @@ -640,7 +642,9 @@ impl NodeRef Handle, marker::Edge> { + pub(super) fn last_leaf_edge( + self, + ) -> Handle, marker::Edge> { let mut node = self; loop { match node.force() { @@ -651,7 +655,7 @@ impl NodeRef { +pub(super) enum Position { Leaf(NodeRef), Internal(NodeRef), InternalKV, @@ -661,7 +665,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// Visits leaf nodes and internal KVs in order of ascending keys, and also /// visits internal nodes as a whole in a depth first order, meaning that /// internal nodes precede their individual KVs and their child nodes. - pub fn visit_nodes_in_order(self, mut visit: F) + pub(super) fn visit_nodes_in_order(self, mut visit: F) where F: FnMut(Position, K, V>), { @@ -693,7 +697,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } /// Calculates the number of elements in a (sub)tree. - pub fn calc_length(self) -> usize { + pub(super) fn calc_length(self) -> usize { let mut result = 0; self.visit_nodes_in_order(|pos| match pos { Position::Leaf(node) => result += node.len(), @@ -708,7 +712,9 @@ impl Handle, marker::KV> { /// Returns the leaf edge closest to a KV for forward navigation. - pub fn next_leaf_edge(self) -> Handle, marker::Edge> { + pub(super) fn next_leaf_edge( + self, + ) -> Handle, marker::Edge> { match self.force() { Leaf(leaf_kv) => leaf_kv.right_edge(), Internal(internal_kv) => { @@ -719,7 +725,7 @@ impl } /// Returns the leaf edge closest to a KV for backward navigation. - pub fn next_back_leaf_edge( + pub(super) fn next_back_leaf_edge( self, ) -> Handle, marker::Edge> { match self.force() { @@ -735,7 +741,7 @@ impl impl NodeRef { /// Returns the leaf edge corresponding to the first point at which the /// given bound is true. - pub fn lower_bound( + pub(super) fn lower_bound( self, mut bound: SearchBound<&Q>, ) -> Handle, marker::Edge> @@ -758,7 +764,7 @@ impl NodeRef( + pub(super) fn upper_bound( self, mut bound: SearchBound<&Q>, ) -> Handle, marker::Edge> diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 4057657632ba..6815ac1c1930 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -40,8 +40,8 @@ use crate::alloc::{Allocator, Layout}; use crate::boxed::Box; const B: usize = 6; -pub const CAPACITY: usize = 2 * B - 1; -pub const MIN_LEN_AFTER_SPLIT: usize = B - 1; +pub(super) const CAPACITY: usize = 2 * B - 1; +pub(super) const MIN_LEN_AFTER_SPLIT: usize = B - 1; const KV_IDX_CENTER: usize = B - 1; const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1; const EDGE_IDX_RIGHT_OF_CENTER: usize = B; @@ -179,7 +179,7 @@ type BoxedNode = NonNull>; /// as the returned reference is used. /// The methods supporting insert bend this rule by returning a raw pointer, /// i.e., a reference without any lifetime. -pub struct NodeRef { +pub(super) struct NodeRef { /// The number of levels that the node and the level of leaves are apart, a /// constant of the node that cannot be entirely described by `Type`, and that /// the node itself does not store. We only need to store the height of the root @@ -195,7 +195,7 @@ pub struct NodeRef { /// The root node of an owned tree. /// /// Note that this does not have a destructor, and must be cleaned up manually. -pub type Root = NodeRef; +pub(super) type Root = NodeRef; impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef, K, V, Type> {} impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef, K, V, Type> { @@ -213,7 +213,7 @@ unsafe impl Send for NodeRef unsafe impl Send for NodeRef {} impl NodeRef { - pub fn new_leaf(alloc: A) -> Self { + pub(super) fn new_leaf(alloc: A) -> Self { Self::from_new_leaf(LeafNode::new(alloc)) } @@ -274,7 +274,7 @@ impl NodeRef { /// The number of edges is `len() + 1`. /// Note that, despite being safe, calling this function can have the side effect /// of invalidating mutable references that unsafe code has created. - pub fn len(&self) -> usize { + pub(super) fn len(&self) -> usize { // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut, // there might be outstanding mutable references to values that we must not invalidate. unsafe { usize::from((*Self::as_leaf_ptr(self)).len) } @@ -285,12 +285,12 @@ impl NodeRef { /// root on top, the number says at which elevation the node appears. /// If you picture trees with leaves on top, the number says how high /// the tree extends above the node. - pub fn height(&self) -> usize { + pub(super) fn height(&self) -> usize { self.height } /// Temporarily takes out another, immutable reference to the same node. - pub fn reborrow(&self) -> NodeRef, K, V, Type> { + pub(super) fn reborrow(&self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -315,7 +315,7 @@ impl NodeRef /// /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. - pub fn ascend( + pub(super) fn ascend( self, ) -> Result, marker::Edge>, Self> { const { @@ -335,24 +335,24 @@ impl NodeRef .ok_or(self) } - pub fn first_edge(self) -> Handle { + pub(super) fn first_edge(self) -> Handle { unsafe { Handle::new_edge(self, 0) } } - pub fn last_edge(self) -> Handle { + pub(super) fn last_edge(self) -> Handle { let len = self.len(); unsafe { Handle::new_edge(self, len) } } /// Note that `self` must be nonempty. - pub fn first_kv(self) -> Handle { + pub(super) fn first_kv(self) -> Handle { let len = self.len(); assert!(len > 0); unsafe { Handle::new_kv(self, 0) } } /// Note that `self` must be nonempty. - pub fn last_kv(self) -> Handle { + pub(super) fn last_kv(self) -> Handle { let len = self.len(); assert!(len > 0); unsafe { Handle::new_kv(self, len - 1) } @@ -381,7 +381,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } /// Borrows a view into the keys stored in the node. - pub fn keys(&self) -> &[K] { + pub(super) fn keys(&self) -> &[K] { let leaf = self.into_leaf(); unsafe { leaf.keys.get_unchecked(..usize::from(leaf.len)).assume_init_ref() } } @@ -391,7 +391,7 @@ impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also /// deallocates the current node in the process. This is unsafe because the /// current node will still be accessible despite being deallocated. - pub unsafe fn deallocate_and_ascend( + pub(super) unsafe fn deallocate_and_ascend( self, alloc: A, ) -> Option, marker::Edge>> { @@ -443,7 +443,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Returns a dormant copy of this node with its lifetime erased which can /// be reawakened later. - pub fn dormant(&self) -> NodeRef { + pub(super) fn dormant(&self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -455,7 +455,7 @@ impl NodeRef { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn awaken<'a>(self) -> NodeRef, K, V, Type> { + pub(super) unsafe fn awaken<'a>(self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -536,7 +536,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// Borrows exclusive access to the length of the node. - pub fn len_mut(&mut self) -> &mut u16 { + pub(super) fn len_mut(&mut self) -> &mut u16 { &mut self.as_leaf_mut().len } } @@ -578,14 +578,14 @@ impl NodeRef { impl NodeRef { /// Returns a new owned tree, with its own root node that is initially empty. - pub fn new(alloc: A) -> Self { + pub(super) fn new(alloc: A) -> Self { NodeRef::new_leaf(alloc).forget_type() } /// Adds a new internal node with a single edge pointing to the previous root node, /// make that new node the root node, and return it. This increases the height by 1 /// and is the opposite of `pop_internal_level`. - pub fn push_internal_level( + pub(super) fn push_internal_level( &mut self, alloc: A, ) -> NodeRef, K, V, marker::Internal> { @@ -604,7 +604,7 @@ impl NodeRef { /// it will not invalidate other handles or references to the root node. /// /// Panics if there is no internal level, i.e., if the root node is a leaf. - pub fn pop_internal_level(&mut self, alloc: A) { + pub(super) fn pop_internal_level(&mut self, alloc: A) { assert!(self.height > 0); let top = self.node; @@ -628,18 +628,18 @@ impl NodeRef { /// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe /// because the return value cannot be used to destroy the root, and there /// cannot be other references to the tree. - pub fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { + pub(super) fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Slightly mutably borrows the owned root node. - pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { + pub(super) fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Irreversibly transitions to a reference that permits traversal and offers /// destructive methods and little else. - pub fn into_dying(self) -> NodeRef { + pub(super) fn into_dying(self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -651,7 +651,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// # Safety /// /// The returned handle has an unbound lifetime. - pub unsafe fn push_with_handle<'b>( + pub(super) unsafe fn push_with_handle<'b>( &mut self, key: K, val: V, @@ -672,7 +672,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key-value pair to the end of the node, and returns /// the mutable reference of the inserted value. - pub fn push(&mut self, key: K, val: V) -> *mut V { + pub(super) fn push(&mut self, key: K, val: V) -> *mut V { // SAFETY: The unbound handle is no longer accessible. unsafe { self.push_with_handle(key, val).into_val_mut() } } @@ -681,7 +681,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// Adds a key-value pair, and an edge to go to the right of that pair, /// to the end of the node. - pub fn push(&mut self, key: K, val: V, edge: Root) { + pub(super) fn push(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); let len = self.len_mut(); @@ -699,21 +699,21 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { impl NodeRef { /// Removes any static information asserting that this node is a `Leaf` node. - pub fn forget_type(self) -> NodeRef { + pub(super) fn forget_type(self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Removes any static information asserting that this node is an `Internal` node. - pub fn forget_type(self) -> NodeRef { + pub(super) fn forget_type(self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Checks whether a node is an `Internal` node or a `Leaf` node. - pub fn force( + pub(super) fn force( self, ) -> ForceResult< NodeRef, @@ -737,7 +737,9 @@ impl NodeRef { impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. - pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { + pub(super) unsafe fn cast_to_leaf_unchecked( + self, + ) -> NodeRef, K, V, marker::Leaf> { debug_assert!(self.height == 0); NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -757,7 +759,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// a child node, these represent the spaces where child pointers would go between the key-value /// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one /// to the left of the node, one between the two pairs, and one at the right of the node. -pub struct Handle { +pub(super) struct Handle { node: Node, idx: usize, _marker: PhantomData, @@ -774,12 +776,12 @@ impl Clone for Handle { impl Handle { /// Retrieves the node that contains the edge or key-value pair this handle points to. - pub fn into_node(self) -> Node { + pub(super) fn into_node(self) -> Node { self.node } /// Returns the position of this handle in the node. - pub fn idx(&self) -> usize { + pub(super) fn idx(&self) -> usize { self.idx } } @@ -787,17 +789,17 @@ impl Handle { impl Handle, marker::KV> { /// Creates a new handle to a key-value pair in `node`. /// Unsafe because the caller must ensure that `idx < node.len()`. - pub unsafe fn new_kv(node: NodeRef, idx: usize) -> Self { + pub(super) unsafe fn new_kv(node: NodeRef, idx: usize) -> Self { debug_assert!(idx < node.len()); Handle { node, idx, _marker: PhantomData } } - pub fn left_edge(self) -> Handle, marker::Edge> { + pub(super) fn left_edge(self) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node, self.idx) } } - pub fn right_edge(self) -> Handle, marker::Edge> { + pub(super) fn right_edge(self) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node, self.idx + 1) } } } @@ -815,7 +817,9 @@ impl Handle, HandleType> { /// Temporarily takes out another immutable handle on the same location. - pub fn reborrow(&self) -> Handle, K, V, NodeType>, HandleType> { + pub(super) fn reborrow( + &self, + ) -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type Handle { node: self.node.reborrow(), idx: self.idx, _marker: PhantomData } } @@ -827,7 +831,7 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// dangerous. /// /// For details, see `NodeRef::reborrow_mut`. - pub unsafe fn reborrow_mut( + pub(super) unsafe fn reborrow_mut( &mut self, ) -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type @@ -837,7 +841,9 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// Returns a dormant copy of this handle which can be reawakened later. /// /// See `DormantMutRef` for more details. - pub fn dormant(&self) -> Handle, HandleType> { + pub(super) fn dormant( + &self, + ) -> Handle, HandleType> { Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData } } } @@ -849,7 +855,9 @@ impl Handle(self) -> Handle, K, V, NodeType>, HandleType> { + pub(super) unsafe fn awaken<'a>( + self, + ) -> Handle, K, V, NodeType>, HandleType> { Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData } } } @@ -857,13 +865,15 @@ impl Handle Handle, marker::Edge> { /// Creates a new handle to an edge in `node`. /// Unsafe because the caller must ensure that `idx <= node.len()`. - pub unsafe fn new_edge(node: NodeRef, idx: usize) -> Self { + pub(super) unsafe fn new_edge(node: NodeRef, idx: usize) -> Self { debug_assert!(idx <= node.len()); Handle { node, idx, _marker: PhantomData } } - pub fn left_kv(self) -> Result, marker::KV>, Self> { + pub(super) fn left_kv( + self, + ) -> Result, marker::KV>, Self> { if self.idx > 0 { Ok(unsafe { Handle::new_kv(self.node, self.idx - 1) }) } else { @@ -871,7 +881,9 @@ impl Handle, mar } } - pub fn right_kv(self) -> Result, marker::KV>, Self> { + pub(super) fn right_kv( + self, + ) -> Result, marker::KV>, Self> { if self.idx < self.node.len() { Ok(unsafe { Handle::new_kv(self.node, self.idx) }) } else { @@ -880,7 +892,7 @@ impl Handle, mar } } -pub enum LeftOrRight { +pub(super) enum LeftOrRight { Left(T), Right(T), } @@ -1034,7 +1046,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// If the returned result is some `SplitResult`, the `left` field will be the root node. /// The returned pointer points to the inserted value, which in the case of `SplitResult` /// is in the `left` or `right` tree. - pub fn insert_recursing( + pub(super) fn insert_recursing( self, key: K, value: V, @@ -1078,7 +1090,7 @@ impl /// /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. - pub fn descend(self) -> NodeRef { + pub(super) fn descend(self) -> NodeRef { const { assert!(BorrowType::TRAVERSAL_PERMIT); } @@ -1097,7 +1109,7 @@ impl } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn into_kv(self) -> (&'a K, &'a V) { + pub(super) fn into_kv(self) -> (&'a K, &'a V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf(); let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() }; @@ -1107,17 +1119,17 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeTyp } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn key_mut(&mut self) -> &mut K { + pub(super) fn key_mut(&mut self) -> &mut K { unsafe { self.node.key_area_mut(self.idx).assume_init_mut() } } - pub fn into_val_mut(self) -> &'a mut V { + pub(super) fn into_val_mut(self) -> &'a mut V { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } - pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { + pub(super) fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; @@ -1127,13 +1139,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> } impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + pub(super) fn into_kv_valmut(self) -> (&'a K, &'a mut V) { unsafe { self.node.into_key_val_mut_at(self.idx) } } } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn kv_mut(&mut self) -> (&mut K, &mut V) { + pub(super) fn kv_mut(&mut self) -> (&mut K, &mut V) { debug_assert!(self.idx < self.node.len()); // We cannot call separate key and value methods, because calling the second one // invalidates the reference returned by the first. @@ -1146,7 +1158,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> } /// Replaces the key and value that the KV handle refers to. - pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) { + pub(super) fn replace_kv(&mut self, k: K, v: V) -> (K, V) { let (key, val) = self.kv_mut(); (mem::replace(key, k), mem::replace(val, v)) } @@ -1156,7 +1168,7 @@ impl Handle, marker::KV> /// Extracts the key and value that the KV handle refers to. /// # Safety /// The node that the handle refers to must not yet have been deallocated. - pub unsafe fn into_key_val(mut self) -> (K, V) { + pub(super) unsafe fn into_key_val(mut self) -> (K, V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.as_leaf_dying(); unsafe { @@ -1170,7 +1182,7 @@ impl Handle, marker::KV> /// # Safety /// The node that the handle refers to must not yet have been deallocated. #[inline] - pub unsafe fn drop_key_val(mut self) { + pub(super) unsafe fn drop_key_val(mut self) { // Run the destructor of the value even if the destructor of the key panics. struct Dropper<'a, T>(&'a mut MaybeUninit); impl Drop for Dropper<'_, T> { @@ -1229,7 +1241,10 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// - The key and value pointed to by this handle are extracted. /// - All the key-value pairs to the right of this handle are put into a newly /// allocated node. - pub fn split(mut self, alloc: A) -> SplitResult<'a, K, V, marker::Leaf> { + pub(super) fn split( + mut self, + alloc: A, + ) -> SplitResult<'a, K, V, marker::Leaf> { let mut new_node = LeafNode::new(alloc); let kv = self.split_leaf_data(&mut new_node); @@ -1240,7 +1255,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// Removes the key-value pair pointed to by this handle and returns it, along with the edge /// that the key-value pair collapsed into. - pub fn remove( + pub(super) fn remove( mut self, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { let old_len = self.node.len(); @@ -1261,7 +1276,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// - The key and value pointed to by this handle are extracted. /// - All the edges and key-value pairs to the right of this handle are put into /// a newly allocated node. - pub fn split( + pub(super) fn split( mut self, alloc: A, ) -> SplitResult<'a, K, V, marker::Internal> { @@ -1285,14 +1300,14 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// Represents a session for evaluating and performing a balancing operation /// around an internal key-value pair. -pub struct BalancingContext<'a, K, V> { +pub(super) struct BalancingContext<'a, K, V> { parent: Handle, K, V, marker::Internal>, marker::KV>, left_child: NodeRef, K, V, marker::LeafOrInternal>, right_child: NodeRef, K, V, marker::LeafOrInternal>, } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { - pub fn consider_for_balancing(self) -> BalancingContext<'a, K, V> { + pub(super) fn consider_for_balancing(self) -> BalancingContext<'a, K, V> { let self1 = unsafe { ptr::read(&self) }; let self2 = unsafe { ptr::read(&self) }; BalancingContext { @@ -1318,7 +1333,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// typically faster, since we only need to shift the node's N elements to /// the right, instead of shifting at least N of the sibling's elements to /// the left. - pub fn choose_parent_kv(self) -> Result>, Self> { + pub(super) fn choose_parent_kv(self) -> Result>, Self> { match unsafe { ptr::read(&self) }.ascend() { Ok(parent_edge) => match parent_edge.left_kv() { Ok(left_parent_kv) => Ok(LeftOrRight::Left(BalancingContext { @@ -1341,25 +1356,25 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { } impl<'a, K, V> BalancingContext<'a, K, V> { - pub fn left_child_len(&self) -> usize { + pub(super) fn left_child_len(&self) -> usize { self.left_child.len() } - pub fn right_child_len(&self) -> usize { + pub(super) fn right_child_len(&self) -> usize { self.right_child.len() } - pub fn into_left_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { + pub(super) fn into_left_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { self.left_child } - pub fn into_right_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { + pub(super) fn into_right_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { self.right_child } /// Returns whether merging is possible, i.e., whether there is enough room /// in a node to combine the central KV with both adjacent child nodes. - pub fn can_merge(&self) -> bool { + pub(super) fn can_merge(&self) -> bool { self.left_child.len() + 1 + self.right_child.len() <= CAPACITY } } @@ -1433,7 +1448,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// the left child node and returns the shrunk parent node. /// /// Panics unless we `.can_merge()`. - pub fn merge_tracking_parent( + pub(super) fn merge_tracking_parent( self, alloc: A, ) -> NodeRef, K, V, marker::Internal> { @@ -1444,7 +1459,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// the left child node and returns that child node. /// /// Panics unless we `.can_merge()`. - pub fn merge_tracking_child( + pub(super) fn merge_tracking_child( self, alloc: A, ) -> NodeRef, K, V, marker::LeafOrInternal> { @@ -1456,7 +1471,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// where the tracked child edge ended up, /// /// Panics unless we `.can_merge()`. - pub fn merge_tracking_child_edge( + pub(super) fn merge_tracking_child_edge( self, track_edge_idx: LeftOrRight, alloc: A, @@ -1479,7 +1494,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// of the parent, while pushing the old parent key-value pair into the right child. /// Returns a handle to the edge in the right child corresponding to where the original /// edge specified by `track_right_edge_idx` ended up. - pub fn steal_left( + pub(super) fn steal_left( mut self, track_right_edge_idx: usize, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { @@ -1491,7 +1506,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// of the parent, while pushing the old parent key-value pair onto the left child. /// Returns a handle to the edge in the left child specified by `track_left_edge_idx`, /// which didn't move. - pub fn steal_right( + pub(super) fn steal_right( mut self, track_left_edge_idx: usize, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { @@ -1500,7 +1515,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } /// This does stealing similar to `steal_left` but steals multiple elements at once. - pub fn bulk_steal_left(&mut self, count: usize) { + pub(super) fn bulk_steal_left(&mut self, count: usize) { assert!(count > 0); unsafe { let left_node = &mut self.left_child; @@ -1563,7 +1578,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } /// The symmetric clone of `bulk_steal_left`. - pub fn bulk_steal_right(&mut self, count: usize) { + pub(super) fn bulk_steal_right(&mut self, count: usize) { assert!(count > 0); unsafe { let left_node = &mut self.left_child; @@ -1628,7 +1643,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } impl Handle, marker::Edge> { - pub fn forget_node_type( + pub(super) fn forget_node_type( self, ) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node.forget_type(), self.idx) } @@ -1636,7 +1651,7 @@ impl Handle, marker::E } impl Handle, marker::Edge> { - pub fn forget_node_type( + pub(super) fn forget_node_type( self, ) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node.forget_type(), self.idx) } @@ -1644,7 +1659,7 @@ impl Handle, marke } impl Handle, marker::KV> { - pub fn forget_node_type( + pub(super) fn forget_node_type( self, ) -> Handle, marker::KV> { unsafe { Handle::new_kv(self.node.forget_type(), self.idx) } @@ -1653,7 +1668,7 @@ impl Handle, marker::K impl Handle, Type> { /// Checks whether the underlying node is an `Internal` node or a `Leaf` node. - pub fn force( + pub(super) fn force( self, ) -> ForceResult< Handle, Type>, @@ -1672,7 +1687,7 @@ impl Handle Handle, K, V, marker::LeafOrInternal>, Type> { /// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`. - pub unsafe fn cast_to_leaf_unchecked( + pub(super) unsafe fn cast_to_leaf_unchecked( self, ) -> Handle, K, V, marker::Leaf>, Type> { let node = unsafe { self.node.cast_to_leaf_unchecked() }; @@ -1683,7 +1698,7 @@ impl<'a, K, V, Type> Handle, K, V, marker::LeafOrInterna impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { /// Move the suffix after `self` from one node to another one. `right` must be empty. /// The first edge of `right` remains unchanged. - pub fn move_suffix( + pub(super) fn move_suffix( &mut self, right: &mut NodeRef, K, V, marker::LeafOrInternal>, ) { @@ -1726,13 +1741,13 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma } } -pub enum ForceResult { +pub(super) enum ForceResult { Leaf(Leaf), Internal(Internal), } /// Result of insertion, when a node needed to expand beyond its capacity. -pub struct SplitResult<'a, K, V, NodeType> { +pub(super) struct SplitResult<'a, K, V, NodeType> { // Altered node in existing tree with elements and edges that belong to the left of `kv`. pub left: NodeRef, K, V, NodeType>, // Some key and value that existed before and were split off, to be inserted elsewhere. @@ -1742,32 +1757,32 @@ pub struct SplitResult<'a, K, V, NodeType> { } impl<'a, K, V> SplitResult<'a, K, V, marker::Leaf> { - pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { + pub(super) fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() } } } impl<'a, K, V> SplitResult<'a, K, V, marker::Internal> { - pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { + pub(super) fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() } } } -pub mod marker { +pub(super) mod marker { use core::marker::PhantomData; - pub enum Leaf {} - pub enum Internal {} - pub enum LeafOrInternal {} + pub(crate) enum Leaf {} + pub(crate) enum Internal {} + pub(crate) enum LeafOrInternal {} - pub enum Owned {} - pub enum Dying {} - pub enum DormantMut {} - pub struct Immut<'a>(PhantomData<&'a ()>); - pub struct Mut<'a>(PhantomData<&'a mut ()>); - pub struct ValMut<'a>(PhantomData<&'a mut ()>); + pub(crate) enum Owned {} + pub(crate) enum Dying {} + pub(crate) enum DormantMut {} + pub(crate) struct Immut<'a>(PhantomData<&'a ()>); + pub(crate) struct Mut<'a>(PhantomData<&'a mut ()>); + pub(crate) struct ValMut<'a>(PhantomData<&'a mut ()>); - pub trait BorrowType { + pub(crate) trait BorrowType { /// If node references of this borrow type allow traversing to other /// nodes in the tree, this constant is set to `true`. It can be used /// for a compile-time assertion. @@ -1786,8 +1801,8 @@ pub mod marker { impl<'a> BorrowType for ValMut<'a> {} impl BorrowType for DormantMut {} - pub enum KV {} - pub enum Edge {} + pub(crate) enum KV {} + pub(crate) enum Edge {} } /// Inserts a value into a slice of initialized elements followed by one uninitialized element. diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 4d2fa0f09417..ecd009f11c71 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -6,7 +6,7 @@ use crate::string::String; impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { // Asserts that the back pointer in each reachable node points to its parent. - pub fn assert_back_pointers(self) { + pub(crate) fn assert_back_pointers(self) { if let ForceResult::Internal(node) = self.force() { for idx in 0..=node.len() { let edge = unsafe { Handle::new_edge(node, idx) }; @@ -20,7 +20,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> // Renders a multi-line display of the keys in order and in tree hierarchy, // picturing the tree growing sideways from its root on the left to its // leaves on the right. - pub fn dump_keys(self) -> String + pub(crate) fn dump_keys(self) -> String where K: Debug, { diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 56f2824b782b..9d870b86f34a 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -10,7 +10,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter /// the leaf edge corresponding to that former pair. It's possible this empties /// a root node that is internal, which the caller should pop from the map /// holding the tree. The caller should also decrement the map's length. - pub fn remove_kv_tracking( + pub(super) fn remove_kv_tracking( self, handle_emptied_internal_root: F, alloc: A, diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 22e015edac3d..96e5bf108024 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -8,7 +8,7 @@ use SearchResult::*; use super::node::ForceResult::*; use super::node::{Handle, NodeRef, marker}; -pub enum SearchBound { +pub(super) enum SearchBound { /// An inclusive bound to look for, just like `Bound::Included(T)`. Included(T), /// An exclusive bound to look for, just like `Bound::Excluded(T)`. @@ -20,7 +20,7 @@ pub enum SearchBound { } impl SearchBound { - pub fn from_range(range_bound: Bound) -> Self { + pub(super) fn from_range(range_bound: Bound) -> Self { match range_bound { Bound::Included(t) => Included(t), Bound::Excluded(t) => Excluded(t), @@ -29,12 +29,12 @@ impl SearchBound { } } -pub enum SearchResult { +pub(super) enum SearchResult { Found(Handle, marker::KV>), GoDown(Handle, marker::Edge>), } -pub enum IndexResult { +pub(super) enum IndexResult { KV(usize), Edge(usize), } @@ -46,7 +46,7 @@ impl NodeRef( + pub(super) fn search_tree( mut self, key: &Q, ) -> SearchResult @@ -80,7 +80,7 @@ impl NodeRef( + pub(super) fn search_tree_for_bifurcation<'r, Q: ?Sized, R>( mut self, range: &'r R, ) -> Result< @@ -156,7 +156,7 @@ impl NodeRef( + pub(super) fn find_lower_bound_edge<'r, Q>( self, bound: SearchBound<&'r Q>, ) -> (Handle, SearchBound<&'r Q>) @@ -170,7 +170,7 @@ impl NodeRef( + pub(super) fn find_upper_bound_edge<'r, Q>( self, bound: SearchBound<&'r Q>, ) -> (Handle, SearchBound<&'r Q>) @@ -192,7 +192,10 @@ impl NodeRef { /// /// The result is meaningful only if the tree is ordered by key, like the tree /// in a `BTreeMap` is. - pub fn search_node(self, key: &Q) -> SearchResult + pub(super) fn search_node( + self, + key: &Q, + ) -> SearchResult where Q: Ord, K: Borrow, diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index c188ed1da611..87a79e6cf3f9 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -8,7 +8,7 @@ use super::search::SearchResult::*; impl Root { /// Calculates the length of both trees that result from splitting up /// a given number of distinct key-value pairs. - pub fn calc_split_length( + pub(super) fn calc_split_length( total_num: usize, root_a: &Root, root_b: &Root, @@ -31,7 +31,11 @@ impl Root { /// and if the ordering of `Q` corresponds to that of `K`. /// If `self` respects all `BTreeMap` tree invariants, then both /// `self` and the returned tree will respect those invariants. - pub fn split_off(&mut self, key: &Q, alloc: A) -> Self + pub(super) fn split_off( + &mut self, + key: &Q, + alloc: A, + ) -> Self where K: Borrow, { diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index b7d4f8512a0f..aa19239f6c55 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -58,7 +58,7 @@ fn list_from(v: &[T]) -> LinkedList { v.iter().cloned().collect() } -pub fn check_links(list: &LinkedList) { +fn check_links(list: &LinkedList) { unsafe { let mut len = 0; let mut last_ptr: Option<&Node> = None; diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 1c33f8f60d82..299c8b8679e3 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -823,6 +823,7 @@ impl VecDeque { /// assert!(buf.capacity() >= 11); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_reserve")] #[track_caller] pub fn reserve(&mut self, additional: usize) { let new_cap = self.len.checked_add(additional).expect("capacity overflow"); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 28e4217e3039..0bb7c432cc35 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -88,6 +88,7 @@ #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] #![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] // // Library features: // tidy-alphabetical-start @@ -227,7 +228,7 @@ pub mod alloc; pub mod boxed; #[cfg(test)] mod boxed { - pub use std::boxed::Box; + pub(crate) use std::boxed::Box; } pub mod borrow; #[unstable(feature = "bstr", issue = "134915")] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index ad86bf4bf072..b80d1fc78894 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -97,7 +97,7 @@ impl RawVec { /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. #[must_use] - pub const fn new() -> Self { + pub(crate) const fn new() -> Self { Self::new_in(Global) } @@ -120,7 +120,7 @@ impl RawVec { #[must_use] #[inline] #[track_caller] - pub fn with_capacity(capacity: usize) -> Self { + pub(crate) fn with_capacity(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData } } @@ -129,7 +129,7 @@ impl RawVec { #[must_use] #[inline] #[track_caller] - pub fn with_capacity_zeroed(capacity: usize) -> Self { + pub(crate) fn with_capacity_zeroed(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT), _marker: PhantomData, @@ -172,7 +172,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[inline] - pub const fn new_in(alloc: A) -> Self { + pub(crate) const fn new_in(alloc: A) -> Self { Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } } @@ -181,7 +181,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -191,7 +191,7 @@ impl RawVec { /// Like `try_with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[inline] - pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + pub(crate) fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { match RawVecInner::try_with_capacity_in(capacity, alloc, T::LAYOUT) { Ok(inner) => Ok(Self { inner, _marker: PhantomData }), Err(e) => Err(e), @@ -203,7 +203,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { + pub(crate) fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -222,7 +222,7 @@ impl RawVec { /// /// Note, that the requested capacity and `self.capacity()` could differ, as /// an allocator could overallocate and return a greater memory block than requested. - pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { + pub(crate) unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { // Sanity-check one half of the safety requirement (we cannot check the other half). debug_assert!( len <= self.capacity(), @@ -247,7 +247,7 @@ impl RawVec { /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is /// guaranteed. #[inline] - pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { + pub(crate) unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { // SAFETY: Precondition passed to the caller unsafe { let ptr = ptr.cast(); @@ -265,7 +265,7 @@ impl RawVec { /// /// See [`RawVec::from_raw_parts_in`]. #[inline] - pub unsafe fn from_nonnull_in(ptr: NonNull, capacity: usize, alloc: A) -> Self { + pub(crate) unsafe fn from_nonnull_in(ptr: NonNull, capacity: usize, alloc: A) -> Self { // SAFETY: Precondition passed to the caller unsafe { let ptr = ptr.cast(); @@ -278,12 +278,12 @@ impl RawVec { /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. #[inline] - pub const fn ptr(&self) -> *mut T { + pub(crate) const fn ptr(&self) -> *mut T { self.inner.ptr() } #[inline] - pub fn non_null(&self) -> NonNull { + pub(crate) fn non_null(&self) -> NonNull { self.inner.non_null() } @@ -291,13 +291,13 @@ impl RawVec { /// /// This will always be `usize::MAX` if `T` is zero-sized. #[inline] - pub const fn capacity(&self) -> usize { + pub(crate) const fn capacity(&self) -> usize { self.inner.capacity(size_of::()) } /// Returns a shared reference to the allocator backing this `RawVec`. #[inline] - pub fn allocator(&self) -> &A { + pub(crate) fn allocator(&self) -> &A { self.inner.allocator() } @@ -323,7 +323,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - pub fn reserve(&mut self, len: usize, additional: usize) { + pub(crate) fn reserve(&mut self, len: usize, additional: usize) { self.inner.reserve(len, additional, T::LAYOUT) } @@ -332,12 +332,16 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline(never)] #[track_caller] - pub fn grow_one(&mut self) { + pub(crate) fn grow_one(&mut self) { self.inner.grow_one(T::LAYOUT) } /// 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> { + pub(crate) fn try_reserve( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TryReserveError> { self.inner.try_reserve(len, additional, T::LAYOUT) } @@ -360,12 +364,12 @@ impl RawVec { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] #[track_caller] - pub fn reserve_exact(&mut self, len: usize, additional: usize) { + pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) { self.inner.reserve_exact(len, additional, T::LAYOUT) } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. - pub fn try_reserve_exact( + pub(crate) fn try_reserve_exact( &mut self, len: usize, additional: usize, @@ -386,7 +390,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[track_caller] #[inline] - pub fn shrink_to_fit(&mut self, cap: usize) { + pub(crate) fn shrink_to_fit(&mut self, cap: usize) { self.inner.shrink_to_fit(cap, T::LAYOUT) } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index edc8d99f2f99..1cedead7aa24 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -85,6 +85,7 @@ use crate::vec::Vec; // functions are actually methods that are in `impl [T]` but not in // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test +#[allow(unreachable_pub)] // cfg(test) pub above pub(crate) mod hack { use core::alloc::Allocator; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8eee7cff2080..431e19e6ef1d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2740,7 +2740,7 @@ impl Weak { /// # Safety /// /// The pointer must have originated from the [`into_raw`] and must still own its potential - /// weak reference. + /// weak reference, and must point to a block of memory allocated by global allocator. /// /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this /// takes ownership of one weak reference currently represented as a raw pointer (the weak diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloc/src/testing/crash_test.rs index 684bac60d9a8..8e00e4f41e5d 100644 --- a/library/alloc/src/testing/crash_test.rs +++ b/library/alloc/src/testing/crash_test.rs @@ -11,7 +11,7 @@ use crate::fmt::Debug; // the `Debug` trait is the only thing we use from `crate /// Crash test dummies are identified and ordered by an id, so they can be used /// as keys in a BTreeMap. #[derive(Debug)] -pub struct CrashTestDummy { +pub(crate) struct CrashTestDummy { pub id: usize, cloned: AtomicUsize, dropped: AtomicUsize, @@ -20,7 +20,7 @@ pub struct CrashTestDummy { impl CrashTestDummy { /// Creates a crash test dummy design. The `id` determines order and equality of instances. - pub fn new(id: usize) -> CrashTestDummy { + pub(crate) fn new(id: usize) -> CrashTestDummy { CrashTestDummy { id, cloned: AtomicUsize::new(0), @@ -31,34 +31,34 @@ impl CrashTestDummy { /// Creates an instance of a crash test dummy that records what events it experiences /// and optionally panics. - pub fn spawn(&self, panic: Panic) -> Instance<'_> { + pub(crate) fn spawn(&self, panic: Panic) -> Instance<'_> { Instance { origin: self, panic } } /// Returns how many times instances of the dummy have been cloned. - pub fn cloned(&self) -> usize { + pub(crate) fn cloned(&self) -> usize { self.cloned.load(SeqCst) } /// Returns how many times instances of the dummy have been dropped. - pub fn dropped(&self) -> usize { + pub(crate) fn dropped(&self) -> usize { self.dropped.load(SeqCst) } /// Returns how many times instances of the dummy have had their `query` member invoked. - pub fn queried(&self) -> usize { + pub(crate) fn queried(&self) -> usize { self.queried.load(SeqCst) } } #[derive(Debug)] -pub struct Instance<'a> { +pub(crate) struct Instance<'a> { origin: &'a CrashTestDummy, panic: Panic, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Panic { +pub(crate) enum Panic { Never, InClone, InDrop, @@ -66,12 +66,12 @@ pub enum Panic { } impl Instance<'_> { - pub fn id(&self) -> usize { + pub(crate) fn id(&self) -> usize { self.origin.id } /// Some anonymous query, the result of which is already given. - pub fn query(&self, result: R) -> R { + pub(crate) fn query(&self, result: R) -> R { self.origin.queried.fetch_add(1, SeqCst); if self.panic == Panic::InQuery { panic!("panic in `query`"); diff --git a/library/alloc/src/testing/mod.rs b/library/alloc/src/testing/mod.rs index 7a094f8a5952..c8457daf93e5 100644 --- a/library/alloc/src/testing/mod.rs +++ b/library/alloc/src/testing/mod.rs @@ -1,3 +1,3 @@ -pub mod crash_test; -pub mod ord_chaos; -pub mod rng; +pub(crate) mod crash_test; +pub(crate) mod ord_chaos; +pub(crate) mod rng; diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloc/src/testing/ord_chaos.rs index 96ce7c157904..55e1ae5e3dea 100644 --- a/library/alloc/src/testing/ord_chaos.rs +++ b/library/alloc/src/testing/ord_chaos.rs @@ -4,7 +4,7 @@ use std::ptr; // Minimal type with an `Ord` implementation violating transitivity. #[derive(Debug)] -pub enum Cyclic3 { +pub(crate) enum Cyclic3 { A, B, C, @@ -37,16 +37,16 @@ impl Eq for Cyclic3 {} // Controls the ordering of values wrapped by `Governed`. #[derive(Debug)] -pub struct Governor { +pub(crate) struct Governor { flipped: Cell, } impl Governor { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Governor { flipped: Cell::new(false) } } - pub fn flip(&self) { + pub(crate) fn flip(&self) { self.flipped.set(!self.flipped.get()); } } @@ -55,7 +55,7 @@ impl Governor { // (assuming that `T` respects total order), but can suddenly be made to invert // that total order. #[derive(Debug)] -pub struct Governed<'a, T>(pub T, pub &'a Governor); +pub(crate) struct Governed<'a, T>(pub T, pub &'a Governor); impl PartialOrd for Governed<'_, T> { fn partial_cmp(&self, other: &Self) -> Option { diff --git a/library/alloc/src/testing/rng.rs b/library/alloc/src/testing/rng.rs index ecf543bee035..77d3348f38a5 100644 --- a/library/alloc/src/testing/rng.rs +++ b/library/alloc/src/testing/rng.rs @@ -1,5 +1,5 @@ /// XorShiftRng -pub struct DeterministicRng { +pub(crate) struct DeterministicRng { count: usize, x: u32, y: u32, @@ -8,12 +8,12 @@ pub struct DeterministicRng { } impl DeterministicRng { - pub fn new() -> Self { + pub(crate) fn new() -> Self { DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } } /// Guarantees that each returned number is unique. - pub fn next(&mut self) -> u32 { + pub(crate) fn next(&mut self) -> u32 { self.count += 1; assert!(self.count <= 70029); let x = self.x; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 54673ceb1da8..48afcf6e0645 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1267,6 +1267,7 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 79d094556c45..51687a3adcdd 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -116,7 +116,6 @@ mod c_char_definition { // Section 2.1 "Basic Types" in MSP430 Embedded Application Binary // Interface says "The char type is unsigned by default". // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf - // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). // powerpc/powerpc64: // - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC // Processor Supplement says ANSI C char is unsigned byte @@ -139,8 +138,10 @@ mod c_char_definition { // https://github.com/IBM/s390x-abi/releases/tag/v1.6.1 // - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char." // https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types - // Xtensa: - // - "The char type is unsigned by default for Xtensa processors." + // xtensa: + // Section 2.17.1 "Data Types and Alignment" of Xtensa LX Microprocessor Overview handbook + // says "`char` type is unsigned by default". + // https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf // // On the following operating systems, c_char is signed by default, regardless of architecture. // Darwin (macOS, iOS, etc.): @@ -150,11 +151,12 @@ mod c_char_definition { // Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char // are promoted to int as if from type signed char by default, unless the /J compilation // option is used." - // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types) - // L4RE: + // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types + // L4Re: // The kernel builds with -funsigned-char on all targets (but useserspace follows the // architecture defaults). As we only have a target for userspace apps so there are no - // special cases for L4RE below. + // special cases for L4Re below. + // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 if #[cfg(all( not(windows), not(target_vendor = "apple"), @@ -166,8 +168,8 @@ mod c_char_definition { target_arch = "msp430", target_arch = "powerpc", target_arch = "powerpc64", - target_arch = "riscv64", target_arch = "riscv32", + target_arch = "riscv64", target_arch = "s390x", target_arch = "xtensa", ) diff --git a/library/core/src/iter/sources/from_fn.rs b/library/core/src/iter/sources/from_fn.rs index 5f3d404d7dca..75cc0ffe3c77 100644 --- a/library/core/src/iter/sources/from_fn.rs +++ b/library/core/src/iter/sources/from_fn.rs @@ -1,7 +1,7 @@ use crate::fmt; -/// Creates a new iterator where each iteration calls the provided closure -/// `F: FnMut() -> Option`. +/// Creates an iterator with the provided closure +/// `F: FnMut() -> Option` as its `[next](Iterator::next)` method. /// /// The iterator will yield the `T`s returned from the closure. /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 859ac1632305..0061e33f9864 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1164,7 +1164,7 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. + /// This method is not magic; it is not provided by the hardware. /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. /// In particular, this method will not circumvent the [ABA Problem]. /// @@ -1203,6 +1203,125 @@ impl AtomicBool { } Err(prev) } + + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function + /// returned `Some(_)`, else `Err(previous_value)`. + /// + /// See also: [`update`](`AtomicBool::update`). + /// + /// Note: This may call the function multiple times if the value has been + /// changed from other threads in the meantime, as long as the function + /// returns `Some(_)`, but the function will have been applied only once to + /// the stored value. + /// + /// `try_update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicBool::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part of this + /// operation [`Relaxed`], and using [`Release`] makes the final successful + /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], + /// [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on `u8`. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let x = AtomicBool::new(false); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(false)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(false)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(true)); + /// assert_eq!(x.load(Ordering::SeqCst), false); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn try_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + f: impl FnMut(bool) -> Option, + ) -> Result { + // FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`; + // when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`. + self.fetch_update(set_order, fetch_order, f) + } + + /// Fetches the value, applies a function to it that it return a new value. + /// The new value is stored and the old value is returned. + /// + /// See also: [`try_update`](`AtomicBool::try_update`). + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, but the function will have been applied only once to the stored value. + /// + /// `update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicBool::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic operations on `u8`. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let x = AtomicBool::new(false); + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| !x), false); + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| !x), true); + /// assert_eq!(x.load(Ordering::SeqCst), false); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: impl FnMut(bool) -> bool, + ) -> bool { + let mut prev = self.load(fetch_order); + loop { + match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) { + Ok(x) => break x, + Err(next_prev) => prev = next_prev, + } + } + } } #[cfg(target_has_atomic_load_store = "ptr")] @@ -1684,7 +1803,7 @@ impl AtomicPtr { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. + /// This method is not magic; it is not provided by the hardware. /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. /// In particular, this method will not circumvent the [ABA Problem]. /// @@ -1732,6 +1851,137 @@ impl AtomicPtr { } Err(prev) } + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function + /// returned `Some(_)`, else `Err(previous_value)`. + /// + /// See also: [`update`](`AtomicPtr::update`). + /// + /// Note: This may call the function multiple times if the value has been + /// changed from other threads in the meantime, as long as the function + /// returns `Some(_)`, but the function will have been applied only once to + /// the stored value. + /// + /// `try_update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicPtr::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part of this + /// operation [`Relaxed`], and using [`Release`] makes the final successful + /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], + /// [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on pointers. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr: *mut _ = &mut 5; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let new: *mut _ = &mut 10; + /// assert_eq!(some_ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr)); + /// let result = some_ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| { + /// if x == ptr { + /// Some(new) + /// } else { + /// None + /// } + /// }); + /// assert_eq!(result, Ok(ptr)); + /// assert_eq!(some_ptr.load(Ordering::SeqCst), new); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn try_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + f: impl FnMut(*mut T) -> Option<*mut T>, + ) -> Result<*mut T, *mut T> { + // FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`; + // when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`. + self.fetch_update(set_order, fetch_order, f) + } + + /// Fetches the value, applies a function to it that it return a new value. + /// The new value is stored and the old value is returned. + /// + /// See also: [`try_update`](`AtomicPtr::try_update`). + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, but the function will have been applied only once to the stored value. + /// + /// `update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicPtr::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on pointers. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr: *mut _ = &mut 5; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let new: *mut _ = &mut 10; + /// let result = some_ptr.update(Ordering::SeqCst, Ordering::SeqCst, |_| new); + /// assert_eq!(result, ptr); + /// assert_eq!(some_ptr.load(Ordering::SeqCst), new); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: impl FnMut(*mut T) -> *mut T, + ) -> *mut T { + let mut prev = self.load(fetch_order); + loop { + match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) { + Ok(x) => break x, + Err(next_prev) => prev = next_prev, + } + } + } /// Offsets the pointer's address by adding `val` (in units of `T`), /// returning the previous pointer. @@ -2297,7 +2547,7 @@ macro_rules! atomic_int { $int_type, no = [ "**Note:** This function is only available on targets where `", - stringify!($int_type), "` has an alignment of ", $align, " bytes." + stringify!($atomic_type), "` has the same alignment as `", stringify!($int_type), "`." ], }] /// @@ -2875,7 +3125,7 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. + /// This method is not magic; it is not provided by the hardware. /// It is implemented in terms of #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] /// and suffers from the same drawbacks. @@ -2913,6 +3163,127 @@ macro_rules! atomic_int { Err(prev) } + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else + /// `Err(previous_value)`. + /// + #[doc = concat!("See also: [`update`](`", stringify!($atomic_type), "::update`).")] + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied + /// only once to the stored value. + /// + /// `try_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. + /// The first describes the required ordering for when the operation finally succeeds while the second + /// describes the required ordering for loads. These correspond to the success and failure orderings of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")] + /// respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic operations on + #[doc = concat!("[`", $s_int_type, "`].")] + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] + /// and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] + /// + #[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")] + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8)); + /// assert_eq!(x.load(Ordering::SeqCst), 9); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn try_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + f: impl FnMut($int_type) -> Option<$int_type>, + ) -> Result<$int_type, $int_type> { + // FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`; + // when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`. + self.fetch_update(set_order, fetch_order, f) + } + + /// Fetches the value, applies a function to it that it return a new value. + /// The new value is stored and the old value is returned. + /// + #[doc = concat!("See also: [`try_update`](`", stringify!($atomic_type), "::try_update`).")] + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, but the function will have been applied only once to the stored value. + /// + /// `update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. + /// The first describes the required ordering for when the operation finally succeeds while the second + /// describes the required ordering for loads. These correspond to the success and failure orderings of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")] + /// respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic operations on + #[doc = concat!("[`", $s_int_type, "`].")] + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] + /// and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] + /// + #[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")] + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 7); + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 8); + /// assert_eq!(x.load(Ordering::SeqCst), 9); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: impl FnMut($int_type) -> $int_type, + ) -> $int_type { + let mut prev = self.load(fetch_order); + loop { + match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) { + Ok(x) => break x, + Err(next_prev) => prev = next_prev, + } + } + } + /// Maximum with the current value. /// /// Finds the maximum of the current value and the argument `val`, and diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index 4f37e18a8cd7..d65f5ed61cfb 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -324,6 +324,20 @@ impl f128 { /// /// The precision of this function is non-deterministic. This means it varies by platform, /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 2.0_f128; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f128::EPSILON); + /// + /// assert_eq!(f128::powi(f128::NAN, 0), 1.0); + /// # } + /// ``` #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] @@ -347,8 +361,10 @@ impl f128 { /// /// let x = 2.0_f128; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// /// assert!(abs_difference <= f128::EPSILON); + /// + /// assert_eq!(f128::powf(1.0, f128::NAN), 1.0); + /// assert_eq!(f128::powf(f128::NAN, 0.0), 1.0); /// # } /// ``` #[inline] diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 42cd6e3fe2a5..5b0903bceabb 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -324,6 +324,20 @@ impl f16 { /// /// The precision of this function is non-deterministic. This means it varies by platform, /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 2.0_f16; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f16::EPSILON); + /// + /// assert_eq!(f16::powi(f16::NAN, 0), 1.0); + /// # } + /// ``` #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] @@ -347,8 +361,10 @@ impl f16 { /// /// let x = 2.0_f16; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// /// assert!(abs_difference <= f16::EPSILON); + /// + /// assert_eq!(f16::powf(1.0, f16::NAN), 1.0); + /// assert_eq!(f16::powf(f16::NAN, 0.0), 1.0); /// # } /// ``` #[inline] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 438d77b1626b..f9b6723788ae 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -306,8 +306,9 @@ impl f32 { /// ``` /// let x = 2.0_f32; /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// /// assert!(abs_difference <= f32::EPSILON); + /// + /// assert_eq!(f32::powi(f32::NAN, 0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -329,8 +330,10 @@ impl f32 { /// ``` /// let x = 2.0_f32; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// /// assert!(abs_difference <= f32::EPSILON); + /// + /// assert_eq!(f32::powf(1.0, f32::NAN), 1.0); + /// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 9bb4bfbab2a0..0de55a15d48e 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -306,8 +306,9 @@ impl f64 { /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f64::EPSILON); /// - /// assert!(abs_difference < 1e-10); + /// assert_eq!(f64::powi(f64::NAN, 0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -329,8 +330,10 @@ impl f64 { /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); + /// assert!(abs_difference <= f64::EPSILON); /// - /// assert!(abs_difference < 1e-10); + /// assert_eq!(f64::powf(1.0, f64::NAN), 1.0); + /// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 9ae03ac7fe07..a0abd439de02 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -4,8 +4,10 @@ use std::{env, fs}; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, llvm}; use crate::core::builder; -use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; -use crate::core::config::{DebuginfoLevel, TargetSelection}; +use crate::core::builder::{ + Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step, cargo_profile_var, +}; +use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection}; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{add_dylib_path, exe, t}; @@ -645,7 +647,7 @@ impl Step for Rustdoc { } // NOTE: Never modify the rustflags here, it breaks the build cache for other tools! - let cargo = prepare_tool_cargo( + let mut cargo = prepare_tool_cargo( builder, build_compiler, Mode::ToolRustc, @@ -656,6 +658,17 @@ impl Step for Rustdoc { features.as_slice(), ); + // rustdoc is performance sensitive, so apply LTO to it. + let lto = match builder.config.rust_lto { + RustcLto::Off => Some("off"), + RustcLto::Thin => Some("thin"), + RustcLto::Fat => Some("fat"), + RustcLto::ThinLocal => None, + }; + if let Some(lto) = lto { + cargo.env(cargo_profile_var("LTO", &builder.config), lto); + } + let _guard = builder.msg_tool( Kind::Build, Mode::ToolRustc, diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d418237a5689..1b413dcb07ef 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -10,7 +10,7 @@ use crate::core::config::flags::Color; use crate::utils::build_stamp; use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_args, linker_flags}; use crate::{ - BootstrapCommand, CLang, Compiler, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode, + BootstrapCommand, CLang, Compiler, Config, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode, TargetSelection, command, prepare_behaviour_dump_dir, t, }; @@ -484,10 +484,7 @@ impl Builder<'_> { build_stamp::clear_if_dirty(self, &my_out, &rustdoc); } - let profile_var = |name: &str| { - let profile = if self.config.rust_optimize.is_release() { "RELEASE" } else { "DEV" }; - format!("CARGO_PROFILE_{}_{}", profile, name) - }; + let profile_var = |name: &str| cargo_profile_var(name, &self.config); // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. @@ -1232,3 +1229,8 @@ impl Builder<'_> { } } } + +pub fn cargo_profile_var(name: &str, config: &Config) -> String { + let profile = if config.rust_optimize.is_release() { "RELEASE" } else { "DEV" }; + format!("CARGO_PROFILE_{}_{}", profile, name) +} diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index b293ac4f3515..04a00fde3ab4 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -11,7 +11,7 @@ use std::{env, fs}; use clap::ValueEnum; -pub use self::cargo::Cargo; +pub use self::cargo::{Cargo, cargo_profile_var}; pub use crate::Compiler; use crate::core::build_steps::{ check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, tool, vendor, diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index a3eb781f1476..6f62df28e494 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -340,4 +340,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Change the compiler profile to default to rust.debug-assertions = true", }, + ChangeInfo { + change_id: 135832, + severity: ChangeSeverity::Info, + summary: "Rustdoc now respects the value of rust.lto.", + }, ]; diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 01bac1498c24..3ef9c7ac35e9 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -30,8 +30,8 @@ pub fn output_result(cmd: &mut Command) -> Result { /// Finds the remote for rust-lang/rust. /// For example for these remotes it will return `upstream`. /// ```text -/// origin https://github.com/Nilstrieb/rust.git (fetch) -/// origin https://github.com/Nilstrieb/rust.git (push) +/// origin https://github.com/pietroalbani/rust.git (fetch) +/// origin https://github.com/pietroalbani/rust.git (push) /// upstream https://github.com/rust-lang/rust (fetch) /// upstream https://github.com/rust-lang/rust (push) /// ``` diff --git a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile index 6f33c6321818..2b8a3f829c60 100644 --- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile @@ -20,6 +20,7 @@ RUN yum upgrade -y && \ gcc-c++ \ git \ glibc-devel \ + glibc-static \ libedit-devel \ libstdc++-devel \ make \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 3a3962305825..0b4682ac32ba 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -21,6 +21,8 @@ RUN yum upgrade -y && \ git \ glibc-devel.i686 \ glibc-devel.x86_64 \ + glibc-static.i686 \ + glibc-static.x86_64 \ libedit-devel \ libstdc++-devel.i686 \ libstdc++-devel.x86_64 \ diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 7730d29d28f6..4c4863e2b4b3 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -86,7 +86,7 @@ envs: # builds) # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain # - # If you *want* these to happen however, temporarily uncomment it before triggering a try build. + # If you *want* these to happen however, temporarily comment it before triggering a try build. DIST_TRY_BUILD: 1 auto: diff --git a/src/tools/clippy/.github/deploy.sh b/src/tools/clippy/.github/deploy.sh index ea118a3b6fce..2f062799a360 100644 --- a/src/tools/clippy/.github/deploy.sh +++ b/src/tools/clippy/.github/deploy.sh @@ -45,6 +45,8 @@ if [[ -n $TAG_NAME ]]; then git add "$TAG_NAME" # Update the symlink git add stable + # Update the index.html file + git add index.html git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}" elif [[ $BETA = "true" ]]; then if git diff --exit-code --quiet -- beta/; then diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh index 701be6bd76d3..5a81b4112918 100755 --- a/src/tools/clippy/.github/driver.sh +++ b/src/tools/clippy/.github/driver.sh @@ -47,9 +47,9 @@ unset CARGO_MANIFEST_DIR # Run a lint and make sure it produces the expected output. It's also expected to exit with code 1 # FIXME: How to match the clippy invocation in compile-test.rs? -./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/box_default.rs 2>box_default.stderr && exit 1 -sed -e "/= help: for/d" box_default.stderr > normalized.stderr -diff -u normalized.stderr tests/ui/box_default.stderr +./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/string_to_string.rs 2>string_to_string.stderr && exit 1 +sed -e "/= help: for/d" string_to_string.stderr > normalized.stderr +diff -u normalized.stderr tests/ui/string_to_string.stderr # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same SYSROOT=$(rustc --print sysroot) diff --git a/src/tools/clippy/.github/workflows/clippy_changelog.yml b/src/tools/clippy/.github/workflows/clippy_changelog.yml new file mode 100644 index 000000000000..a2657bfea490 --- /dev/null +++ b/src/tools/clippy/.github/workflows/clippy_changelog.yml @@ -0,0 +1,59 @@ +name: Clippy changelog check + +on: + merge_group: + pull_request: + types: [opened, reopened, synchronize, edited] + +concurrency: + # For a given workflow, if we push to the same PR, cancel all previous builds on that PR. + # If the push is not attached to a PR, we will cancel all builds on the same branch. + group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + cancel-in-progress: true + +jobs: + changelog: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + + steps: + # Run + - name: Check Changelog + if: ${{ github.event_name == 'pull_request' }} + run: | + body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR_NUMBER" | \ + python -c "import sys, json; print(json.load(sys.stdin)['body'])") + output=$(awk '/^changelog:\s*\S/ && !/changelog: \[.*\]: your change/' <<< "$body" | sed "s/changelog:\s*//g") + if [ -z "$output" ]; then + echo "ERROR: pull request message must contain 'changelog: ...' with your changelog. Please add it." + exit 1 + else + echo "changelog: $output" + fi + env: + PYTHONIOENCODING: 'utf-8' + PR_NUMBER: '${{ github.event.number }}' + + # We need to have the "conclusion" job also on PR CI, to make it possible + # to add PRs to a merge queue. + conclusion_changelog: + needs: [ changelog ] + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + # + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml index dee7d028655e..c337a96bdac5 100644 --- a/src/tools/clippy/.github/workflows/clippy_mq.yml +++ b/src/tools/clippy/.github/workflows/clippy_mq.yml @@ -15,37 +15,7 @@ defaults: shell: bash jobs: - changelog: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.ref }} - # Unsetting this would make so that any malicious package could get our Github Token - persist-credentials: false - - # Run - - name: Check Changelog - run: | - MESSAGE=$(git log --format=%B -n 1) - PR=$(echo "$MESSAGE" | grep -o "#[0-9]*" | head -1 | sed -e 's/^#//') - body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR" | \ - python -c "import sys, json; print(json.load(sys.stdin)['body'])") - output=$(grep "^changelog:\s*\S" <<< "$body" | sed "s/changelog:\s*//g") || { - echo "ERROR: PR body must contain 'changelog: ...'" - exit 1 - } - if [[ "$output" = "none" ]]; then - echo "WARNING: changelog is 'none'" - else - echo "changelog: $output" - fi - env: - PYTHONIOENCODING: 'utf-8' base: - needs: changelog strategy: matrix: include: @@ -119,7 +89,6 @@ jobs: OS: ${{ runner.os }} metadata_collection: - needs: changelog runs-on: ubuntu-latest steps: @@ -138,7 +107,6 @@ jobs: run: cargo collect-metadata integration_build: - needs: changelog runs-on: ubuntu-latest steps: @@ -228,7 +196,7 @@ jobs: INTEGRATION: ${{ matrix.integration }} conclusion: - needs: [ changelog, base, metadata_collection, integration_build, integration ] + needs: [ base, metadata_collection, integration_build, integration ] # We need to ensure this job does *not* get skipped if its dependencies fail, # because a skipped job is considered a success by GitHub. So we have to # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml index 64966f1d1898..d487c7d94985 100644 --- a/src/tools/clippy/.github/workflows/lintcheck.yml +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -1,6 +1,12 @@ name: Lintcheck -on: pull_request +on: + pull_request: + paths-ignore: + - 'book/**' + - 'util/**' + - 'tests/**' + - '*.md' env: RUST_BACKTRACE: 1 diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index 69d00dc027e8..13902f78b541 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -27,7 +27,7 @@ jobs: - name: Install mdbook run: | mkdir mdbook - curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.34/mdbook-v0.4.34-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.43/mdbook-v0.4.43-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH # Run diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 1770e8095a01..bc42c07224e1 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5533,6 +5533,7 @@ Released 2018-09-13 [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs +[`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use @@ -5762,11 +5763,13 @@ Released 2018-09-13 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive +[`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid +[`manual_repeat_n`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain [`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic @@ -5904,6 +5907,7 @@ Released 2018-09-13 [`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty +[`non_std_lazy_statics`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_std_lazy_statics [`non_zero_suggestions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_zero_suggestions [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options @@ -6063,6 +6067,7 @@ Released 2018-09-13 [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count [`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next +[`sliced_string_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#sliced_string_as_bytes [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc @@ -6172,12 +6177,14 @@ Released 2018-09-13 [`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports +[`unnecessary_semicolon`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_semicolon [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern +[`unneeded_struct_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_struct_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns [`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable @@ -6216,6 +6223,7 @@ Released 2018-09-13 [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion [`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format [`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq +[`useless_nonzero_new_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_nonzero_new_unchecked [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 1f6c918fc6cc..3b33f7190638 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -199,7 +199,7 @@ currently. Between writing new lints, fixing issues, reviewing pull requests and responding to issues there may not always be enough time to stay on top of it all. -Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug], for example +Our highest priority is fixing [ICEs][I-ICE] and [bugs][C-bug], for example an ICE in a popular crate that many other crates depend on. We don't want Clippy to crash on your code and we want it to be as reliable as the suggestions from Rust compiler errors. @@ -213,8 +213,8 @@ Or rather: before the sync this should be addressed, e.g. by removing a lint again, so it doesn't hit beta/stable. [triage]: https://forge.rust-lang.org/release/triage-procedure.html -[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash -[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug +[I-ICE]: https://github.com/rust-lang/rust-clippy/labels/I-ICE +[C-bug]: https://github.com/rust-lang/rust-clippy/labels/C-bug [p-low]: https://github.com/rust-lang/rust-clippy/labels/P-low [p-medium]: https://github.com/rust-lang/rust-clippy/labels/P-medium [p-high]: https://github.com/rust-lang/rust-clippy/labels/P-high diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index efa59fecc0e8..c9e4f15afbf8 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT OR Apache-2.0" keywords = ["clippy", "lint", "plugin"] categories = ["development-tools", "development-tools::cargo-plugins"] build = "build.rs" -edition = "2021" +edition = "2024" publish = false [[bin]] diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index cb3a22d4288f..32c1d33e2ed3 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -159,11 +159,11 @@ line. (You can swap `clippy::all` with the specific lint category you are target You can add options to your code to `allow`/`warn`/`deny` Clippy lints: * the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`). - Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html). + Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html). * all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`, - `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive - lints prone to false positives. + `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive + lints prone to false positives. * only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.) diff --git a/src/tools/clippy/book/book.toml b/src/tools/clippy/book/book.toml index 93b6641f7e1e..c918aadf83c4 100644 --- a/src/tools/clippy/book/book.toml +++ b/src/tools/clippy/book/book.toml @@ -6,7 +6,7 @@ src = "src" title = "Clippy Documentation" [rust] -edition = "2018" +edition = "2024" [output.html] edit-url-template = "https://github.com/rust-lang/rust-clippy/edit/master/book/{path}" diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index c07568697d02..c26ad319f4f5 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -299,10 +299,11 @@ This is good, because it makes writing this particular lint less complicated. We have to make this decision with every new Clippy lint. It boils down to using either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. -In short, the `EarlyLintPass` runs before type checking and -[HIR](https://rustc-dev-guide.rust-lang.org/hir.html) lowering and the `LateLintPass` -has access to type information. Consider using the `LateLintPass` unless you need -something specific from the `EarlyLintPass`. +`EarlyLintPass` runs before type checking and +[HIR](https://rustc-dev-guide.rust-lang.org/hir.html) lowering, while `LateLintPass` +runs after these stages, providing access to type information. The `cargo dev new_lint` command +defaults to the recommended `LateLintPass`, but you can specify `--pass=early` if your lint +only needs AST level analysis. Since we don't need type information for checking the function name, we used `--pass=early` when running the new lint automation and all the imports were @@ -537,7 +538,7 @@ via `Tools -> Clippy` and you should see the generated code in the output below. If the command was executed successfully, you can copy the code over to where you are implementing your lint. -[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55 +[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55 ## Print HIR lint @@ -552,7 +553,7 @@ attribute to expressions you often need to enable _Clippy_. [_High-Level Intermediate Representation (HIR)_]: https://rustc-dev-guide.rust-lang.org/hir.html -[print_hir_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=daf14db3a7f39ca467cd1b86c34b9afb +[print_hir_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=daf14db3a7f39ca467cd1b86c34b9afb ## Documentation diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md index c354e8914f5d..b44ad80a25cc 100644 --- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md +++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md @@ -265,10 +265,10 @@ functions to deal with macros: ``` [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html -[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html -[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.pat_ty [paths]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/paths/index.html diff --git a/src/tools/clippy/book/src/development/defining_lints.md b/src/tools/clippy/book/src/development/defining_lints.md index ceabb255e2d0..169cecd7d11d 100644 --- a/src/tools/clippy/book/src/development/defining_lints.md +++ b/src/tools/clippy/book/src/development/defining_lints.md @@ -139,10 +139,10 @@ Untracked files: ``` -## The `define_clippy_lints` macro +## The `declare_clippy_lint` macro After `cargo dev new_lint`, you should see a macro with the name -`define_clippy_lints`. It will be in the same file if you defined a standalone +`declare_clippy_lint`. It will be in the same file if you defined a standalone lint, and it will be in `mod.rs` if you defined a type-specific lint. The macro looks something like this: diff --git a/src/tools/clippy/book/src/development/infrastructure/release.md b/src/tools/clippy/book/src/development/infrastructure/release.md index 20b870eb69a8..8b080c099b81 100644 --- a/src/tools/clippy/book/src/development/infrastructure/release.md +++ b/src/tools/clippy/book/src/development/infrastructure/release.md @@ -96,9 +96,9 @@ git tag rust-1.XX.0 # XX should be exchanged with the correspondin git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote ``` -After this, the release should be available on the Clippy [release page]. +After this, the release should be available on the Clippy [tags page]. -[release page]: https://github.com/rust-lang/rust-clippy/releases +[tags page]: https://github.com/rust-lang/rust-clippy/tags ## Publish `clippy_utils` diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 181e794e6e46..b8f9fff9c613 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -750,6 +750,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_pattern_char_comparison`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison) * [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) +* [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n) * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) @@ -762,11 +763,13 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) * [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) * [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) +* [`non_std_lazy_statics`](https://rust-lang.github.io/rust-clippy/master/index.html#non_std_lazy_statics) * [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) * [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) * [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) * [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) * [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) +* [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push) * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index c761e207c6b6..e473a5839402 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -3,7 +3,7 @@ name = "clippy_config" # begin autogenerated version version = "0.1.86" # end autogenerated version -edition = "2021" +edition = "2024" publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index c616589c56e0..552141476f3a 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -619,6 +619,7 @@ define_Conf! { manual_pattern_char_comparison, manual_range_contains, manual_rem_euclid, + manual_repeat_n, manual_retain, manual_split_once, manual_str_repeat, @@ -631,11 +632,13 @@ define_Conf! { mem_replace_with_default, missing_const_for_fn, needless_borrow, + non_std_lazy_statics, option_as_ref_deref, option_map_unwrap_or, ptr_as_ptr, redundant_field_names, redundant_static_lifetimes, + same_item_push, seek_from_current, seek_rewind, transmute_ptr_to_ref, diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index d3a103eaf4c6..47b7b3758613 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -2,7 +2,7 @@ name = "clippy_dev" description = "Clippy developer tooling" version = "0.0.1" -edition = "2021" +edition = "2024" [dependencies] aho-corasick = "1.0" diff --git a/src/tools/clippy/clippy_dev/src/setup/intellij.rs b/src/tools/clippy/clippy_dev/src/setup/intellij.rs index a7138f36a4ef..c56811ee0a01 100644 --- a/src/tools/clippy/clippy_dev/src/setup/intellij.rs +++ b/src/tools/clippy/clippy_dev/src/setup/intellij.rs @@ -62,7 +62,7 @@ fn check_and_get_rustc_dir(rustc_path: &str) -> Result { eprintln!("error: unable to get the absolute path of rustc ({err})"); return Err(()); }, - }; + } } let path = path.join("compiler"); diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 612d1c0ae139..fc0780f89a7f 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -842,7 +842,7 @@ fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { Ok(file) => drop(file), Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, Err(e) => panic_file(e, new_name, "create"), - }; + } match fs::rename(old_name, new_name) { Ok(()) => true, Err(e) => { diff --git a/src/tools/clippy/clippy_dummy/Cargo.toml b/src/tools/clippy/clippy_dummy/Cargo.toml index c206a1eb07b5..61bdd421c764 100644 --- a/src/tools/clippy/clippy_dummy/Cargo.toml +++ b/src/tools/clippy/clippy_dummy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_dummy" # rename to clippy before publishing version = "0.0.303" -edition = "2018" +edition = "2024" readme = "crates-readme.md" description = "A bunch of helpful lints to avoid common pitfalls in Rust." build = 'build.rs' diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index b575ac1bf4cc..c62a7ec783b6 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["clippy", "lint", "plugin"] -edition = "2021" +edition = "2024" [dependencies] arrayvec = { version = "0.7", default-features = false } diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 380b094d017e..0389223c3e0f 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -445,8 +445,8 @@ fn convert_assoc_item_kind(value: AssocItemKind) -> SourceItemOrderingTraitAssoc #[allow(clippy::enum_glob_use)] // Very local glob use for legibility. use SourceItemOrderingTraitAssocItemKind::*; match value { - AssocItemKind::Const { .. } => Const, - AssocItemKind::Type { .. } => Type, + AssocItemKind::Const => Const, + AssocItemKind::Type => Type, AssocItemKind::Fn { .. } => Fn, } } diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index c8dd77d9578d..c01155ca86e0 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -257,7 +257,7 @@ fn build_sugg<'tcx>( // The receiver may have been a value type, so we need to add an `&` to // be sure the argument to clone_from will be a reference. arg_sugg = arg_sugg.addr(); - }; + } format!("{receiver_sugg}.clone_from({arg_sugg})") }, diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs index 8c91c65eaf76..3e4bcfbfc190 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -60,7 +60,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute]) } outer_attr_kind.insert(kind); }, - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index 96a2b1614646..60371dcd7715 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -161,6 +161,15 @@ declare_clippy_lint! { /// [dependencies] /// regex = "*" /// ``` + /// Use instead: + /// ```toml + /// [dependencies] + /// # allow patch updates, but not minor or major version changes + /// some_crate_1 = "~1.2.3" + /// + /// # pin the version to a specific version + /// some_crate_2 = "=1.2.3" + /// ``` #[clippy::version = "1.32.0"] pub WILDCARD_DEPENDENCIES, cargo, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs index 3cf4a43b0d4c..504d0a267e47 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs @@ -84,6 +84,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca diag .note("`usize` and `isize` may be as small as 16 bits on some platforms") .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types"); - }; + } }); } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 4be53ace6871..45045e58ac75 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -205,7 +205,7 @@ fn expr_muldiv_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { // - uncertain if there are any uncertain values (because they could be negative or positive), Sign::Uncertain => return Sign::Uncertain, Sign::ZeroOrPositive => (), - }; + } } // A mul/div is: @@ -236,7 +236,7 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { // - uncertain if there are any uncertain values (because they could be negative or positive), Sign::Uncertain => return Sign::Uncertain, Sign::ZeroOrPositive => positive_count += 1, - }; + } } // A sum is: diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 364f5c7dc7a0..1edfde974227 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -273,7 +273,7 @@ fn get_types_from_cast<'a>( }, _ => {}, } - }; + } None } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 87e546fbf014..86bcf8edd578 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -142,6 +142,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_NESTED_REFDEFS_INFO, + crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO, crate::doc::EMPTY_DOCS_INFO, crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, @@ -335,6 +336,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::matches::INFALLIBLE_DESTRUCTURING_MATCH_INFO, crate::matches::MANUAL_FILTER_INFO, crate::matches::MANUAL_MAP_INFO, + crate::matches::MANUAL_OK_ERR_INFO, crate::matches::MANUAL_UNWRAP_OR_INFO, crate::matches::MATCH_AS_REF_INFO, crate::matches::MATCH_BOOL_INFO, @@ -419,6 +421,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, + crate::methods::MANUAL_REPEAT_N_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, crate::methods::MANUAL_STR_REPEAT_INFO, @@ -466,6 +469,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, crate::methods::SKIP_WHILE_NEXT_INFO, + crate::methods::SLICED_STRING_AS_BYTES_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, crate::methods::STRING_LIT_CHARS_ANY_INFO, @@ -495,6 +499,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNWRAP_OR_DEFAULT_INFO, crate::methods::UNWRAP_USED_INFO, crate::methods::USELESS_ASREF_INFO, + crate::methods::USELESS_NONZERO_NEW_UNCHECKED_INFO, crate::methods::VEC_RESIZE_TO_ZERO_INFO, crate::methods::VERBOSE_FILE_READS_INFO, crate::methods::WAKER_CLONE_WAKE_INFO, @@ -572,6 +577,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::non_expressive_names::SIMILAR_NAMES_INFO, crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO, crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO, + crate::non_std_lazy_statics::NON_STD_LAZY_STATICS_INFO, crate::non_zero_suggestions::NON_ZERO_SUGGESTIONS_INFO, crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO, crate::octal_escapes::OCTAL_ESCAPES_INFO, @@ -753,8 +759,10 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, + crate::unnecessary_semicolon::UNNECESSARY_SEMICOLON_INFO, crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO, crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO, + crate::unneeded_struct_pattern::UNNEEDED_STRUCT_PATTERN_INFO, crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO, crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO, crate::unused_async::UNUSED_ASYNC_INFO, 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 33a97222b8f8..bbd5dc15542d 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 @@ -80,6 +80,6 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { String::new(), Applicability::MachineApplicable, ); - }; + } } } 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 c04a73c890f0..ca3eaae7b85f 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -223,19 +223,17 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { } fn visit_pat(&mut self, pat: &'tcx Pat<'_>) { - match pat.kind { - PatKind::Expr(&PatExpr { - hir_id, - kind: PatExprKind::Lit { lit, .. }, - .. - }) => { - let ty = self.cx.typeck_results().node_type(hir_id); - self.check_lit(lit, ty, hir_id); - return; - }, - _ => {}, + if let PatKind::Expr(&PatExpr { + hir_id, + kind: PatExprKind::Lit { lit, .. }, + .. + }) = pat.kind + { + let ty = self.cx.typeck_results().node_type(hir_id); + self.check_lit(lit, ty, hir_id); + return; } - walk_pat(self, pat) + walk_pat(self, pat); } fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index f5589d8f8e25..123e358d7c3d 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -331,7 +331,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { deref_count += 1; }, None => break None, - }; + } }; let use_node = use_cx.use_node(cx); diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs index f9e4a43c0e7a..2577324f23df 100644 --- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs +++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs @@ -1,11 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use itertools::Itertools; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_span::{BytePos, Span}; +use std::cmp::Ordering; use std::ops::Range; -use super::DOC_LAZY_CONTINUATION; +use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS}; fn map_container_to_text(c: &super::Container) -> &'static str { match c { @@ -28,12 +29,57 @@ pub(super) fn check( return; } + // Blockquote let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count(); let blockquote_level = containers .iter() .filter(|c| matches!(c, super::Container::Blockquote)) .count(); - let lcount = doc[range.clone()].chars().filter(|c| *c == ' ').count(); + if ccount < blockquote_level { + span_lint_and_then( + cx, + DOC_LAZY_CONTINUATION, + span, + "doc quote line without `>` marker", + |diag| { + let mut doc_start_range = &doc[range]; + let mut suggested = String::new(); + for c in containers { + let text = map_container_to_text(c); + if doc_start_range.starts_with(text) { + doc_start_range = &doc_start_range[text.len()..]; + span = span.with_lo( + span.lo() + BytePos(u32::try_from(text.len()).expect("text is not 2**32 or bigger")), + ); + } else if matches!(c, super::Container::Blockquote) + && let Some(i) = doc_start_range.find('>') + { + doc_start_range = &doc_start_range[i + 1..]; + span = span + .with_lo(span.lo() + BytePos(u32::try_from(i).expect("text is not 2**32 or bigger") + 1)); + } else { + suggested.push_str(text); + } + } + diag.span_suggestion_verbose( + span, + "add markers to start of line", + suggested, + Applicability::MachineApplicable, + ); + diag.help("if this not intended to be a quote at all, escape it with `\\>`"); + }, + ); + return; + } + + if ccount != 0 && blockquote_level != 0 { + // If this doc is a blockquote, we don't go further. + return; + } + + // List + let leading_spaces = doc[range].chars().filter(|c| *c == ' ').count(); let list_indentation = containers .iter() .map(|c| { @@ -44,50 +90,36 @@ pub(super) fn check( } }) .sum(); - if ccount < blockquote_level || lcount < list_indentation { - let msg = if ccount < blockquote_level { - "doc quote line without `>` marker" - } else { - "doc list item without indentation" - }; - span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { - if ccount == 0 && blockquote_level == 0 { + match leading_spaces.cmp(&list_indentation) { + Ordering::Less => span_lint_and_then( + cx, + DOC_LAZY_CONTINUATION, + span, + "doc list item without indentation", + |diag| { // simpler suggestion style for indentation - let indent = list_indentation - lcount; + let indent = list_indentation - leading_spaces; diag.span_suggestion_verbose( span.shrink_to_hi(), "indent this line", - std::iter::repeat(" ").take(indent).join(""), + std::iter::repeat_n(" ", indent).join(""), Applicability::MaybeIncorrect, ); diag.help("if this is supposed to be its own paragraph, add a blank line"); - return; - } - let mut doc_start_range = &doc[range]; - let mut suggested = String::new(); - for c in containers { - let text = map_container_to_text(c); - if doc_start_range.starts_with(text) { - doc_start_range = &doc_start_range[text.len()..]; - span = span - .with_lo(span.lo() + BytePos(u32::try_from(text.len()).expect("text is not 2**32 or bigger"))); - } else if matches!(c, super::Container::Blockquote) - && let Some(i) = doc_start_range.find('>') - { - doc_start_range = &doc_start_range[i + 1..]; - span = - span.with_lo(span.lo() + BytePos(u32::try_from(i).expect("text is not 2**32 or bigger") + 1)); - } else { - suggested.push_str(text); - } - } - diag.span_suggestion_verbose( + }, + ), + Ordering::Greater => { + let sugg = std::iter::repeat_n(" ", list_indentation).join(""); + span_lint_and_sugg( + cx, + DOC_OVERINDENTED_LIST_ITEMS, span, - "add markers to start of line", - suggested, - Applicability::MachineApplicable, + "doc list item overindented", + format!("try using `{sugg}` ({list_indentation} spaces)"), + sugg, + Applicability::MaybeIncorrect, ); - diag.help("if this not intended to be a quote at all, escape it with `\\>`"); - }); + }, + Ordering::Equal => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 7561a6cf2a78..15530c3dbc50 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -428,6 +428,39 @@ declare_clippy_lint! { "require every line of a paragraph to be indented and marked" } +declare_clippy_lint! { + /// ### What it does + /// + /// Detects overindented list items in doc comments where the continuation + /// lines are indented more than necessary. + /// + /// ### Why is this bad? + /// + /// Overindented list items in doc comments can lead to inconsistent and + /// poorly formatted documentation when rendered. Excessive indentation may + /// cause the text to be misinterpreted as a nested list item or code block, + /// affecting readability and the overall structure of the documentation. + /// + /// ### Example + /// + /// ```no_run + /// /// - This is the first item in a list + /// /// and this line is overindented. + /// # fn foo() {} + /// ``` + /// + /// Fixes this into: + /// ```no_run + /// /// - This is the first item in a list + /// /// and this line is overindented. + /// # fn foo() {} + /// ``` + #[clippy::version = "1.80.0"] + pub DOC_OVERINDENTED_LIST_ITEMS, + style, + "ensure list items are not overindented" +} + declare_clippy_lint! { /// ### What it does /// Checks if the first paragraph in the documentation of items listed in the module page is too long. @@ -617,6 +650,7 @@ impl_lint_pass!(Documentation => [ SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, DOC_LAZY_CONTINUATION, + DOC_OVERINDENTED_LIST_ITEMS, EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, TOO_LONG_FIRST_DOC_PARAGRAPH, diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index e9e9d00907ea..a090a987d4fc 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { var.span, "C-like enum variant discriminant is not portable to 32-bit targets", ); - }; + } } } } diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 57a30de7ad14..52b699274bbb 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -3,7 +3,9 @@ use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; use clippy_utils::ty::get_type_diagnostic_name; use clippy_utils::usage::{local_used_after_expr, local_used_in}; -use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id}; +use clippy_utils::{ + get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id, +}; use rustc_errors::Applicability; use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; @@ -101,19 +103,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx }; if body.value.span.from_expansion() { - if body.params.is_empty() { - if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) { - // replace `|| vec![]` with `Vec::new` - span_lint_and_sugg( - cx, - REDUNDANT_CLOSURE, - expr.span, - "redundant closure", - "replace the closure with `Vec::new`", - "std::vec::Vec::new".into(), - Applicability::MachineApplicable, - ); - } + if body.params.is_empty() + && let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) + { + let vec_crate = if is_no_std_crate(cx) { "alloc" } else { "std" }; + // replace `|| vec![]` with `Vec::new` + span_lint_and_sugg( + cx, + REDUNDANT_CLOSURE, + expr.span, + "redundant closure", + "replace the closure with `Vec::new`", + format!("{vec_crate}::vec::Vec::new"), + Applicability::MachineApplicable, + ); } // skip `foo(|| macro!())` return; 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 688979311c89..cdbfe7af8f9d 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 @@ -183,7 +183,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .collect() }; self.emit_sugg(spans, msg, help); - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs index 05e341e06fde..752dbc0db4db 100644 --- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs @@ -45,7 +45,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: for param in generics.params { if param.is_impl_trait() { report(cx, param, generics); - }; + } } } } 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 1a01f5f885c3..90d3db2700fa 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -160,7 +160,7 @@ fn check_needless_must_use( && !is_must_use_ty(cx, future_ty) { return; - }; + } } span_lint_and_help( 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 dd5908553e59..41d2b18803d9 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -120,7 +120,7 @@ fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, B let ecx = ConstEvalCtxt::new(cx); if let Some(Constant::Int(c)) = ecx.eval(r) { return Some((c, op.node, l)); - }; + } if let Some(Constant::Int(c)) = ecx.eval(l) { return Some((c, invert_op(op.node)?, r)); } 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 37481dc7feb7..152d506a7c00 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -350,7 +350,7 @@ fn check_with_condition<'tcx>( if cx.typeck_results().expr_ty(cond_left).is_signed() { } else { print_lint_and_sugg(cx, var_name, expr); - }; + } } }, ExprKind::Path(QPath::TypeRelative(_, name)) => { diff --git a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs index 5131f5b7269b..b1cb6da9475b 100644 --- a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs +++ b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs @@ -65,6 +65,6 @@ impl LateLintPass<'_> for IterOverHashType { expr.span, "iteration over unordered hash-based type", ); - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index 2d2438514cc9..34ded6c65009 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -41,6 +41,6 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped { Some(ty.span.with_lo(local.pat.span.hi())), "remove the explicit type `_` declaration", ); - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index fad6f9d08803..4b700673d0f8 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -279,6 +279,7 @@ mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; mod non_send_fields_in_send_ty; +mod non_std_lazy_statics; mod non_zero_suggestions; mod nonstandard_macro_braces; mod octal_escapes; @@ -372,8 +373,10 @@ mod unnecessary_literal_bound; mod unnecessary_map_on_constructor; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; +mod unnecessary_semicolon; mod unnecessary_struct_initialization; mod unnecessary_wraps; +mod unneeded_struct_pattern; mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_async; @@ -680,7 +683,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unit_types::UnitTypes)); store.register_late_pass(move |_| Box::new(loops::Loops::new(conf))); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::new(lifetimes::Lifetimes)); + store.register_late_pass(move |_| Box::new(lifetimes::Lifetimes::new(conf))); store.register_late_pass(|_| Box::new(entry::HashMapPass)); store.register_late_pass(|_| Box::new(minmax::MinMaxPass)); store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv)); @@ -970,5 +973,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp)); store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)); store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf))); + store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern)); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index e6761ea5c67c..c9ab0beb5dfa 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -1,4 +1,6 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::trait_ref_of_method; use itertools::Itertools; use rustc_ast::visit::{try_visit, walk_list}; @@ -20,7 +22,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, kw}; @@ -91,7 +93,19 @@ declare_clippy_lint! { "unused lifetimes in function definitions" } -declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); +pub struct Lifetimes { + msrv: Msrv, +} + +impl Lifetimes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { @@ -102,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { .. } = item.kind { - check_fn_inner(cx, sig, Some(id), None, generics, item.span, true); + check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, &self.msrv); } else if let ItemKind::Impl(impl_) = item.kind { if !item.span.from_expansion() { report_extra_impl_lifetimes(cx, impl_); @@ -121,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { item.generics, item.span, report_extra_lifetimes, + &self.msrv, ); } } @@ -131,11 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { TraitFn::Required(sig) => (None, Some(sig)), TraitFn::Provided(id) => (Some(id), None), }; - check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true); + check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true, &self.msrv); } } + + extract_msrv_attr!(LateContext); } +#[allow(clippy::too_many_arguments)] fn check_fn_inner<'tcx>( cx: &LateContext<'tcx>, sig: &'tcx FnSig<'_>, @@ -144,6 +162,7 @@ fn check_fn_inner<'tcx>( generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, + msrv: &Msrv, ) { if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) { return; @@ -195,7 +214,7 @@ fn check_fn_inner<'tcx>( } } - if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) { + if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params, msrv) { if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) { return; } @@ -216,6 +235,7 @@ fn could_use_elision<'tcx>( body: Option, trait_sig: Option<&[Ident]>, named_generics: &'tcx [GenericParam<'_>], + msrv: &Msrv, ) -> Option<(Vec, Vec)> { // There are two scenarios where elision works: // * no output references, all input references have different LT @@ -249,17 +269,17 @@ fn could_use_elision<'tcx>( let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; - if let Some(trait_sig) = trait_sig { - if explicit_self_type(cx, func, trait_sig.first().copied()) { - return None; - } + if let Some(trait_sig) = trait_sig + && non_elidable_self_type(cx, func, trait_sig.first().copied(), msrv) + { + return None; } if let Some(body_id) = body { let body = cx.tcx.hir().body(body_id); let first_ident = body.params.first().and_then(|param| param.pat.simple_ident()); - if explicit_self_type(cx, func, first_ident) { + if non_elidable_self_type(cx, func, first_ident, msrv) { return None; } @@ -332,9 +352,15 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { - if let Some(ident) = ident +// elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064 +fn non_elidable_self_type<'tcx>( + cx: &LateContext<'tcx>, + func: &FnDecl<'tcx>, + ident: Option, + msrv: &Msrv, +) -> bool { + if !msrv.meets(msrvs::EXPLICIT_SELF_TYPE_ELISION) + && let Some(ident) = ident && ident.name == kw::SelfLower && !func.implicit_self.has_implicit_self() && let Some(self_ty) = func.inputs.first() @@ -488,11 +514,13 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ false } +#[allow(clippy::struct_excessive_bools)] struct Usage { lifetime: Lifetime, in_where_predicate: bool, in_bounded_ty: bool, in_generics_arg: bool, + lifetime_elision_impossible: bool, } struct LifetimeChecker<'cx, 'tcx, F> { @@ -501,6 +529,7 @@ struct LifetimeChecker<'cx, 'tcx, F> { where_predicate_depth: usize, bounded_ty_depth: usize, generic_args_depth: usize, + lifetime_elision_impossible: bool, phantom: std::marker::PhantomData, } @@ -525,6 +554,7 @@ where where_predicate_depth: 0, bounded_ty_depth: 0, generic_args_depth: 0, + lifetime_elision_impossible: false, phantom: std::marker::PhantomData, } } @@ -566,6 +596,7 @@ where in_where_predicate: self.where_predicate_depth != 0, in_bounded_ty: self.bounded_ty_depth != 0, in_generics_arg: self.generic_args_depth != 0, + lifetime_elision_impossible: self.lifetime_elision_impossible, }); } } @@ -592,11 +623,44 @@ where self.generic_args_depth -= 1; } + fn visit_fn_decl(&mut self, fd: &'tcx FnDecl<'tcx>) -> Self::Result { + self.lifetime_elision_impossible = !is_candidate_for_elision(fd); + walk_fn_decl(self, fd); + self.lifetime_elision_impossible = false; + } + fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } } +/// Check if `fd` supports function elision with an anonymous (or elided) lifetime, +/// and has a lifetime somewhere in its output type. +fn is_candidate_for_elision(fd: &FnDecl<'_>) -> bool { + struct V; + + impl Visitor<'_> for V { + type Result = ControlFlow; + + fn visit_lifetime(&mut self, lifetime: &Lifetime) -> Self::Result { + ControlFlow::Break(lifetime.is_elided() || lifetime.is_anonymous()) + } + } + + if fd.lifetime_elision_allowed + && let Return(ret_ty) = fd.output + && walk_unambig_ty(&mut V, ret_ty).is_break() + { + // The first encountered input lifetime will either be one on `self`, or will be the only lifetime. + fd.inputs + .iter() + .find_map(|ty| walk_unambig_ty(&mut V, ty).break_value()) + .unwrap() + } else { + false + } +} + fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) { let mut checker = LifetimeChecker::::new(cx, generics); @@ -662,6 +726,7 @@ fn report_elidable_impl_lifetimes<'tcx>( Usage { lifetime, in_where_predicate: false, + lifetime_elision_impossible: false, .. }, ] = usages.as_slice() @@ -719,7 +784,7 @@ fn report_elidable_lifetimes( |diag| { if !include_suggestions { return; - }; + } if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) { diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index e2dcb20f906d..a4cedf3bed35 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -251,7 +251,7 @@ impl LiteralDigitGrouping { ); if !consistent { return Err(WarningType::InconsistentDigitGrouping); - }; + } } Ok(()) diff --git a/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs b/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs index 49353a1b76be..a957c0e22a29 100644 --- a/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs +++ b/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs @@ -29,9 +29,9 @@ declare_clippy_lint! { /// let y = "hello"; /// x.expect(&format!("{y:?}")); /// ``` - #[clippy::version = "1.83.0"] + #[clippy::version = "1.85.0"] pub LITERAL_STRING_WITH_FORMATTING_ARGS, - suspicious, + nursery, "Checks if string literals have formatting arguments" } diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index f3ca4a4a5715..c5e75af2303c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -830,7 +830,7 @@ impl Loops { for_kv_map::check(cx, pat, arg, body); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); - same_item_push::check(cx, pat, arg, body, expr); + same_item_push::check(cx, pat, arg, body, expr, &self.msrv); 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); diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 951ebc9caef0..c27e930c99a5 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -1,8 +1,9 @@ use super::SAME_ITEM_PUSH; -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::path_to_local; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{msrvs, path_to_local, std_or_core}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -19,19 +20,30 @@ pub(super) fn check<'tcx>( _: &'tcx Expr<'_>, body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, + msrv: &Msrv, ) { - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) { + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext, msrv: &Msrv) { let mut app = Applicability::Unspecified; let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; - span_lint_and_help( + let secondary_help = if msrv.meets(msrvs::REPEAT_N) + && let Some(std_or_core) = std_or_core(cx) + { + format!("or `{vec_str}.extend({std_or_core}::iter::repeat_n({item_str}, SIZE))`") + } else { + format!("or `{vec_str}.resize(NEW_SIZE, {item_str})`") + }; + + span_lint_and_then( cx, SAME_ITEM_PUSH, vec.span, - "it looks like the same item is being pushed into this Vec", - None, - format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), + "it looks like the same item is being pushed into this `Vec`", + |diag| { + diag.help(format!("consider using `vec![{item_str};SIZE]`")) + .help(secondary_help); + }, ); } @@ -67,11 +79,11 @@ pub(super) fn check<'tcx>( { match init.kind { // immutable bindings that are initialized with literal - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt, msrv), // immutable bindings that are initialized with constant ExprKind::Path(ref path) => { if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { - emit_lint(cx, vec, pushed_item, ctxt); + emit_lint(cx, vec, pushed_item, ctxt, msrv); } }, _ => {}, @@ -79,11 +91,11 @@ pub(super) fn check<'tcx>( } }, // constant - Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt, msrv), _ => {}, } }, - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt, msrv), _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index d2a2321dae80..17e25635ce10 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -6,7 +6,7 @@ use clippy_utils::source::snippet_with_context; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; @@ -99,7 +99,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< && let QPath::Resolved(_, count_func_path) = count_func_qpath && let Some(segment_zero) = count_func_path.segments.first() && let Some(args) = segment_zero.args - && let Some(real_ty_span) = args.args.first().map(|arg| arg.span()) + && let Some(real_ty_span) = args.args.first().map(GenericArg::span) && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id) { diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index aa59b047b169..816ca17b3d2d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -102,12 +102,48 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { { build_suggestion(cx, expr, add_lhs, div_rhs, &mut applicability); } + + // (x + (Y - 1)) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, div_rhs) { + build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + } + + // ((Y - 1) + x) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, div_rhs) { + build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability); + } + + // (x - (-Y - 1)) / Y + if inner_op.node == BinOpKind::Sub + && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = div_rhs.kind + && differ_by_one(abs_div_rhs, inner_rhs) + { + build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + } } } extract_msrv_attr!(LateContext); } +/// Checks if two expressions represent non-zero integer literals such that `small_expr + 1 == +/// large_expr`. +fn differ_by_one(small_expr: &Expr<'_>, large_expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(small) = small_expr.kind + && let ExprKind::Lit(large) = large_expr.kind + && let LitKind::Int(s, _) = small.node + && let LitKind::Int(l, _) = large.node + { + Some(l.get()) == s.get().checked_add(1) + } else if let ExprKind::Unary(UnOp::Neg, small_inner_expr) = small_expr.kind + && let ExprKind::Unary(UnOp::Neg, large_inner_expr) = large_expr.kind + { + differ_by_one(large_inner_expr, small_inner_expr) + } else { + false + } +} + fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); match expr_ty.peel_refs().kind() { 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 9860deba8432..38106277a88f 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 @@ -7,7 +7,7 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit}; +use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; @@ -202,8 +202,14 @@ fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { } fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange { - if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind - && let PatExprKind::Lit{ lit: end_lit, negated: false } = &end.kind + if let PatExprKind::Lit { + lit: start_lit, + negated: false, + } = &start.kind + && let PatExprKind::Lit { + lit: end_lit, + negated: false, + } = &end.kind { check_lit_range(start_lit, end_lit) } else { 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 a70955a7c78d..8503dde3fb6b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -106,7 +106,7 @@ impl<'tcx> QuestionMark { emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body); }, } - }; + } } } @@ -295,7 +295,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) ) { return; - }; + } let ty = typeck_results.pat_ty(pat); // Option and Result are allowed, everything else isn't. if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) { 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 ebfd946b07ee..8aeec89f0bfa 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { } }, _ => return, - }; + } let mut app = Applicability::MachineApplicable; let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0; diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 79de41db3438..d69384a2cb70 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { let target_res = cx.qpath_res(target_path, target_arg.hir_id); if target_res == Res::Err { return; - }; + } if let Res::Local(hir_id) = target_res && let Some(used_mutably) = mutated_variables(then, cx) 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 cfa054706d6b..4cc43e427ec6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs @@ -34,7 +34,7 @@ fn get_cond_expr<'tcx>( needs_negated: is_none_expr(cx, then_expr), /* if the `then_expr` resolves to `None`, need to negate the * cond */ }); - }; + } None } @@ -45,7 +45,7 @@ fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> if block.stmts.is_empty() { return block.expr; } - }; + } None } @@ -68,14 +68,14 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) && path_to_local_id(arg, target); } - }; + } false } fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) { return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone); - }; + } false } diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs new file mode 100644 index 000000000000..b1a555b91d1b --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs @@ -0,0 +1,135 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::option_arg_ty; +use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks, span_contains_comment}; +use rustc_ast::BindingMode; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind, Path, QPath}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::Ty; +use rustc_span::symbol::Ident; + +use super::MANUAL_OK_ERR; + +pub(crate) fn check_if_let( + cx: &LateContext<'_>, + expr: &Expr<'_>, + let_pat: &Pat<'_>, + let_expr: &Expr<'_>, + if_then: &Expr<'_>, + else_expr: &Expr<'_>, +) { + if let Some(inner_expr_ty) = option_arg_ty(cx, cx.typeck_results().expr_ty(expr)) + && let Some((is_ok, ident)) = is_ok_or_err(cx, let_pat) + && is_some_ident(cx, if_then, ident, inner_expr_ty) + && is_none(cx, else_expr) + { + apply_lint(cx, expr, let_expr, is_ok); + } +} + +pub(crate) fn check_match(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]) { + if let Some(inner_expr_ty) = option_arg_ty(cx, cx.typeck_results().expr_ty(expr)) + && arms.len() == 2 + && arms.iter().all(|arm| arm.guard.is_none()) + && let Some((idx, is_ok)) = arms.iter().enumerate().find_map(|(arm_idx, arm)| { + // Check if the arm is a `Ok(x) => x` or `Err(x) => x` alternative. + // In this case, return its index and whether it uses `Ok` or `Err`. + if let Some((is_ok, ident)) = is_ok_or_err(cx, arm.pat) + && is_some_ident(cx, arm.body, ident, inner_expr_ty) + { + Some((arm_idx, is_ok)) + } else { + None + } + }) + // Accept wildcard only as the second arm + && is_variant_or_wildcard(cx, arms[1-idx].pat, idx == 0, is_ok) + // Check that the body of the non `Ok`/`Err` arm is `None` + && is_none(cx, arms[1 - idx].body) + { + apply_lint(cx, expr, scrutinee, is_ok); + } +} + +/// Check that `pat` applied to a `Result` only matches `Ok(_)`, `Err(_)`, not a subset or a +/// superset of it. If `can_be_wild` is `true`, wildcards are also accepted. In the case of +/// a non-wildcard, `must_match_err` indicates whether the `Err` or the `Ok` variant should be +/// accepted. +fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool, must_match_err: bool) -> bool { + match pat.kind { + PatKind::Wild | PatKind::Path(..) | PatKind::Binding(_, _, _, None) if can_be_wild => true, + PatKind::TupleStruct(qpath, ..) => { + is_res_lang_ctor(cx, cx.qpath_res(&qpath, pat.hir_id), ResultErr) == must_match_err + }, + PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) => { + is_variant_or_wildcard(cx, pat, can_be_wild, must_match_err) + }, + _ => false, + } +} + +/// Return `Some((true, IDENT))` if `pat` contains `Ok(IDENT)`, `Some((false, IDENT))` if it +/// contains `Err(IDENT)`, `None` otherwise. +fn is_ok_or_err<'hir>(cx: &LateContext<'_>, pat: &Pat<'hir>) -> Option<(bool, &'hir Ident)> { + if let PatKind::TupleStruct(qpath, [arg], _) = &pat.kind + && let PatKind::Binding(BindingMode::NONE, _, ident, _) = &arg.kind + && let res = cx.qpath_res(qpath, pat.hir_id) + && let Res::Def(DefKind::Ctor(..), id) = res + && let id @ Some(_) = cx.tcx.opt_parent(id) + { + let lang_items = cx.tcx.lang_items(); + if id == lang_items.result_ok_variant() { + return Some((true, ident)); + } else if id == lang_items.result_err_variant() { + return Some((false, ident)); + } + } + None +} + +/// Check if `expr` contains `Some(ident)`, possibly as a block +fn is_some_ident<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, ident: &Ident, ty: Ty<'tcx>) -> bool { + if let ExprKind::Call(body_callee, [body_arg]) = peel_blocks(expr).kind + && is_res_lang_ctor(cx, path_res(cx, body_callee), OptionSome) + && cx.typeck_results().expr_ty(body_arg) == ty + && let ExprKind::Path(QPath::Resolved( + _, + Path { + segments: [segment], .. + }, + )) = body_arg.kind + { + segment.ident.name == ident.name + } else { + false + } +} + +/// Check if `expr` is `None`, possibly as a block +fn is_none(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone) +} + +/// Suggest replacing `expr` by `scrutinee.METHOD()`, where `METHOD` is either `ok` or +/// `err`, depending on `is_ok`. +fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok: bool) { + let method = if is_ok { "ok" } else { "err" }; + let mut app = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_par(); + span_lint_and_sugg( + cx, + MANUAL_OK_ERR, + expr.span, + format!("manual implementation of `{method}`"), + "replace with", + format!("{scrut}.{method}()"), + app, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index bac5cf88cfbf..0b57740064c1 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -109,7 +109,7 @@ where } }, None => return None, - }; + } let mut app = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index 7e43d222a662..b90cf6357c5c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_unit_expr; -use clippy_utils::source::{expr_block, snippet}; +use clippy_utils::source::expr_block; use clippy_utils::sugg::Sugg; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -17,17 +17,28 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression", + "`match` on a boolean expression", move |diag| { if arms.len() == 2 { - // no guards - let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { + let mut app = Applicability::MachineApplicable; + let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { + let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); if let PatExprKind::Lit { lit, .. } = arm_bool.kind { - match lit.node { - LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), - LitKind::Bool(false) => Some((arms[1].body, arms[0].body)), + match &lit.node { + LitKind::Bool(true) => Some(test), + LitKind::Bool(false) => Some(!test), _ => None, } + .map(|test| { + if let Some(guard) = &arms[0] + .guard + .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) + { + test.and(guard) + } else { + test + } + }) } else { None } @@ -35,39 +46,31 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] None }; - if let Some((true_expr, false_expr)) = exprs { - let mut app = Applicability::HasPlaceholders; + if let Some(test_sugg) = test_sugg { let ctxt = expr.span.ctxt(); + let (true_expr, false_expr) = (arms[0].body, arms[1].body); let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { (false, false) => Some(format!( "if {} {} else {}", - snippet(cx, scrutinee.span, "b"), + test_sugg, expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )), (false, true) => Some(format!( "if {} {}", - snippet(cx, scrutinee.span, "b"), + test_sugg, expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) )), - (true, false) => { - let test = Sugg::hir(cx, scrutinee, ".."); - Some(format!( - "if {} {}", - !test, - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )) - }, + (true, false) => Some(format!( + "if {} {}", + !test_sugg, + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), (true, true) => None, }; if let Some(sugg) = sugg { - diag.span_suggestion( - expr.span, - "consider using an `if`/`else` expression", - sugg, - Applicability::HasPlaceholders, - ); + diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); } } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 223d0dc76569..d697f427c705 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -117,7 +117,7 @@ where if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() { ex_new = ex_inner; } - }; + } span_lint_and_sugg( cx, MATCH_LIKE_MATCHES_MACRO, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 9f5b7c855a13..df1b83cbb516 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr}; -use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatExpr, PatExprKind, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs index 91e40e4275c0..595655600890 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs @@ -170,7 +170,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { ); }); }, - }; + } } enum CommonPrefixSearcher<'a> { diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index ac1eae07eff6..a7fdd483c16c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -2,6 +2,7 @@ mod collapsible_match; mod infallible_destructuring_match; mod manual_filter; mod manual_map; +mod manual_ok_err; mod manual_unwrap_or; mod manual_utils; mod match_as_ref; @@ -972,6 +973,40 @@ declare_clippy_lint! { "checks for unnecessary guards in match expressions" } +declare_clippy_lint! { + /// ### What it does + /// Checks for manual implementation of `.ok()` or `.err()` + /// on `Result` values. + /// + /// ### Why is this bad? + /// Using `.ok()` or `.err()` rather than a `match` or + /// `if let` is less complex and more readable. + /// + /// ### Example + /// ```no_run + /// # fn func() -> Result { Ok(0) } + /// let a = match func() { + /// Ok(v) => Some(v), + /// Err(_) => None, + /// }; + /// let b = if let Err(v) = func() { + /// Some(v) + /// } else { + /// None + /// }; + /// ``` + /// Use instead: + /// ```no_run + /// # fn func() -> Result { Ok(0) } + /// let a = func().ok(); + /// let b = func().err(); + /// ``` + #[clippy::version = "1.86.0"] + pub MANUAL_OK_ERR, + complexity, + "find manual implementations of `.ok()` or `.err()` on `Result`" +} + pub struct Matches { msrv: Msrv, infallible_destructuring_match_linted: bool, @@ -1013,6 +1048,7 @@ impl_lint_pass!(Matches => [ MANUAL_MAP, MANUAL_FILTER, REDUNDANT_GUARDS, + MANUAL_OK_ERR, ]); impl<'tcx> LateLintPass<'tcx> for Matches { @@ -1091,6 +1127,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { manual_unwrap_or::check_match(cx, expr, ex, arms); manual_map::check_match(cx, expr, ex, arms); manual_filter::check_match(cx, ex, arms, expr); + manual_ok_err::check_match(cx, expr, ex, arms); } if self.infallible_destructuring_match_linted { @@ -1134,6 +1171,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_let.if_then, else_expr, ); + manual_ok_err::check_if_let( + cx, + expr, + if_let.let_pat, + if_let.let_expr, + if_let.if_then, + else_expr, + ); } } redundant_pattern_match::check_if_let( diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 2ce6a8a85a5e..35f2e780d2e2 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::source::{first_line_of_span, indent_of, snippet}; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{get_attr, is_lint_allowed}; use itertools::Itertools; @@ -152,7 +152,7 @@ fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: & diag.multipart_suggestion( suggestion_message, vec![ - (expr.span.shrink_to_lo(), replacement), + (first_line_of_span(cx, expr.span).shrink_to_lo(), replacement), (found.found_span, scrutinee_replacement), ], Applicability::MaybeIncorrect, @@ -441,8 +441,9 @@ impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> { let parent_expr_before = self.parent_expr.replace(ex); match ex.kind { - // Skip blocks because values in blocks will be dropped as usual. - ExprKind::Block(..) => (), + // Skip blocks because values in blocks will be dropped as usual, and await + // desugaring because temporary insides the future will have been dropped. + ExprKind::Block(..) | ExprKind::Match(_, _, MatchSource::AwaitDesugar) => (), _ => walk_expr(self, ex), } diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs index 6c02207af49d..ff7769af1df4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine err_ty = ty; } else { return; - }; + } span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs index 390ba889fd2e..b75d1ab9a7aa 100644 --- a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs +++ b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs @@ -13,7 +13,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) { && has_non_exhaustive_attr(cx.tcx, *adt_def) { return; - }; + } for arm in arms { if let PatKind::Or(fields) = arm.pat.kind { // look for multiple fields in this arm that contains at least one Wild pattern diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs index 4a2124c74a88..687272e550bb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs @@ -62,5 +62,5 @@ pub(super) fn check<'tcx>( ), applicability, ); - }; + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs index 34159f2d150e..a9f6a41c2357 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs @@ -32,5 +32,5 @@ pub(super) fn check<'tcx>( ), applicability, ); - }; + } } 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 a82abc79f2a2..de22514c37c6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -46,5 +46,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E 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 2a0a9d3710dc..223a960b800e 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 @@ -32,7 +32,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, // &T where T: Copy ty::Ref(_, ty, _) if is_copy(cx, *ty) => {}, _ => return, - }; + } span_lint_and_sugg( cx, CLONED_INSTEAD_OF_COPIED, diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs index 10360b4817bc..cbf713a3b17c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs @@ -1,8 +1,8 @@ use crate::methods::DRAIN_COLLECT; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_range_full; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{is_range_full, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; use rustc_lint::LateContext; @@ -58,12 +58,13 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re .then_some("Vec") .or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String")) .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs)) + && let Some(exec_context) = std_or_core(cx) { let recv = snippet(cx, recv.span, ""); let sugg = if let ty::Ref(..) = recv_ty.kind() { - format!("std::mem::take({recv})") + format!("{exec_context}::mem::take({recv})") } else { - format!("std::mem::take(&mut {recv})") + format!("{exec_context}::mem::take(&mut {recv})") }; span_lint_and_sugg( 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 44b55570eead..f2786efa44cb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs @@ -37,7 +37,7 @@ pub(super) fn check( "expect_err".to_string(), Applicability::MachineApplicable, ); - }; + } } /// Given a `Result` type, return its data (`T`). 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 6dc48c26ba93..daa6e0e7f940 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 @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>( if ty.is_str() && can_be_static_str(cx, arg) { return false; } - }; + } true } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs index 163058713377..aa45969c8982 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs @@ -25,5 +25,5 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span "into_iter()".to_string(), Applicability::MaybeIncorrect, ); - }; + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs b/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs new file mode 100644 index 000000000000..6e09bf132aa1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs @@ -0,0 +1,43 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::{expr_use_ctxt, fn_def_id, is_trait_method, std_or_core}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::MANUAL_REPEAT_N; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + repeat_expr: &Expr<'_>, + take_arg: &Expr<'_>, + msrv: &Msrv, +) { + if msrv.meets(msrvs::REPEAT_N) + && !expr.span.from_expansion() + && is_trait_method(cx, expr, sym::Iterator) + && let ExprKind::Call(_, [repeat_arg]) = repeat_expr.kind + && let Some(def_id) = fn_def_id(cx, repeat_expr) + && cx.tcx.is_diagnostic_item(sym::iter_repeat, def_id) + && !expr_use_ctxt(cx, expr).is_ty_unified + && let Some(std_or_core) = std_or_core(cx) + { + let mut app = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MANUAL_REPEAT_N, + expr.span, + "this `repeat().take()` can be written more concisely", + "consider using `repeat_n()` instead", + format!( + "{std_or_core}::iter::repeat_n({}, {})", + snippet_with_context(cx, repeat_arg.span, expr.span.ctxt(), "..", &mut app).0, + snippet(cx, take_arg.span, "..") + ), + app, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index 1ebb71e251ab..78656ace831d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -3,7 +3,7 @@ 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::Sugg; -use clippy_utils::{eager_or_lazy, higher, usage}; +use clippy_utils::{eager_or_lazy, higher, std_or_core, usage}; use rustc_ast::LitKind; use rustc_ast::ast::RangeLimits; use rustc_data_structures::packed::Pu128; @@ -75,6 +75,7 @@ pub(super) fn check( } = body_hir && !usage::BindingUsageFinder::are_params_used(cx, body_hir) && let Some(count) = extract_count_with_applicability(cx, range, &mut applicability) + && let Some(exec_context) = std_or_core(cx) { let method_to_use_name; let new_span; @@ -105,7 +106,7 @@ pub(super) fn check( let mut parts = vec![ ( receiver.span.to(method_call_span), - format!("std::iter::{method_to_use_name}"), + format!("{exec_context}::iter::{method_to_use_name}"), ), new_span, ]; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 3965c4d40878..42418318fda8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -58,6 +58,7 @@ mod manual_inspect; mod manual_is_variant_and; mod manual_next_back; mod manual_ok_or; +mod manual_repeat_n; mod manual_saturating_arithmetic; mod manual_str_repeat; mod manual_try_fold; @@ -101,6 +102,7 @@ mod single_char_add_str; mod single_char_insert_string; mod single_char_push_string; mod skip_while_next; +mod sliced_string_as_bytes; mod stable_sort_primitive; mod str_split; mod str_splitn; @@ -130,6 +132,7 @@ mod unnecessary_to_owned; mod unused_enumerate_index; mod unwrap_expect_used; mod useless_asref; +mod useless_nonzero_new_unchecked; mod utils; mod vec_resize_to_zero; mod verbose_file_reads; @@ -2416,14 +2419,14 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `.then_some(..).unwrap_or(..)` + /// Checks for unnecessary method chains that can be simplified into `if .. else ..`. /// /// ### Why is this bad? /// This can be written more clearly with `if .. else ..` /// /// ### Limitations /// This lint currently only looks for usages of - /// `.then_some(..).unwrap_or(..)`, but will be expanded + /// `.then_some(..).unwrap_or(..)` and `.then(..).unwrap_or(..)`, but will be expanded /// to account for similar patterns. /// /// ### Example @@ -4311,6 +4314,84 @@ declare_clippy_lint! { "using `Iterator::last` on a `DoubleEndedIterator`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for `NonZero*::new_unchecked()` being used in a `const` context. + /// + /// ### Why is this bad? + /// + /// Using `NonZero*::new_unchecked()` is an `unsafe` function and requires an `unsafe` context. When used in a + /// context evaluated at compilation time, `NonZero*::new().unwrap()` will provide the same result with identical + /// runtime performances while not requiring `unsafe`. + /// + /// ### Example + /// ```no_run + /// use std::num::NonZeroUsize; + /// const PLAYERS: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) }; + /// ``` + /// Use instead: + /// ```no_run + /// use std::num::NonZeroUsize; + /// const PLAYERS: NonZeroUsize = NonZeroUsize::new(3).unwrap(); + /// ``` + #[clippy::version = "1.86.0"] + pub USELESS_NONZERO_NEW_UNCHECKED, + complexity, + "using `NonZero::new_unchecked()` in a `const` context" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for `repeat().take()` that can be replaced with `repeat_n()`. + /// + /// ### Why is this bad? + /// + /// Using `repeat_n()` is more concise and clearer. Also, `repeat_n()` is sometimes faster than `repeat().take()` when the type of the element is non-trivial to clone because the original value can be reused for the last `.next()` call rather than always cloning. + /// + /// ### Example + /// ```no_run + /// let _ = std::iter::repeat(10).take(3); + /// ``` + /// Use instead: + /// ```no_run + /// let _ = std::iter::repeat_n(10, 3); + /// ``` + #[clippy::version = "1.86.0"] + pub MANUAL_REPEAT_N, + style, + "detect `repeat().take()` that can be replaced with `repeat_n()`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for string slices immediantly followed by `as_bytes`. + /// + /// ### Why is this bad? + /// It involves doing an unnecessary UTF-8 alignment check which is less efficient, and can cause a panic. + /// + /// ### Known problems + /// In some cases, the UTF-8 validation and potential panic from string slicing may be required for + /// the code's correctness. If you need to ensure the slice boundaries fall on valid UTF-8 character + /// boundaries, the original form (`s[1..5].as_bytes()`) should be preferred. + /// + /// ### Example + /// ```rust + /// let s = "Lorem ipsum"; + /// s[1..5].as_bytes(); + /// ``` + /// Use instead: + /// ```rust + /// let s = "Lorem ipsum"; + /// &s.as_bytes()[1..5]; + /// ``` + #[clippy::version = "1.86.0"] + pub SLICED_STRING_AS_BYTES, + perf, + "slicing a string and immediately calling as_bytes is less efficient and can lead to panics" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4477,6 +4558,9 @@ impl_lint_pass!(Methods => [ MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, UNNECESSARY_MAP_OR, DOUBLE_ENDED_ITERATOR_LAST, + USELESS_NONZERO_NEW_UNCHECKED, + MANUAL_REPEAT_N, + SLICED_STRING_AS_BYTES, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4505,6 +4589,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { from_iter_instead_of_collect::check(cx, expr, args, func); unnecessary_fallible_conversions::check_function(cx, expr, func); manual_c_str_literals::check(cx, expr, func, args, &self.msrv); + useless_nonzero_new_unchecked::check(cx, expr, func, args, &self.msrv); }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; @@ -4743,6 +4828,7 @@ impl Methods { if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); } + sliced_string_as_bytes::check(cx, expr, recv); }, ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, &self.msrv), @@ -4924,8 +5010,8 @@ impl Methods { }, ("is_empty", []) => { match method_call(recv) { - Some(("as_bytes", prev_recv, [], _, _)) => { - needless_as_bytes::check(cx, "is_empty", recv, prev_recv, expr.span); + Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) => { + needless_as_bytes::check(cx, prev_method, "is_empty", prev_recv, expr.span); }, Some(("as_str", recv, [], as_str_span, _)) => { redundant_as_str::check(cx, expr, recv, as_str_span, span); @@ -4962,8 +5048,8 @@ impl Methods { double_ended_iterator_last::check(cx, expr, recv, call_span); }, ("len", []) => { - if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) { - needless_as_bytes::check(cx, "len", recv, prev_recv, expr.span); + if let Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) = method_call(recv) { + needless_as_bytes::check(cx, prev_method, "len", prev_recv, expr.span); } }, ("lock", []) => { @@ -5015,7 +5101,7 @@ impl Methods { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); option_map_or_err_ok::check(cx, expr, recv, def, map); - unnecessary_map_or::check(cx, expr, recv, def, map, &self.msrv); + unnecessary_map_or::check(cx, expr, recv, def, map, span, &self.msrv); }, ("map_or_else", [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); @@ -5146,6 +5232,7 @@ impl Methods { ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); + manual_repeat_n::check(cx, expr, recv, arg, &self.msrv); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, @@ -5220,8 +5307,8 @@ impl Methods { Some(("map", m_recv, [m_arg], span, _)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv); }, - Some(("then_some", t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); + Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs index 75e9f3172303..7c9f7bae9906 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs @@ -8,18 +8,16 @@ use rustc_span::Span; use super::NEEDLESS_AS_BYTES; -pub fn check(cx: &LateContext<'_>, method: &str, recv: &Expr<'_>, prev_recv: &Expr<'_>, span: Span) { - if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice() - && let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs() - && (is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str()) - { +pub fn check(cx: &LateContext<'_>, prev_method: &str, method: &str, prev_recv: &Expr<'_>, span: Span) { + let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs(); + if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() { let mut app = Applicability::MachineApplicable; let sugg = Sugg::hir_with_context(cx, prev_recv, span.ctxt(), "..", &mut app); span_lint_and_sugg( cx, NEEDLESS_AS_BYTES, span, - "needless call to `as_bytes()`", + format!("needless call to `{prev_method}`"), format!("`{method}()` can be called directly on strings"), format!("{sugg}.{method}()"), app, diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs index 697eab32a33b..b71f79f84824 100644 --- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,8 +1,11 @@ use super::OBFUSCATED_IF_ELSE; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::ExprKind; use rustc_lint::LateContext; pub(super) fn check<'tcx>( @@ -11,19 +14,30 @@ pub(super) fn check<'tcx>( then_recv: &'tcx hir::Expr<'_>, then_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>, + then_method_name: &str, ) { - // something.then_some(blah).unwrap_or(blah) - // ^^^^^^^^^-then_recv ^^^^-then_arg ^^^^- unwrap_arg - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr - let recv_ty = cx.typeck_results().expr_ty(then_recv); if recv_ty.is_bool() { - let mut applicability = Applicability::MachineApplicable; + let mut applicability = if switch_to_eager_eval(cx, then_arg) && switch_to_eager_eval(cx, unwrap_arg) { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + + let if_then = match then_method_name { + "then" if let ExprKind::Closure(closure) = then_arg.kind => { + let body = cx.tcx.hir().body(closure.body); + snippet_with_applicability(cx, body.value.span, "..", &mut applicability) + }, + "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + _ => String::new().into(), + }; + let sugg = format!( "if {} {{ {} }} else {{ {} }}", - snippet_with_applicability(cx, then_recv.span, "..", &mut applicability), - snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability), + if_then, snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability) ); @@ -31,8 +45,7 @@ pub(super) fn check<'tcx>( cx, OBFUSCATED_IF_ELSE, expr.span, - "use of `.then_some(..).unwrap_or(..)` can be written \ - more clearly with `if .. else ..`", + "this method chain can be written more clearly with `if .. else ..`", "try", sugg, applicability, 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 febd7fd5cf2f..b3811a335e1a 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 @@ -37,7 +37,7 @@ pub(super) fn check( let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#); } else { let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#); - }; + } span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs new file mode 100644 index 000000000000..6d4cfdb34f31 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs @@ -0,0 +1,29 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_lang_item; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem, is_range_literal}; +use rustc_lint::LateContext; + +use super::SLICED_STRING_AS_BYTES; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>) { + if let ExprKind::Index(indexed, index, _) = recv.kind + && is_range_literal(index) + && let ty = cx.typeck_results().expr_ty(indexed).peel_refs() + && (ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)) + { + let mut applicability = Applicability::MaybeIncorrect; + let stringish = snippet_with_applicability(cx, indexed.span, "_", &mut applicability); + let range = snippet_with_applicability(cx, index.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + SLICED_STRING_AS_BYTES, + expr.span, + "calling `as_bytes` after slicing a string", + "try", + format!("&{stringish}.as_bytes()[{range}]"), + applicability, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 671c189a98e6..c0e015685881 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -87,7 +87,7 @@ pub fn check_for_loop_iter( // skip lint return true; } - }; + } // the lint should not be executed if no violation happens let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs index b7dbebe60a42..6dea1506d0e3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs @@ -1,9 +1,8 @@ use std::borrow::Cow; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_opt; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; use clippy_utils::visitors::is_local_used; @@ -12,7 +11,7 @@ use rustc_ast::LitKind::Bool; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{Span, sym}; use super::UNNECESSARY_MAP_OR; @@ -42,13 +41,14 @@ pub(super) fn check<'a>( recv: &Expr<'_>, def: &Expr<'_>, map: &Expr<'_>, + method_span: Span, msrv: &Msrv, ) { let ExprKind::Lit(def_kind) = def.kind else { return; }; - let recv_ty = cx.typeck_results().expr_ty(recv); + let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let Bool(def_bool) = def_kind.node else { return; @@ -60,6 +60,8 @@ pub(super) fn check<'a>( Some(_) | None => return, }; + let ext_def_span = def.span.until(map.span); + let (sugg, method, applicability) = if let ExprKind::Closure(map_closure) = map.kind && let closure_body = cx.tcx.hir().body(map_closure.body) && let closure_body_value = closure_body.value.peel_blocks() @@ -114,26 +116,17 @@ pub(super) fn check<'a>( } .into_string(); - (sugg, "a standard comparison", app) - } else if !def_bool - && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) - && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) - && let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite()) - { + (vec![(expr.span, sugg)], "a standard comparison", app) + } else if !def_bool && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) { let suggested_name = variant.method_name(); ( - format!("{recv_callsite}.{suggested_name}({span_callsite})",), + vec![(method_span, suggested_name.into()), (ext_def_span, String::default())], suggested_name, Applicability::MachineApplicable, ) - } else if def_bool - && matches!(variant, Variant::Some) - && msrv.meets(msrvs::IS_NONE_OR) - && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) - && let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite()) - { + } else if def_bool && matches!(variant, Variant::Some) && msrv.meets(msrvs::IS_NONE_OR) { ( - format!("{recv_callsite}.is_none_or({span_callsite})"), + vec![(method_span, "is_none_or".into()), (ext_def_span, String::default())], "is_none_or", Applicability::MachineApplicable, ) @@ -145,13 +138,13 @@ pub(super) fn check<'a>( return; } - span_lint_and_sugg( + span_lint_and_then( cx, UNNECESSARY_MAP_OR, expr.span, "this `map_or` can be simplified", - format!("use {method} instead"), - sugg, - applicability, + |diag| { + diag.multipart_suggestion_verbose(format!("use {method} instead"), sugg, applicability); + }, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 9a45b04d1a62..f0b29213e1e5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -43,8 +43,7 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) }, // The two exprs are method calls. - // Check to see that the function is the same and the arguments are mirrored - // This is enough because the receiver of the method is listed in the arguments + // Check to see that the function is the same and the arguments and receivers are mirrored ( ExprKind::MethodCall(left_segment, left_receiver, left_args, _), ExprKind::MethodCall(right_segment, right_receiver, right_args, _), 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 964f1603f0e5..7d72310c1c44 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 @@ -217,10 +217,13 @@ fn check_into_iter_call_arg( && implements_trait(cx, parent_ty, iterator_trait_id, &[]) && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + // If the receiver is a `Cow`, we can't remove the `into_owned` generally, see https://github.com/rust-lang/rust-clippy/issues/13624. + && !is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Cow) { if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } + let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) { "copied" } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs new file mode 100644 index 000000000000..0bd50429c09d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs @@ -0,0 +1,59 @@ +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::is_inside_always_const_context; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, QPath, UnsafeSource}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::USELESS_NONZERO_NEW_UNCHECKED; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<'tcx>, args: &[Expr<'_>], msrv: &Msrv) { + if msrv.meets(msrvs::CONST_UNWRAP) + && let ExprKind::Path(QPath::TypeRelative(ty, segment)) = func.kind + && segment.ident.name == sym::new_unchecked + && let [init_arg] = args + && is_inside_always_const_context(cx.tcx, expr.hir_id) + && is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::NonZero) + { + let mut app = Applicability::MachineApplicable; + let ty_str = snippet_with_applicability(cx, ty.span, "_", &mut app); + let msg = format!("`{ty_str}::new()` and `Option::unwrap()` can be safely used in a `const` context"); + let sugg = format!( + "{ty_str}::new({}).unwrap()", + snippet_with_applicability(cx, init_arg.span, "_", &mut app) + ); + + if let Node::Block(Block { + stmts: [], + span: block_span, + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }) = cx.tcx.parent_hir_node(expr.hir_id) + { + if !block_span.from_expansion() { + // The expression is the only component of an `unsafe` block. Propose + // to replace the block altogether. + span_lint_and_sugg( + cx, + USELESS_NONZERO_NEW_UNCHECKED, + *block_span, + msg, + "use instead", + sugg, + app, + ); + } + } else { + // The expression is enclosed in a larger `unsafe` context. Indicate that + // this may no longer be needed for the fixed expression. + span_lint_and_then(cx, USELESS_NONZERO_NEW_UNCHECKED, expr.span, msg, |diagnostic| { + diagnostic + .span_suggestion(expr.span, "use instead", sugg, app) + .note("the fixed expression does not require an `unsafe` context"); + }); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index b856c929cf67..b511b1e46b38 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -214,11 +214,12 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { ); }, ); - }; + } if let StmtKind::Semi(expr) = stmt.kind - && let ExprKind::Binary(ref binop, a, b) = expr.kind - && (binop.node == BinOpKind::And || binop.node == BinOpKind::Or) - && let Some(sugg) = Sugg::hir_opt(cx, a) + && let ExprKind::Binary(binop, a, b) = &expr.kind + && matches!(binop.node, BinOpKind::And | BinOpKind::Or) + && !stmt.span.from_expansion() + && expr.span.eq_ctxt(stmt.span) { span_lint_hir_and_then( cx, @@ -227,16 +228,14 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { stmt.span, "boolean short circuit operator in statement may be clearer using an explicit test", |diag| { - let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg }; - diag.span_suggestion( - stmt.span, - "replace it with", - format!("if {sugg} {{ {}; }}", &snippet(cx, b.span, ".."),), - Applicability::MachineApplicable, // snippet - ); + let mut app = Applicability::MachineApplicable; + let test = Sugg::hir_with_context(cx, a, expr.span.ctxt(), "_", &mut app); + let test = if binop.node == BinOpKind::Or { !test } else { test }; + let then = Sugg::hir_with_context(cx, b, expr.span.ctxt(), "_", &mut app); + diag.span_suggestion(stmt.span, "replace it with", format!("if {test} {{ {then}; }}"), app); }, ); - }; + } } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { 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 748289454bea..d52fe7e7d5b9 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 @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { }) => impl_params.push((path.segments[0].ident.to_string(), path.span)), GenericArg::Type(_) => return, _ => (), - }; + } } // find the type that the Impl is for diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 29dcbaa9e62a..06e92985e664 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -220,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::Impl { .. } | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span), - }; + } let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); 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 f28b431ab997..e9ec23b1efa6 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 @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { // this prevents ICEs such as when self is a type parameter or a primitive type // (see #10887, #11063) && let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, self_path_did) = self_path.res - && cx.match_def_path(trait_def_id, &[sym::core, sym::fmt, sym::Debug]) + && cx.tcx.is_diagnostic_item(sym::Debug, trait_def_id) // don't trigger if this impl was derived && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) && !item.span.from_expansion() diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 05aa425de9ed..bba1b63be277 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } | hir::ItemKind::Use(..) => {}, - }; + } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs index 9a6b1dfc52b5..4383f28717dc 100644 --- a/src/tools/clippy/clippy_lints/src/multi_assignments.rs +++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs @@ -56,10 +56,10 @@ impl EarlyLintPass for MultiAssignments { if let ExprKind::Assign(target, source, _) = &expr.kind { if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind { span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively"); - }; + } if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind { span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively"); } - }; + } } } 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 79252bba74d7..aad6ae52a6db 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 @@ -171,7 +171,7 @@ fn collect_unsafe_exprs<'tcx>( }, _ => {}, - }; + } Continue::<(), _>(Descend::Yes) }); diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 388414964588..86c084423b71 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg), - }; + } } } } 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 a67addea9486..4e19a2f409dd 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -107,6 +107,10 @@ struct LocalAssign { impl LocalAssign { fn from_expr(expr: &Expr<'_>, span: Span) -> Option { + if expr.span.from_expansion() { + return None; + } + if let ExprKind::Assign(lhs, rhs, _) = expr.kind { if lhs.span.from_expansion() { return None; @@ -336,7 +340,7 @@ fn check<'tcx>( ); }, _ => {}, - }; + } Some(()) } 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 9ee4e4932777..2e2916c957da 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 @@ -37,7 +37,9 @@ declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]); impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Fn { sig: fn_sig, .. } = &item.kind { + if let ItemKind::Fn { sig: fn_sig, .. } = &item.kind + && !item.span.from_expansion() + { let attrs = cx.tcx.hir().attrs(item.hir_id()); let mut app = Applicability::MaybeIncorrect; let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(item.ident.span.lo()), "..", &mut app); 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 8409d179b0f5..147654675ec9 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -89,16 +89,6 @@ declare_clippy_lint! { /// /// The `const` value should be stored inside a `static` item. /// - /// ### Known problems - /// When an enum has variants with interior mutability, use of its non - /// interior mutable variants can generate false positives. See issue - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) - /// - /// Types that have underlying or potential interior mutability trigger the lint whether - /// the interior mutable field is used or not. See issues - /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) - /// /// ### Example /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index 0caa19cd8443..852c3885f568 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { } }, _ => {}, - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs new file mode 100644 index 000000000000..312610db0423 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs @@ -0,0 +1,306 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::msrvs::Msrv; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{def_path_def_ids, fn_def_id, path_def_id}; +use rustc_data_structures::fx::FxIndexMap; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::impl_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Lints when `once_cell::sync::Lazy` or `lazy_static!` are used to define a static variable, + /// and suggests replacing such cases with `std::sync::LazyLock` instead. + /// + /// Note: This lint will not trigger in crate with `no_std` context, or with MSRV < 1.80.0. It + /// also will not trigger on `once_cell::sync::Lazy` usage in crates which use other types + /// from `once_cell`, such as `once_cell::race::OnceBox`. + /// + /// ### Why restrict this? + /// - Reduces the need for an extra dependency + /// - Enforce convention of using standard library types when possible + /// + /// ### Example + /// ```ignore + /// lazy_static! { + /// static ref FOO: String = "foo".to_uppercase(); + /// } + /// static BAR: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| "BAR".to_lowercase()); + /// ``` + /// Use instead: + /// ```ignore + /// static FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "FOO".to_lowercase()); + /// static BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "BAR".to_lowercase()); + /// ``` + #[clippy::version = "1.81.0"] + pub NON_STD_LAZY_STATICS, + pedantic, + "lazy static that could be replaced by `std::sync::LazyLock`" +} + +/// A list containing functions with corresponding replacements in `LazyLock`. +/// +/// Some functions could be replaced as well if we have replaced `Lazy` to `LazyLock`, +/// therefore after suggesting replace the type, we need to make sure the function calls can be +/// replaced, otherwise the suggestions cannot be applied thus the applicability should be +/// `Unspecified` or `MaybeIncorret`. +static FUNCTION_REPLACEMENTS: &[(&str, Option<&str>)] = &[ + ("once_cell::sync::Lazy::force", Some("std::sync::LazyLock::force")), + ("once_cell::sync::Lazy::get", None), // `std::sync::LazyLock::get` is experimental + ("once_cell::sync::Lazy::new", Some("std::sync::LazyLock::new")), + // Note: `Lazy::{into_value, get_mut, force_mut}` are not in the list. + // Because the lint only checks for `static`s, and using these functions with statics + // will either be a hard error or triggers `static_mut_ref` that will be hard errors. + // But keep in mind that if somehow we decide to expand this lint to catch non-statics, + // add those functions into the list. +]; + +pub struct NonStdLazyStatic { + msrv: Msrv, + lazy_static_lazy_static: Vec, + once_cell_crate: Vec, + once_cell_sync_lazy: Vec, + once_cell_sync_lazy_new: Vec, + sugg_map: FxIndexMap>, + lazy_type_defs: FxIndexMap, + uses_other_once_cell_types: bool, +} + +impl NonStdLazyStatic { + #[must_use] + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + lazy_static_lazy_static: Vec::new(), + once_cell_crate: Vec::new(), + once_cell_sync_lazy: Vec::new(), + once_cell_sync_lazy_new: Vec::new(), + sugg_map: FxIndexMap::default(), + lazy_type_defs: FxIndexMap::default(), + uses_other_once_cell_types: false, + } + } +} + +impl_lint_pass!(NonStdLazyStatic => [NON_STD_LAZY_STATICS]); + +/// Return if current MSRV does not meet the requirement for `lazy_cell` feature, +/// or current context has `no_std` attribute. +macro_rules! ensure_prerequisite { + ($msrv:expr, $cx:ident) => { + if !$msrv.meets(clippy_utils::msrvs::LAZY_CELL) || clippy_utils::is_no_std_crate($cx) { + return; + } + }; +} + +impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { + extract_msrv_attr!(LateContext); + + fn check_crate(&mut self, cx: &LateContext<'hir>) { + // Do not lint if current crate does not support `LazyLock`. + ensure_prerequisite!(self.msrv, cx); + + // Fetch def_ids for external paths + self.lazy_static_lazy_static = def_path_def_ids(cx.tcx, &["lazy_static", "lazy_static"]).collect(); + self.once_cell_sync_lazy = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy"]).collect(); + self.once_cell_sync_lazy_new = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy", "new"]).collect(); + // And CrateNums for `once_cell` crate + self.once_cell_crate = self.once_cell_sync_lazy.iter().map(|d| d.krate).collect(); + + // Convert hardcoded fn replacement list into a map with def_id + for (path, sugg) in FUNCTION_REPLACEMENTS { + let path_vec: Vec<&str> = path.split("::").collect(); + for did in def_path_def_ids(cx.tcx, &path_vec) { + self.sugg_map.insert(did, sugg.map(ToOwned::to_owned)); + } + } + } + + fn check_item(&mut self, cx: &LateContext<'hir>, item: &Item<'hir>) { + ensure_prerequisite!(self.msrv, cx); + + if let ItemKind::Static(..) = item.kind + && let Some(macro_call) = clippy_utils::macros::root_macro_call(item.span) + && self.lazy_static_lazy_static.contains(¯o_call.def_id) + { + span_lint( + cx, + NON_STD_LAZY_STATICS, + macro_call.span, + "this macro has been superceded by `std::sync::LazyLock`", + ); + return; + } + + if in_external_macro(cx.sess(), item.span) { + return; + } + + if let Some(lazy_info) = LazyInfo::from_item(self, cx, item) { + self.lazy_type_defs.insert(item.owner_id.to_def_id(), lazy_info); + } + } + + fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &Expr<'hir>) { + ensure_prerequisite!(self.msrv, cx); + + // All functions in the `FUNCTION_REPLACEMENTS` have only one args + if let ExprKind::Call(callee, [arg]) = expr.kind + && let Some(call_def_id) = fn_def_id(cx, expr) + && self.sugg_map.contains_key(&call_def_id) + && let ExprKind::Path(qpath) = arg.peel_borrows().kind + && let Some(arg_def_id) = cx.typeck_results().qpath_res(&qpath, arg.hir_id).opt_def_id() + && let Some(lazy_info) = self.lazy_type_defs.get_mut(&arg_def_id) + { + lazy_info.calls_span_and_id.insert(callee.span, call_def_id); + } + } + + fn check_ty(&mut self, cx: &LateContext<'hir>, ty: &'hir rustc_hir::Ty<'hir, rustc_hir::AmbigArg>) { + ensure_prerequisite!(self.msrv, cx); + + // Record if types from `once_cell` besides `sync::Lazy` are used. + if let rustc_hir::TyKind::Path(qpath) = ty.peel_refs().kind + && let Some(ty_def_id) = cx.qpath_res(&qpath, ty.hir_id).opt_def_id() + // Is from `once_cell` crate + && self.once_cell_crate.contains(&ty_def_id.krate) + // And is NOT `once_cell::sync::Lazy` + && !self.once_cell_sync_lazy.contains(&ty_def_id) + { + self.uses_other_once_cell_types = true; + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'hir>) { + ensure_prerequisite!(self.msrv, cx); + + if !self.uses_other_once_cell_types { + for (_, lazy_info) in &self.lazy_type_defs { + lazy_info.lint(cx, &self.sugg_map); + } + } + } +} + +struct LazyInfo { + /// Span of the [`hir::Ty`] without including args. + /// i.e.: + /// ```ignore + /// static FOO: Lazy = Lazy::new(...); + /// // ^^^^ + /// ``` + ty_span_no_args: Span, + /// `Span` and `DefId` of calls on `Lazy` type. + /// i.e.: + /// ```ignore + /// static FOO: Lazy = Lazy::new(...); + /// // ^^^^^^^^^ + /// ``` + calls_span_and_id: FxIndexMap, +} + +impl LazyInfo { + fn from_item(state: &NonStdLazyStatic, cx: &LateContext<'_>, item: &Item<'_>) -> Option { + // Check if item is a `once_cell:sync::Lazy` static. + if let ItemKind::Static(ty, _, body_id) = item.kind + && let Some(path_def_id) = path_def_id(cx, ty) + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && state.once_cell_sync_lazy.contains(&path_def_id) + { + let ty_span_no_args = path_span_without_args(path); + let body = cx.tcx.hir().body(body_id); + + // visit body to collect `Lazy::new` calls + let mut new_fn_calls = FxIndexMap::default(); + for_each_expr::<(), ()>(cx, body, |ex| { + if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id) + && state.once_cell_sync_lazy_new.contains(&fn_did) + { + new_fn_calls.insert(call_span, fn_did); + } + std::ops::ControlFlow::Continue(()) + }); + + Some(LazyInfo { + ty_span_no_args, + calls_span_and_id: new_fn_calls, + }) + } else { + None + } + } + + fn lint(&self, cx: &LateContext<'_>, sugg_map: &FxIndexMap>) { + // Applicability might get adjusted to `Unspecified` later if any calls + // in `calls_span_and_id` are not replaceable judging by the `sugg_map`. + let mut appl = Applicability::MachineApplicable; + let mut suggs = vec![(self.ty_span_no_args, "std::sync::LazyLock".to_string())]; + + for (span, def_id) in &self.calls_span_and_id { + let maybe_sugg = sugg_map.get(def_id).cloned().flatten(); + if let Some(sugg) = maybe_sugg { + suggs.push((*span, sugg)); + } else { + // If NO suggested replacement, not machine applicable + appl = Applicability::Unspecified; + } + } + + span_lint_and_then( + cx, + NON_STD_LAZY_STATICS, + self.ty_span_no_args, + "this type has been superceded by `LazyLock` in the standard library", + |diag| { + diag.multipart_suggestion("use `std::sync::LazyLock` instead", suggs, appl); + }, + ); + } +} + +/// Return the span of a given `Path` without including any of its args. +/// +/// NB: Re-write of a private function `rustc_lint::non_local_def::path_span_without_args`. +fn path_span_without_args(path: &hir::Path<'_>) -> Span { + path.segments + .last() + .and_then(|seg| seg.args) + .map_or(path.span, |args| path.span.until(args.span_ext)) +} + +/// Returns the `DefId` and `Span` of the callee if the given expression is a function call. +/// +/// NB: Modified from [`clippy_utils::fn_def_id`], to support calling in an static `Item`'s body. +fn fn_def_id_and_span_from_body(cx: &LateContext<'_>, expr: &Expr<'_>, body_id: BodyId) -> Option<(DefId, Span)> { + // FIXME: find a way to cache the result. + let typeck = cx.tcx.typeck_body(body_id); + match &expr.kind { + ExprKind::Call( + Expr { + kind: ExprKind::Path(qpath), + hir_id: path_hir_id, + span, + .. + }, + .., + ) => { + // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or + // deref to fn pointers, dyn Fn, impl Fn - #8850 + if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) = + typeck.qpath_res(qpath, *path_hir_id) + { + Some((id, *span)) + } else { + None + } + }, + _ => None, + } +} 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 0eca788c7874..9d07a14718da 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 @@ -104,7 +104,7 @@ impl ArithmeticSideEffects { if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { return false; - }; + } let int_type = substs.type_at(0); let unsigned_int_types = [ @@ -214,13 +214,13 @@ impl ArithmeticSideEffects { | hir::BinOpKind::Sub ) { return; - }; + } let (mut actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); actual_lhs = expr_or_init(cx, actual_lhs); actual_rhs = expr_or_init(cx, actual_rhs); let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs(); - let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs(); + let rhs_ty = cx.typeck_results().expr_ty_adjusted(actual_rhs).peel_refs(); if self.has_allowed_binary(lhs_ty, rhs_ty) { return; } @@ -283,7 +283,7 @@ impl ArithmeticSideEffects { if ConstEvalCtxt::new(cx).eval_simple(receiver).is_some() { return; } - let instance_ty = cx.typeck_results().expr_ty(receiver); + let instance_ty = cx.typeck_results().expr_ty_adjusted(receiver); if !Self::is_integral(instance_ty) { return; } @@ -311,7 +311,7 @@ impl ArithmeticSideEffects { if ConstEvalCtxt::new(cx).eval(un_expr).is_some() { return; } - let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs(); if self.has_allowed_unary(ty) { return; } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index b0d872e98fd4..cf6b8992973a 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -104,7 +104,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) } else { expr_snip = arg_snip.to_string(); eq_impl = without_deref; - }; + } let span; let hint; 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 1a0bfd8b9970..10455d3b93a0 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -127,7 +127,7 @@ pub(super) fn check<'tcx>( None, note, ); - }; + } } } 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 d72a2fc3b1ab..54f50f11e034 100644 --- a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs @@ -49,5 +49,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr lint_double_comparison!(==); }, _ => (), - }; + } } diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 8272d3643d42..01dc6a27c33e 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -120,7 +120,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ty::Array(arr_ty, _) = value { return matches!(arr_ty.kind(), ty::Float(_)); - }; + } matches!(value, ty::Float(_)) } diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 9e8a821c3f4e..d9845bc3b0f7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -262,7 +262,7 @@ declare_clippy_lint! { /// to `trailing_zeros` /// /// ### Why is this bad? - /// `x.trailing_zeros() > 4` is much clearer than `x & 15 + /// `x.trailing_zeros() >= 4` is much clearer than `x & 15 /// == 0` /// /// ### Known problems @@ -278,7 +278,7 @@ declare_clippy_lint! { /// /// ```no_run /// # let x: i32 = 1; - /// if x.trailing_zeros() > 4 { } + /// if x.trailing_zeros() >= 4 { } /// ``` #[clippy::version = "pre 1.29.0"] pub VERBOSE_BIT_MASK, diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index c83bdda347a6..691d7b904eff 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( } else { check_non_const_operands(cx, e, lhs); } - }; + } } fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs index 54eea14833ff..fc5565e821ed 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs @@ -21,6 +21,6 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, right: "any number modulo -1 will panic/overflow or result in 0", ); } - }; + } } } 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 794bef7b3214..55676522419c 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -53,6 +53,6 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { ); } } - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index 031f09310590..421b2b747555 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -43,7 +43,7 @@ impl EarlyLintPass for Precedence { cx, PRECEDENCE, expr.span, - "operator precedence can trip the unwary", + "operator precedence might not be obvious", "consider parenthesizing your expression", sugg, appl, 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 41a44de536b1..b4dadef57a3c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // avoid clippy::double_parens if !is_in_fn_call_arg { hint = hint.maybe_par(); - }; + } diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability); } 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 1b557730ecad..8d6b1c7274d9 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::HasSession; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; @@ -49,6 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) && is_not_macro_export(item) + && !in_external_macro(cx.sess(), item.span) { let span = item.span.with_hi(item.ident.span.hi()); let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id()); 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 81556f396141..7bd4d6e993b4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs @@ -215,6 +215,6 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { }, _ => (), } - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs index f54cafffb83c..5dddf9263a35 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; -use clippy_utils::{expr_or_init, fn_def_id}; +use clippy_utils::{expr_or_init, fn_def_id, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -93,6 +93,7 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) { && let ExprKind::Call(_, [repeat_expr]) = expr.kind && fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did)) && !repeat_expr.span.from_expansion() + && let Some(exec_context) = std_or_core(cx) { emit_lint( cx, @@ -100,7 +101,10 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) { "iter::repeat", "none of the yielded `Vec`s will have the requested capacity", "if you intended to create an iterator that yields `Vec`s with an initial capacity, try", - format!("std::iter::repeat_with(|| {})", snippet(cx, repeat_expr.span, "..")), + format!( + "{exec_context}::iter::repeat_with(|| {})", + snippet(cx, repeat_expr.span, "..") + ), ); } } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index dfaee8cc3054..664e984fece3 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{Descend, for_each_expr, for_each_unconsumed_temporary}; +use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::{ - binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, - path_to_local_id, span_contains_cfg, span_find_starting_semi, + binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, + leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg, + span_find_starting_semi, }; use core::ops::ControlFlow; use rustc_ast::MetaItemInner; @@ -389,22 +390,8 @@ fn check_final_expr<'tcx>( } }; - if let Some(inner) = inner { - if for_each_unconsumed_temporary(cx, inner, |temporary_ty| { - if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env()) - && temporary_ty - .walk() - .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - }) - .is_break() - { - return; - } + if inner.is_some_and(|inner| leaks_droppable_temporary_with_limited_lifetime(cx, inner)) { + return; } if ret_span.from_expansion() || is_from_proc_macro(cx, expr) { 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 9737b84cdb9c..2d989b1cf0ba 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 @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_trait_def_id; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, is_no_std_crate}; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr}; @@ -125,7 +125,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { span, format!("{suggested_type} of `Range` that is only one element"), |diag| { - if should_emit_every_value { + if should_emit_every_value && !is_no_std_crate(cx) { diag.span_suggestion( span, "if you wanted a `Vec` that contains the entire range, try", diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index db1c75fc3dea..f72ff10dd43c 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -97,7 +97,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( && let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next() { return Some((pointee_ty, count)); - }; + } if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods && let method_ident = method_path.ident.as_str() @@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( cx.typeck_results().expr_ty(ptr_self).kind() { return Some((*pointee_ty, count)); - }; + } None } @@ -130,6 +130,6 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { && pointee_ty == ty_used_for_size_of { span_lint_and_help(cx, SIZE_OF_IN_ELEMENT_COUNT, count_expr.span, LINT_MSG, None, HELP_MSG); - }; + } } } 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 d2d693eaa1f3..d26288adb391 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -3,6 +3,7 @@ use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, + span_contains_comment, }; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; @@ -190,7 +191,7 @@ impl SlowVectorInit { InitializationType::Extend(e) | InitializationType::Resize(e) => { Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization"); }, - }; + } } fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &'static str) { @@ -206,6 +207,14 @@ impl SlowVectorInit { let span_to_replace = slow_fill .span .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo()); + + // If there is no comment in `span_to_replace`, Clippy can automatically fix the code. + let app = if span_contains_comment(cx.tcx.sess.source_map(), span_to_replace) { + Applicability::Unspecified + } else { + Applicability::MachineApplicable + }; + span_lint_and_sugg( cx, SLOW_VECTOR_INITIALIZATION, @@ -213,7 +222,7 @@ impl SlowVectorInit { msg, "consider replacing this with", format!("vec![0; {len_expr}]"), - Applicability::Unspecified, + app, ); } } diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index ff1168005123..9b4c3d275ae7 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -296,7 +296,7 @@ fn check_xor_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { { let span = s1.span.to(s3.span); generate_swap_warning(block, cx, lhs0, rhs0, rhs1, rhs2, span, true); - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs index 531422798a68..bed4e60ba62d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -50,10 +50,7 @@ pub(super) fn check<'tcx>( } let args = last.args; let missing_generic = match args { - Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| match arg { - GenericArg::Infer(_) => true, - _ => false, - }), + Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| matches!(arg, GenericArg::Infer(_))), _ => true, }; if !missing_generic { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 3729dfd3e86f..f27aaa2fa77a 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { return false; - }; + } let int_ty = substs.type_at(0); if from_ty != int_ty { 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 99a55f9fc357..008e09dd8bd1 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -119,7 +119,7 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & && let LitKind::Int(val, _) = lit.node { return (val == i as u128).then_some(lhs); - }; + } None }) diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 1a5fdf0cd64f..2e97772407fd 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -71,7 +71,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m Applicability::Unspecified, ); return true; - }; + } false }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs new file mode 100644 index 000000000000..efbc536dcb4d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs @@ -0,0 +1,109 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::leaks_droppable_temporary_with_limited_lifetime; +use rustc_errors::Applicability; +use rustc_hir::{Block, ExprKind, HirId, MatchSource, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::impl_lint_pass; +use rustc_span::edition::Edition::Edition2021; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the presence of a semicolon at the end of + /// a `match` or `if` statement evaluating to `()`. + /// + /// ### Why is this bad? + /// The semicolon is not needed, and may be removed to + /// avoid confusion and visual clutter. + /// + /// ### Example + /// ```no_run + /// # let a: u32 = 42; + /// if a > 10 { + /// println!("a is greater than 10"); + /// }; + /// ``` + /// Use instead: + /// ```no_run + /// # let a: u32 = 42; + /// if a > 10 { + /// println!("a is greater than 10"); + /// } + /// ``` + #[clippy::version = "1.86.0"] + pub UNNECESSARY_SEMICOLON, + pedantic, + "unnecessary semicolon after expression returning `()`" +} + +#[derive(Default)] +pub struct UnnecessarySemicolon { + last_statements: Vec, +} + +impl_lint_pass!(UnnecessarySemicolon => [UNNECESSARY_SEMICOLON]); + +impl UnnecessarySemicolon { + /// Enter or leave a block, remembering the last statement of the block. + fn handle_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>, enter: bool) { + // Up to edition 2021, removing the semicolon of the last statement of a block + // may result in the scrutinee temporary values to live longer than the block + // variables. To avoid this problem, we do not lint the last statement of an + // expressionless block. + if cx.tcx.sess.edition() <= Edition2021 + && block.expr.is_none() + && let Some(last_stmt) = block.stmts.last() + { + if enter { + self.last_statements.push(last_stmt.hir_id); + } else { + self.last_statements.pop(); + } + } + } + + /// Checks if `stmt` is the last statement in an expressionless block for edition ≤ 2021. + fn is_last_in_block(&self, stmt: &Stmt<'_>) -> bool { + self.last_statements + .last() + .is_some_and(|last_stmt_id| last_stmt_id == &stmt.hir_id) + } +} + +impl<'tcx> LateLintPass<'tcx> for UnnecessarySemicolon { + fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { + self.handle_block(cx, block, true); + } + + fn check_block_post(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { + self.handle_block(cx, block, false); + } + + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) { + // rustfmt already takes care of removing semicolons at the end + // of loops. + if let StmtKind::Semi(expr) = stmt.kind + && !stmt.span.from_expansion() + && !expr.span.from_expansion() + && matches!( + expr.kind, + ExprKind::If(..) | ExprKind::Match(_, _, MatchSource::Normal | MatchSource::Postfix) + ) + && cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit + { + if self.is_last_in_block(stmt) && leaks_droppable_temporary_with_limited_lifetime(cx, expr) { + return; + } + + let semi_span = expr.span.shrink_to_hi().to(stmt.span.shrink_to_hi()); + span_lint_and_sugg( + cx, + UNNECESSARY_SEMICOLON, + semi_span, + "unnecessary semicolon", + "remove", + String::new(), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs b/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs new file mode 100644 index 000000000000..40ba70d451db --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs @@ -0,0 +1,76 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Pat, PatKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for struct patterns that match against unit variant. + /// + /// ### Why is this bad? + /// Struct pattern `{ }` or `{ .. }` is not needed for unit variant. + /// + /// ### Example + /// ```no_run + /// match Some(42) { + /// Some(v) => v, + /// None { .. } => 0, + /// }; + /// // Or + /// match Some(42) { + /// Some(v) => v, + /// None { } => 0, + /// }; + /// ``` + /// Use instead: + /// ```no_run + /// match Some(42) { + /// Some(v) => v, + /// None => 0, + /// }; + /// ``` + #[clippy::version = "1.83.0"] + pub UNNEEDED_STRUCT_PATTERN, + style, + "using struct pattern to match against unit variant" +} + +declare_lint_pass!(UnneededStructPattern => [UNNEEDED_STRUCT_PATTERN]); + +impl LateLintPass<'_> for UnneededStructPattern { + fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { + if !pat.span.from_expansion() + && let PatKind::Struct(path, [], _) = &pat.kind + && let QPath::Resolved(_, path) = path + && let Res::Def(DefKind::Variant, did) = path.res + { + let enum_did = cx.tcx.parent(did); + let variant = cx.tcx.adt_def(enum_did).variant_with_id(did); + + let has_only_fields_brackets = variant.ctor.is_some() && variant.fields.is_empty(); + let non_exhaustive_activated = !variant.def_id.is_local() && variant.is_field_list_non_exhaustive(); + if !has_only_fields_brackets || non_exhaustive_activated { + return; + } + + if is_from_proc_macro(cx, *path) { + return; + } + + if let Some(brackets_span) = pat.span.trim_start(path.span) { + span_lint_and_sugg( + cx, + UNNEEDED_STRUCT_PATTERN, + brackets_span, + "struct pattern is not needed for a unit variant", + "remove the struct pattern", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 7c9455bf8abe..e65123b8a949 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -182,7 +182,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { emit_lint(cx, expr.span, expr.hir_id, op, &[]); }, _ => {}, - }; + } } fn should_lint<'a>(cx: &LateContext<'a>, mut inner: &'a hir::Expr<'a>) -> Option { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 7ffab81a5444..5e452c6d2ac0 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::{DiagExt as _, Sugg}; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{ @@ -12,6 +12,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; @@ -251,26 +252,25 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { // ^^^ let (into_iter_recv, depth) = into_iter_deep_call(cx, into_iter_recv); - let plural = if depth == 0 { "" } else { "s" }; - let mut applicability = Applicability::MachineApplicable; - let sugg = snippet_with_applicability( - cx, - into_iter_recv.span.source_callsite(), - "", - &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, + let receiver_span = into_iter_recv.span.source_callsite(); + let adjustments = adjustments(cx, into_iter_recv); + let mut sugg = if adjustments.is_empty() { + vec![] + } else { + vec![(receiver_span.shrink_to_lo(), adjustments)] + }; + let plural = if depth == 0 { "" } else { "s" }; + sugg.push((e.span.with_lo(receiver_span.hi()), String::new())); + diag.multipart_suggestion( format!("consider removing the `.into_iter()`{plural}"), sugg, - applicability, + Applicability::MachineApplicable, ); diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); }, @@ -431,3 +431,16 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) } false } + +fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String { + let mut prefix = String::new(); + for adj in cx.typeck_results().expr_adjustments(expr) { + match adj.kind { + Adjust::Deref(_) => prefix = format!("*{prefix}"), + Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"), + Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"), + _ => {}, + } + } + prefix +} diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs index 49aad881994e..b8bcb9b37560 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs @@ -69,6 +69,6 @@ impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons { ), applicability, ); - }; + } } } diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 0730b561bc29..03c667846b61 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { }; if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) { return; - }; + } // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!` let callsite = expr.span.parent_callsite().unwrap_or(expr.span); diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 7fa070cd226b..68b7e1592e2e 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -3,7 +3,7 @@ name = "clippy_utils" # begin autogenerated version version = "0.1.86" # end autogenerated version -edition = "2021" +edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index c267b804124a..251e3dfe41be 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-01-09 +nightly-2025-01-28 ``` 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 cd6290ced334..179d42a8b5dc 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -400,7 +400,9 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), TyKind::Path(qpath) => qpath_search_pat(&qpath), TyKind::Infer(()) => (Pat::Str("_"), Pat::Str("_")), - TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => (Pat::Str("dyn"), Pat::Str("")), + TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => { + (Pat::Str("dyn"), Pat::Str("")) + }, // NOTE: `TraitObject` is incomplete. It will always return true then. _ => (Pat::Str(""), Pat::Str("")), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index d46beddf7312..a660623f4185 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -12,7 +12,9 @@ use rustc_apfloat::ieee::{Half, Quad}; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind}; +use rustc_hir::{ + BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp, +}; use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; @@ -451,8 +453,8 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } else { Some(val) } - } - PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value), + }, + PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(*body).value), PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id), } } diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 60be7e4a4d39..6bb876322f24 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -475,7 +475,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)), _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)), }; - }; + } }, ExprKind::Path(QPath::Resolved(_, path)) if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 9e11a57d1b30..e471dfb6ef19 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -88,7 +88,7 @@ use core::mem; use core::ops::ControlFlow; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; -use std::iter::{once, repeat}; +use std::iter::{once, repeat_n}; use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; @@ -116,15 +116,15 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, Ty, TyCtxt, - TypeVisitableExt, UintTy, UpvarCapture, + self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgKind, GenericArgsRef, IntTy, Ty, + TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{InnerSpan, Span, sym}; use rustc_target::abi::Integer; -use visitors::Visitable; +use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; @@ -814,7 +814,7 @@ fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &' e = ep; }, _ => break e, - }; + } }; result.reverse(); (result, root) @@ -2045,7 +2045,7 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t { return Some(expr); } - }; + } None } @@ -3420,7 +3420,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St })) .join("::") } else { - repeat(String::from("super")).take(go_up_by).chain(path).join("::") + repeat_n(String::from("super"), go_up_by).chain(path).join("::") } } @@ -3465,3 +3465,20 @@ pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } false } + +/// Returns true if `expr` creates any temporary whose type references a non-static lifetime and has +/// a significant drop and does not consume it. +pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + for_each_unconsumed_temporary(cx, expr, |temporary_ty| { + if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env()) + && temporary_ty + .walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_break() +} diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 45beb146eb6a..f4c730ef118b 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -251,7 +251,7 @@ impl<'a> PanicExpn<'a> { // This has no argument if name == "panic_cold_explicit" { return Some(Self::Empty); - }; + } let [arg, rest @ ..] = args else { return None; diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index 5eb9b3b8f227..605764cef89f 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -184,9 +184,10 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { vis.visit_body(mir); vis.into_map(cx) }; - let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(DenseBitSet::new_empty(mir.local_decls.len()))) - .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone")) - .into_results_cursor(mir); + let maybe_storage_live_result = + MaybeStorageLive::new(Cow::Owned(DenseBitSet::new_empty(mir.local_decls.len()))) + .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone")) + .into_results_cursor(mir); let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin); vis.visit_body(mir); vis.into_map(cx, maybe_storage_live_result) diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 2169a5fdd63b..d73cb7e35611 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -18,10 +18,10 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY } + 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP } - 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE } - 1,80,0 { BOX_INTO_ITER } + 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION } + 1,80,0 { BOX_INTO_ITER, LAZY_CELL } 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,74,0 { REPR_RUST } diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 2c49df9d807f..bb2a62821100 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -125,7 +125,7 @@ impl<'a> NumericLiteral<'a> { integer = &digits[..exp_start]; } else { fraction = Some(&digits[integer.len() + 1..exp_start]); - }; + } exponent = Some((&digits[exp_start..=i], &digits[i + 1..])); break; }, 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 104ae154e369..287bdc9a6fd6 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 @@ -29,13 +29,14 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) let def_id = body.source.def_id(); for local in &body.local_decls { - check_ty(tcx, local.ty, local.source_info.span)?; + check_ty(tcx, local.ty, local.source_info.span, msrv)?; } // impl trait is gone in MIR, so check the return type manually check_ty( tcx, tcx.fn_sig(def_id).instantiate_identity().output().skip_binder(), body.local_decls.iter().next().unwrap().source_info.span, + msrv, )?; for bb in &*body.basic_blocks { @@ -51,7 +52,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) Ok(()) } -fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { +fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, msrv: &Msrv) -> McfResult { for arg in ty.walk() { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -62,7 +63,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { }; match ty.kind() { - ty::Ref(_, _, hir::Mutability::Mut) => { + ty::Ref(_, _, hir::Mutability::Mut) if !msrv.meets(msrvs::CONST_MUT_REFS) => { return Err((span, "mutable references in const fn are unstable".into())); }, ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())), diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 32e7c2bbf7cb..f2bbdda70585 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -118,7 +118,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) { return true; } - }; + } }, _ => (), } @@ -1341,3 +1341,14 @@ pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> _ => None, } } + +/// Check if `ty` is an `Option` and return its argument type if it is. +pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { + match ty.kind() { + ty::Adt(adt, args) => cx + .tcx + .is_diagnostic_item(sym::Option, adt.did()) + .then(|| args.type_at(0)), + _ => None, + } +} 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 b5cec31ba9da..3398ff8af2f5 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 @@ -55,7 +55,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { && let Some(self_ty_def_id) = adt_def_id(self_ty(cx, method_def_id)) { receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id); - }; + } let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false); let rhs = if type_is_inferable_from_arguments(cx, expr) { meet( diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index dcc763a8abd7..99984c41714b 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -2,12 +2,11 @@ use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_ast::visit::{VisitorResult, try_visit}; -use rustc_hir::{self as hir, AmbigArg}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr}; use rustc_hir::{ - AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath, - Stmt, StructTailExpr, UnOp, UnsafeSource, + self as hir, AmbigArg, AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, + ItemKind, LetExpr, Pat, QPath, Stmt, StructTailExpr, UnOp, UnsafeSource, }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml index b0e4e3e3e573..55e588f5ec73 100644 --- a/src/tools/clippy/lintcheck/Cargo.toml +++ b/src/tools/clippy/lintcheck/Cargo.toml @@ -6,7 +6,7 @@ readme = "README.md" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-clippy" categories = ["development-tools"] -edition = "2021" +edition = "2024" publish = false default-run = "lintcheck" diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs index bd4fcc5e337e..af243f94274d 100644 --- a/src/tools/clippy/lintcheck/src/config.rs +++ b/src/tools/clippy/lintcheck/src/config.rs @@ -107,7 +107,7 @@ impl LintcheckConfig { } else { std::thread::available_parallelism().map_or(1, NonZero::get) }; - }; + } for lint_name in &mut config.lint_filter { *lint_name = format!( diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index 03e2a24f6f98..e88d9f427bec 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -145,7 +145,7 @@ impl Crate { assert_eq!(status.code(), Some(0)); return Vec::new(); - }; + } if !config.fix { cmd.arg("--message-format=json"); @@ -313,7 +313,7 @@ fn lintcheck(config: LintcheckConfig) { filter }) .collect_into(&mut lint_level_args); - }; + } let crates: Vec = crates .into_iter() diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index b1f0a82b1f47..c15d1fe6cd34 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-01-09" +channel = "nightly-2025-01-28" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/rustc_tools_util/Cargo.toml b/src/tools/clippy/rustc_tools_util/Cargo.toml index b63632916ba1..cba025639482 100644 --- a/src/tools/clippy/rustc_tools_util/Cargo.toml +++ b/src/tools/clippy/rustc_tools_util/Cargo.toml @@ -7,6 +7,6 @@ readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["rustc", "tool", "git", "version", "hash"] categories = ["development-tools"] -edition = "2018" +edition = "2024" [dependencies] diff --git a/src/tools/clippy/rustfmt.toml b/src/tools/clippy/rustfmt.toml index 4248f42f654b..0dc6adce7bfc 100644 --- a/src/tools/clippy/rustfmt.toml +++ b/src/tools/clippy/rustfmt.toml @@ -2,8 +2,8 @@ max_width = 120 comment_width = 100 match_block_trailing_comma = true wrap_comments = true -edition = "2021" +edition = "2024" error_on_line_overflow = true imports_granularity = "Module" -version = "Two" +style_edition = "2024" ignore = ["tests/ui/crashes/ice-10912.rs"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 68edefd3095c..8201f332d333 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -223,7 +223,7 @@ pub fn main() { if !has_sysroot_arg(args) { args.extend(vec!["--sysroot".into(), sys_root]); } - }; + } }; // make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc" diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index e2e4d92df79f..d1b1a1d23232 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -300,7 +300,9 @@ fn run_ui_cargo(cx: &TestContext) { } fn main() { - set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); + unsafe { + set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); + } let cx = TestContext::new(); diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs index 64eba5e0888a..565dcd73f582 100644 --- a/src/tools/clippy/tests/missing-test-files.rs +++ b/src/tools/clippy/tests/missing-test-files.rs @@ -60,7 +60,7 @@ fn explore_directory(dir: &Path) -> Vec { } }, _ => {}, - }; + } } } } diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index ff178924bd15..ae5d8ef1d0b5 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -13,5 +13,9 @@ note: rustc running on note: compiler flags: -Z ui-testing -Z deduplicate-diagnostics=no +query stack during panic: +#0 [early_lint_checks] perform lints prior to macro expansion +#1 [hir_crate] getting the crate HIR +... and 3 other queries... use `env RUST_BACKTRACE=1` to see the full query stack note: Clippy version: foo diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index 3f2040730851..f09106773c7e 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -170,6 +170,7 @@ pub fn hard_coded_allowed() { let _ = Saturating(0u32) + Saturating(0u32); let _ = String::new() + ""; + let _ = String::new() + &String::new(); let _ = Wrapping(0u32) + Wrapping(0u32); let saturating: Saturating = Saturating(0u32); @@ -408,11 +409,14 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() { _n.wrapping_rem(_n); _n.wrapping_rem_euclid(_n); + _n.saturating_div(*Box::new(_n)); + // Unary _n = -_n; _n = -&_n; _custom = -_custom; _custom = -&_custom; + _ = -*Box::new(_n); } // Copied and pasted from the `integer_arithmetic` lint for comparison. @@ -534,4 +538,11 @@ pub fn issue_12318() { one.sub_assign(1); } +pub fn explicit_methods() { + use core::ops::Add; + let one: i32 = 1; + one.add(&one); + Box::new(one).add(one); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 78b1aca4b8a4..9b4cfb83fbb2 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -14,730 +14,760 @@ LL | let _ = 1f128 + 1f128; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:307:5 + --> tests/ui/arithmetic_side_effects.rs:173:13 + | +LL | let _ = String::new() + &String::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:308:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:308:5 + --> tests/ui/arithmetic_side_effects.rs:309:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:309:5 + --> tests/ui/arithmetic_side_effects.rs:310:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:310:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:311:5 + --> tests/ui/arithmetic_side_effects.rs:312:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:313:5 + --> tests/ui/arithmetic_side_effects.rs:314:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:315:5 + --> tests/ui/arithmetic_side_effects.rs:316:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:317:5 + --> tests/ui/arithmetic_side_effects.rs:318:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:319:5 + --> tests/ui/arithmetic_side_effects.rs:320:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:321:5 + --> tests/ui/arithmetic_side_effects.rs:322:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:323:5 + --> tests/ui/arithmetic_side_effects.rs:324:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:325:5 + --> tests/ui/arithmetic_side_effects.rs:326:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:327:5 + --> tests/ui/arithmetic_side_effects.rs:328:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:329:5 + --> tests/ui/arithmetic_side_effects.rs:330:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:331:5 + --> tests/ui/arithmetic_side_effects.rs:332:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:333:5 + --> tests/ui/arithmetic_side_effects.rs:334:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:335:5 + --> tests/ui/arithmetic_side_effects.rs:336:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:337:5 + --> tests/ui/arithmetic_side_effects.rs:338:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:339:5 + --> tests/ui/arithmetic_side_effects.rs:340:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:341:5 + --> tests/ui/arithmetic_side_effects.rs:342:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:343:5 + --> tests/ui/arithmetic_side_effects.rs:344:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:345:5 + --> tests/ui/arithmetic_side_effects.rs:346:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:347:5 + --> tests/ui/arithmetic_side_effects.rs:348:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:349:5 + --> tests/ui/arithmetic_side_effects.rs:350:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:351:5 + --> tests/ui/arithmetic_side_effects.rs:352:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:352:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:353:5 + --> tests/ui/arithmetic_side_effects.rs:354:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:5 + --> tests/ui/arithmetic_side_effects.rs:355:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:357:10 + --> tests/ui/arithmetic_side_effects.rs:358:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:10 + --> tests/ui/arithmetic_side_effects.rs:359:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:359:10 + --> tests/ui/arithmetic_side_effects.rs:360:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:10 + --> tests/ui/arithmetic_side_effects.rs:361:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:361:10 + --> tests/ui/arithmetic_side_effects.rs:362:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:10 + --> tests/ui/arithmetic_side_effects.rs:363:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:363:10 + --> tests/ui/arithmetic_side_effects.rs:364:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:10 + --> tests/ui/arithmetic_side_effects.rs:365:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:365:10 + --> tests/ui/arithmetic_side_effects.rs:366:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:10 + --> tests/ui/arithmetic_side_effects.rs:367:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:367:10 + --> tests/ui/arithmetic_side_effects.rs:368:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:10 + --> tests/ui/arithmetic_side_effects.rs:369:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:369:10 + --> tests/ui/arithmetic_side_effects.rs:370:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:10 + --> tests/ui/arithmetic_side_effects.rs:371:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:371:10 + --> tests/ui/arithmetic_side_effects.rs:372:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:10 + --> tests/ui/arithmetic_side_effects.rs:373:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:373:10 + --> tests/ui/arithmetic_side_effects.rs:374:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:10 + --> tests/ui/arithmetic_side_effects.rs:375:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:375:10 + --> tests/ui/arithmetic_side_effects.rs:376:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:15 + --> tests/ui/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:377:15 + --> tests/ui/arithmetic_side_effects.rs:378:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:15 + --> tests/ui/arithmetic_side_effects.rs:379:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:379:15 + --> tests/ui/arithmetic_side_effects.rs:380:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:15 + --> tests/ui/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:381:15 + --> tests/ui/arithmetic_side_effects.rs:382:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:15 + --> tests/ui/arithmetic_side_effects.rs:383:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:383:15 + --> tests/ui/arithmetic_side_effects.rs:384:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:15 + --> tests/ui/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:385:15 + --> tests/ui/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:15 + --> tests/ui/arithmetic_side_effects.rs:387:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:387:15 + --> tests/ui/arithmetic_side_effects.rs:388:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:15 + --> tests/ui/arithmetic_side_effects.rs:389:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:389:15 + --> tests/ui/arithmetic_side_effects.rs:390:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:15 + --> tests/ui/arithmetic_side_effects.rs:391:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:391:15 + --> tests/ui/arithmetic_side_effects.rs:392:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:15 + --> tests/ui/arithmetic_side_effects.rs:393:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:393:15 + --> tests/ui/arithmetic_side_effects.rs:394:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:15 + --> tests/ui/arithmetic_side_effects.rs:395:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:395:15 + --> tests/ui/arithmetic_side_effects.rs:396:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:396:15 + --> tests/ui/arithmetic_side_effects.rs:397:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:397:15 + --> tests/ui/arithmetic_side_effects.rs:398:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:15 + --> tests/ui/arithmetic_side_effects.rs:399:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:401:23 + --> tests/ui/arithmetic_side_effects.rs:402:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:402:21 + --> tests/ui/arithmetic_side_effects.rs:403:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:403:21 + --> tests/ui/arithmetic_side_effects.rs:404:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:28 + --> tests/ui/arithmetic_side_effects.rs:405:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:406:23 + --> tests/ui/arithmetic_side_effects.rs:407:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:407:21 + --> tests/ui/arithmetic_side_effects.rs:408:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:408:21 + --> tests/ui/arithmetic_side_effects.rs:409:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:409:28 + --> tests/ui/arithmetic_side_effects.rs:410:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:412:10 + --> tests/ui/arithmetic_side_effects.rs:412:23 + | +LL | _n.saturating_div(*Box::new(_n)); + | ^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:415:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:413:10 + --> tests/ui/arithmetic_side_effects.rs:416:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:414:15 + --> tests/ui/arithmetic_side_effects.rs:417:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:415:15 + --> tests/ui/arithmetic_side_effects.rs:418:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:424:5 + --> tests/ui/arithmetic_side_effects.rs:419:9 + | +LL | _ = -*Box::new(_n); + | ^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:428:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:425:5 + --> tests/ui/arithmetic_side_effects.rs:429:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:426:5 + --> tests/ui/arithmetic_side_effects.rs:430:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:427:5 + --> tests/ui/arithmetic_side_effects.rs:431:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:428:5 + --> tests/ui/arithmetic_side_effects.rs:432:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:439:5 + --> tests/ui/arithmetic_side_effects.rs:443:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:440:5 + --> tests/ui/arithmetic_side_effects.rs:444:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:441:5 + --> tests/ui/arithmetic_side_effects.rs:445:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:443:5 + --> tests/ui/arithmetic_side_effects.rs:447:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:445:5 + --> tests/ui/arithmetic_side_effects.rs:449:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:446:5 + --> tests/ui/arithmetic_side_effects.rs:450:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:448:5 + --> tests/ui/arithmetic_side_effects.rs:452:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:450:5 + --> tests/ui/arithmetic_side_effects.rs:454:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:451:5 + --> tests/ui/arithmetic_side_effects.rs:455:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:461:5 + --> tests/ui/arithmetic_side_effects.rs:465:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:515:9 + --> tests/ui/arithmetic_side_effects.rs:519:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:519:9 + --> tests/ui/arithmetic_side_effects.rs:523:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:530:5 + --> tests/ui/arithmetic_side_effects.rs:534:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:534:5 + --> tests/ui/arithmetic_side_effects.rs:538:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 123 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:544:5 + | +LL | one.add(&one); + | ^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:545:5 + | +LL | Box::new(one).add(one); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 128 previous errors diff --git a/src/tools/clippy/tests/ui/auxiliary/non-exhaustive-enum.rs b/src/tools/clippy/tests/ui/auxiliary/non-exhaustive-enum.rs index 420232f9f8d8..e3205193ccea 100644 --- a/src/tools/clippy/tests/ui/auxiliary/non-exhaustive-enum.rs +++ b/src/tools/clippy/tests/ui/auxiliary/non-exhaustive-enum.rs @@ -6,3 +6,24 @@ pub enum ErrorKind { #[doc(hidden)] Uncategorized, } + +#[non_exhaustive] +pub enum ExtNonExhaustiveEnum { + Unit, + Tuple(i32), + Struct { field: i32 }, +} + +pub enum ExtNonExhaustiveVariant { + ExhaustiveUnit, + #[non_exhaustive] + Unit, + #[non_exhaustive] + Tuple(i32), + #[non_exhaustive] + StructNoField {}, + #[non_exhaustive] + Struct { + field: i32, + }, +} diff --git a/src/tools/clippy/tests/ui/bytes_nth.fixed b/src/tools/clippy/tests/ui/bytes_nth.fixed index 11deb2390fd4..da35fcb55e5a 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.fixed +++ b/src/tools/clippy/tests/ui/bytes_nth.fixed @@ -1,4 +1,5 @@ #![allow(clippy::unnecessary_operation)] +#![allow(clippy::sliced_string_as_bytes)] #![warn(clippy::bytes_nth)] fn main() { diff --git a/src/tools/clippy/tests/ui/bytes_nth.rs b/src/tools/clippy/tests/ui/bytes_nth.rs index 62d9c7a5ea79..5dbe84ecec8b 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.rs +++ b/src/tools/clippy/tests/ui/bytes_nth.rs @@ -1,4 +1,5 @@ #![allow(clippy::unnecessary_operation)] +#![allow(clippy::sliced_string_as_bytes)] #![warn(clippy::bytes_nth)] fn main() { diff --git a/src/tools/clippy/tests/ui/bytes_nth.stderr b/src/tools/clippy/tests/ui/bytes_nth.stderr index c6f21576c3db..c5f341cb37f6 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.stderr +++ b/src/tools/clippy/tests/ui/bytes_nth.stderr @@ -1,5 +1,5 @@ error: called `.bytes().nth()` on a `String` - --> tests/ui/bytes_nth.rs:6:13 + --> tests/ui/bytes_nth.rs:7:13 | LL | let _ = s.bytes().nth(3); | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()` @@ -8,13 +8,13 @@ LL | let _ = s.bytes().nth(3); = help: to override `-D warnings` add `#[allow(clippy::bytes_nth)]` error: called `.bytes().nth().unwrap()` on a `String` - --> tests/ui/bytes_nth.rs:7:14 + --> tests/ui/bytes_nth.rs:8:14 | LL | let _ = &s.bytes().nth(3).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]` error: called `.bytes().nth()` on a `str` - --> tests/ui/bytes_nth.rs:8:13 + --> tests/ui/bytes_nth.rs:9:13 | LL | let _ = s[..].bytes().nth(3); | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()` diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.fixed b/src/tools/clippy/tests/ui/crashes/ice-11230.fixed new file mode 100644 index 000000000000..1d4c3dd9dcc4 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.fixed @@ -0,0 +1,16 @@ +// Test for https://github.com/rust-lang/rust-clippy/issues/11230 +#![warn(clippy::explicit_iter_loop)] +#![warn(clippy::needless_collect)] + +// explicit_iter_loop +fn main() { + const A: &[for<'a> fn(&'a ())] = &[]; + for v in A {} +} + +// needless_collect +trait Helper<'a>: Iterator {} + +fn x(w: &mut dyn for<'a> Helper<'a>) { + w.next().is_none(); +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.rs b/src/tools/clippy/tests/ui/crashes/ice-11230.rs index 94044e9435ed..a16fb271497c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11230.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.rs @@ -1,6 +1,16 @@ // Test for https://github.com/rust-lang/rust-clippy/issues/11230 +#![warn(clippy::explicit_iter_loop)] +#![warn(clippy::needless_collect)] +// explicit_iter_loop fn main() { const A: &[for<'a> fn(&'a ())] = &[]; for v in A.iter() {} } + +// needless_collect +trait Helper<'a>: Iterator {} + +fn x(w: &mut dyn for<'a> Helper<'a>) { + w.collect::>().is_empty(); +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.stderr b/src/tools/clippy/tests/ui/crashes/ice-11230.stderr new file mode 100644 index 000000000000..7167d90e456e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.stderr @@ -0,0 +1,20 @@ +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> tests/ui/crashes/ice-11230.rs:8:14 + | +LL | for v in A.iter() {} + | ^^^^^^^^ help: to write this more concisely, try: `A` + | + = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::explicit_iter_loop)]` + +error: avoid using `collect()` when not needed + --> tests/ui/crashes/ice-11230.rs:15:7 + | +LL | w.collect::>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + | + = note: `-D clippy::needless-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.fixed b/src/tools/clippy/tests/ui/crashes/ice-11422.fixed index ca5721cbb2ba..d996b1db08a6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11422.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-11422.fixed @@ -3,7 +3,7 @@ use std::fmt::Debug; use std::ops::*; -fn gen() -> impl PartialOrd + Debug {} +fn r#gen() -> impl PartialOrd + Debug {} struct Bar {} trait Foo {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.rs b/src/tools/clippy/tests/ui/crashes/ice-11422.rs index 355ec2480bba..eb89b7c38f43 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11422.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11422.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use std::ops::*; -fn gen() -> impl PartialOrd + PartialEq + Debug {} +fn r#gen() -> impl PartialOrd + PartialEq + Debug {} struct Bar {} trait Foo {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.stderr b/src/tools/clippy/tests/ui/crashes/ice-11422.stderr index a340977f4699..67944e4e6e80 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11422.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-11422.stderr @@ -1,15 +1,15 @@ error: this bound is already specified as the supertrait of `PartialOrd` - --> tests/ui/crashes/ice-11422.rs:6:31 + --> tests/ui/crashes/ice-11422.rs:6:33 | -LL | fn gen() -> impl PartialOrd + PartialEq + Debug {} - | ^^^^^^^^^ +LL | fn r#gen() -> impl PartialOrd + PartialEq + Debug {} + | ^^^^^^^^^ | = note: `-D clippy::implied-bounds-in-impls` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::implied_bounds_in_impls)]` help: try removing this bound | -LL - fn gen() -> impl PartialOrd + PartialEq + Debug {} -LL + fn gen() -> impl PartialOrd + Debug {} +LL - fn r#gen() -> impl PartialOrd + PartialEq + Debug {} +LL + fn r#gen() -> impl PartialOrd + Debug {} | error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed index 0822cc7c6350..8e2ed1bbd18d 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed @@ -1,4 +1,5 @@ #![warn(clippy::doc_lazy_continuation)] +#![allow(clippy::doc_overindented_list_items)] /// 1. nest here /// lazy continuation diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs index 068de140e00a..1da11d8fae26 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs @@ -1,4 +1,5 @@ #![warn(clippy::doc_lazy_continuation)] +#![allow(clippy::doc_overindented_list_items)] /// 1. nest here /// lazy continuation diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr index b38f43b7555f..cea6157119f7 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr @@ -1,5 +1,5 @@ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:4:5 + --> tests/ui/doc/doc_lazy_list.rs:5:5 | LL | /// lazy continuation | ^ @@ -13,7 +13,7 @@ LL | /// lazy continuation | +++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:9:5 + --> tests/ui/doc/doc_lazy_list.rs:10:5 | LL | /// lazy list continuations don't make warnings with this lint | ^ @@ -25,7 +25,7 @@ LL | /// lazy list continuations don't make warnings with this lint | +++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:11:5 + --> tests/ui/doc/doc_lazy_list.rs:12:5 | LL | /// because they don't have the | ^ @@ -37,7 +37,7 @@ LL | /// because they don't have the | +++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:16:5 + --> tests/ui/doc/doc_lazy_list.rs:17:5 | LL | /// lazy continuation | ^ @@ -49,7 +49,7 @@ LL | /// lazy continuation | ++++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:21:5 + --> tests/ui/doc/doc_lazy_list.rs:22:5 | LL | /// lazy list continuations don't make warnings with this lint | ^ @@ -61,7 +61,7 @@ LL | /// lazy list continuations don't make warnings with this lint | ++++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:23:5 + --> tests/ui/doc/doc_lazy_list.rs:24:5 | LL | /// because they don't have the | ^ @@ -73,7 +73,7 @@ LL | /// because they don't have the | ++++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:28:5 + --> tests/ui/doc/doc_lazy_list.rs:29:5 | LL | /// lazy continuation | ^ @@ -85,7 +85,7 @@ LL | /// lazy continuation | ++++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:33:5 + --> tests/ui/doc/doc_lazy_list.rs:34:5 | LL | /// this will warn on the lazy continuation | ^ @@ -97,7 +97,7 @@ LL | /// this will warn on the lazy continuation | ++++++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:35:5 + --> tests/ui/doc/doc_lazy_list.rs:36:5 | LL | /// and so should this | ^^^^ @@ -109,7 +109,7 @@ LL | /// and so should this | ++ error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:56:5 + --> tests/ui/doc/doc_lazy_list.rs:57:5 | LL | /// 'protocol_descriptors': [ | ^ @@ -121,7 +121,7 @@ LL | /// 'protocol_descriptors': [ | + error: doc list item without indentation - --> tests/ui/doc/doc_lazy_list.rs:75:5 + --> tests/ui/doc/doc_lazy_list.rs:76:5 | LL | /// ] | ^ diff --git a/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.fixed b/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.fixed new file mode 100644 index 000000000000..940cff48c1e9 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.fixed @@ -0,0 +1,28 @@ +#![warn(clippy::doc_overindented_list_items)] + +#[rustfmt::skip] +/// - first list item +/// overindented line +//~^ ERROR: doc list item overindented +/// this is overindented line too +//~^ ERROR: doc list item overindented +/// - second list item +fn foo() {} + +#[rustfmt::skip] +/// - first list item +/// overindented line +//~^ ERROR: doc list item overindented +/// this is overindented line too +//~^ ERROR: doc list item overindented +/// - second list item +fn bar() {} + +#[rustfmt::skip] +/// * first list item +/// overindented line +//~^ ERROR: doc list item overindented +/// this is overindented line too +//~^ ERROR: doc list item overindented +/// * second list item +fn baz() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.rs b/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.rs new file mode 100644 index 000000000000..77f3ee8a64d4 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.rs @@ -0,0 +1,28 @@ +#![warn(clippy::doc_overindented_list_items)] + +#[rustfmt::skip] +/// - first list item +/// overindented line +//~^ ERROR: doc list item overindented +/// this is overindented line too +//~^ ERROR: doc list item overindented +/// - second list item +fn foo() {} + +#[rustfmt::skip] +/// - first list item +/// overindented line +//~^ ERROR: doc list item overindented +/// this is overindented line too +//~^ ERROR: doc list item overindented +/// - second list item +fn bar() {} + +#[rustfmt::skip] +/// * first list item +/// overindented line +//~^ ERROR: doc list item overindented +/// this is overindented line too +//~^ ERROR: doc list item overindented +/// * second list item +fn baz() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.stderr b/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.stderr new file mode 100644 index 000000000000..ff201ba5eb94 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_overindented_list_items.stderr @@ -0,0 +1,41 @@ +error: doc list item overindented + --> tests/ui/doc/doc_overindented_list_items.rs:5:5 + | +LL | /// overindented line + | ^^^^^^^ help: try using ` ` (2 spaces) + | + = note: `-D clippy::doc-overindented-list-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_overindented_list_items)]` + +error: doc list item overindented + --> tests/ui/doc/doc_overindented_list_items.rs:7:5 + | +LL | /// this is overindented line too + | ^^^^^ help: try using ` ` (2 spaces) + +error: doc list item overindented + --> tests/ui/doc/doc_overindented_list_items.rs:14:7 + | +LL | /// overindented line + | ^^^^^ help: try using ` ` (2 spaces) + +error: doc list item overindented + --> tests/ui/doc/doc_overindented_list_items.rs:16:7 + | +LL | /// this is overindented line too + | ^^^ help: try using ` ` (2 spaces) + +error: doc list item overindented + --> tests/ui/doc/doc_overindented_list_items.rs:23:5 + | +LL | /// overindented line + | ^^^^^^^ help: try using ` ` (2 spaces) + +error: doc list item overindented + --> tests/ui/doc/doc_overindented_list_items.rs:25:5 + | +LL | /// this is overindented line too + | ^^^^^ help: try using ` ` (2 spaces) + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/drain_collect_nostd.fixed b/src/tools/clippy/tests/ui/drain_collect_nostd.fixed new file mode 100644 index 000000000000..a4ab2956f2a6 --- /dev/null +++ b/src/tools/clippy/tests/ui/drain_collect_nostd.fixed @@ -0,0 +1,8 @@ +#![warn(clippy::drain_collect)] +#![no_std] +extern crate alloc; +use alloc::vec::Vec; + +fn remove_all(v: &mut Vec) -> Vec { + core::mem::take(v) +} diff --git a/src/tools/clippy/tests/ui/drain_collect_nostd.rs b/src/tools/clippy/tests/ui/drain_collect_nostd.rs new file mode 100644 index 000000000000..a8be1ce6bbd3 --- /dev/null +++ b/src/tools/clippy/tests/ui/drain_collect_nostd.rs @@ -0,0 +1,8 @@ +#![warn(clippy::drain_collect)] +#![no_std] +extern crate alloc; +use alloc::vec::Vec; + +fn remove_all(v: &mut Vec) -> Vec { + v.drain(..).collect() +} diff --git a/src/tools/clippy/tests/ui/drain_collect_nostd.stderr b/src/tools/clippy/tests/ui/drain_collect_nostd.stderr new file mode 100644 index 000000000000..91b38932fee7 --- /dev/null +++ b/src/tools/clippy/tests/ui/drain_collect_nostd.stderr @@ -0,0 +1,11 @@ +error: you seem to be trying to move all elements into a new `Vec` + --> tests/ui/drain_collect_nostd.rs:7:5 + | +LL | v.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `core::mem::take(v)` + | + = note: `-D clippy::drain-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::drain_collect)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/eta_nostd.fixed b/src/tools/clippy/tests/ui/eta_nostd.fixed new file mode 100644 index 000000000000..23059c52b67f --- /dev/null +++ b/src/tools/clippy/tests/ui/eta_nostd.fixed @@ -0,0 +1,10 @@ +#![warn(clippy::redundant_closure)] +#![no_std] + +extern crate alloc; +use alloc::vec; +use alloc::vec::Vec; + +fn issue_13895() { + let _: Option> = true.then(alloc::vec::Vec::new); +} diff --git a/src/tools/clippy/tests/ui/eta_nostd.rs b/src/tools/clippy/tests/ui/eta_nostd.rs new file mode 100644 index 000000000000..ae44ac348c64 --- /dev/null +++ b/src/tools/clippy/tests/ui/eta_nostd.rs @@ -0,0 +1,10 @@ +#![warn(clippy::redundant_closure)] +#![no_std] + +extern crate alloc; +use alloc::vec; +use alloc::vec::Vec; + +fn issue_13895() { + let _: Option> = true.then(|| vec![]); +} diff --git a/src/tools/clippy/tests/ui/eta_nostd.stderr b/src/tools/clippy/tests/ui/eta_nostd.stderr new file mode 100644 index 000000000000..4dfef43efa47 --- /dev/null +++ b/src/tools/clippy/tests/ui/eta_nostd.stderr @@ -0,0 +1,11 @@ +error: redundant closure + --> tests/ui/eta_nostd.rs:9:40 + | +LL | let _: Option> = true.then(|| vec![]); + | ^^^^^^^^^ help: replace the closure with `Vec::new`: `alloc::vec::Vec::new` + | + = note: `-D clippy::redundant-closure` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed index c250162dfb8c..67da45a348f9 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed @@ -1,6 +1,6 @@ #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::manual_repeat_n)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs index 8adbb841c8ba..423a7454bed7 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs @@ -1,6 +1,6 @@ #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::manual_repeat_n)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; diff --git a/src/tools/clippy/tests/ui/implicit_hasher.fixed b/src/tools/clippy/tests/ui/implicit_hasher.fixed index 2d6dc0274cf2..971746ae95d7 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.fixed +++ b/src/tools/clippy/tests/ui/implicit_hasher.fixed @@ -70,7 +70,7 @@ pub fn map(map: &mut HashMap) {} pub fn set(set: &mut HashSet) {} #[inline_macros] -pub mod gen { +pub mod gen_ { use super::*; inline! { impl Foo for HashMap { diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs index 0a334357bd1b..b34aa1f81374 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.rs +++ b/src/tools/clippy/tests/ui/implicit_hasher.rs @@ -70,7 +70,7 @@ pub fn map(map: &mut HashMap) {} pub fn set(set: &mut HashSet) {} #[inline_macros] -pub mod gen { +pub mod gen_ { use super::*; inline! { impl Foo for HashMap { diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr index 48c6ebc209cf..442f4789aacf 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.stderr +++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr @@ -98,7 +98,7 @@ error: impl for `HashMap` should be generalized over different hashers LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ | - = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen_` (in Nightly builds, run with -Z macro-backtrace for more info) help: add a type parameter for `BuildHasher` | LL ~ impl Foo for HashMap { diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed index 1fb1df5b4425..f6eb5a9784ac 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed @@ -50,3 +50,14 @@ fn issue_13843() { let _ = 1_000_000_u32.div_ceil(6u32); } + +fn issue_13950() { + let x = 33u32; + let _ = x.div_ceil(8); + let _ = x.div_ceil(8); + + let y = -33i32; + let _ = (y + -8) / -7; + let _ = (-8 + y) / -7; + let _ = (y - 8) / -7; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs index 4f6d38f0d145..2f063afe787d 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.rs +++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs @@ -50,3 +50,14 @@ fn issue_13843() { let _ = (1_000_000 + 6u32 - 1) / 6u32; } + +fn issue_13950() { + let x = 33u32; + let _ = (x + 7) / 8; + let _ = (7 + x) / 8; + + let y = -33i32; + let _ = (y + -8) / -7; + let _ = (-8 + y) / -7; + let _ = (y - 8) / -7; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr index 3d87fe8e0409..0bac5d8ef1c1 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr @@ -85,5 +85,17 @@ error: manually reimplementing `div_ceil` LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` -error: aborting due to 14 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:56:13 + | +LL | let _ = (x + 7) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:57:13 + | +LL | let _ = (7 + x) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed index f32b78aa14d0..01c58151bc94 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed @@ -50,3 +50,14 @@ fn issue_13843() { let _ = 1_000_000_u32.div_ceil(6u32); } + +fn issue_13950() { + let x = 33u32; + let _ = x.div_ceil(8); + let _ = x.div_ceil(8); + + let y = -33i32; + let _ = y.div_ceil(-7); + let _ = y.div_ceil(-7); + let _ = y.div_ceil(-7); +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs index 54d89fcbd462..048ff401581f 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs @@ -50,3 +50,14 @@ fn issue_13843() { let _ = (1_000_000 + 6u32 - 1) / 6u32; } + +fn issue_13950() { + let x = 33u32; + let _ = (x + 7) / 8; + let _ = (7 + x) / 8; + + let y = -33i32; + let _ = (y + -8) / -7; + let _ = (-8 + y) / -7; + let _ = (y - 8) / -7; +} diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr index c5e8c1a687cd..807cfd82724e 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr @@ -109,5 +109,35 @@ error: manually reimplementing `div_ceil` LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` -error: aborting due to 18 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:56:13 + | +LL | let _ = (x + 7) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:57:13 + | +LL | let _ = (7 + x) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:60:13 + | +LL | let _ = (y + -8) / -7; + | ^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:61:13 + | +LL | let _ = (-8 + y) / -7; + | ^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:62:13 + | +LL | let _ = (y - 8) / -7; + | ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` + +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/manual_ok_err.fixed b/src/tools/clippy/tests/ui/manual_ok_err.fixed new file mode 100644 index 000000000000..e7e0464c4787 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_ok_err.fixed @@ -0,0 +1,91 @@ +#![warn(clippy::manual_ok_err)] + +fn funcall() -> Result { + todo!() +} + +fn main() { + let _ = funcall().ok(); + + let _ = funcall().ok(); + + let _ = funcall().err(); + + let _ = funcall().err(); + + let _ = funcall().ok(); + + let _ = funcall().err(); + + #[allow(clippy::redundant_pattern)] + let _ = funcall().ok(); + + struct S; + + impl std::ops::Neg for S { + type Output = Result; + + fn neg(self) -> Self::Output { + funcall() + } + } + + // Suggestion should be properly parenthesized + let _ = (-S).ok(); + + no_lint(); +} + +fn no_lint() { + let _ = match funcall() { + Ok(v) if v > 3 => Some(v), + _ => None, + }; + + let _ = match funcall() { + Err(_) => None, + Ok(3) => None, + Ok(v) => Some(v), + }; + + let _ = match funcall() { + _ => None, + Ok(v) => Some(v), + }; + + let _ = match funcall() { + Err(_) | Ok(3) => None, + Ok(v) => Some(v), + }; + + #[expect(clippy::redundant_pattern)] + let _ = match funcall() { + _v @ _ => None, + Ok(v) => Some(v), + }; + + // Content of `Option` and matching content of `Result` do + // not have the same type. + let _: Option<&dyn std::any::Any> = match Ok::<_, ()>(&1) { + Ok(v) => Some(v), + _ => None, + }; + + let _ = match Ok::<_, ()>(&1) { + _x => None, + Ok(v) => Some(v), + }; + + let _ = match Ok::<_, std::convert::Infallible>(1) { + Ok(3) => None, + Ok(v) => Some(v), + }; +} + +const fn cf(x: Result) -> Option { + // Do not lint in const code + match x { + Ok(v) => Some(v), + Err(_) => None, + } +} diff --git a/src/tools/clippy/tests/ui/manual_ok_err.rs b/src/tools/clippy/tests/ui/manual_ok_err.rs new file mode 100644 index 000000000000..03ad773f47cf --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_ok_err.rs @@ -0,0 +1,125 @@ +#![warn(clippy::manual_ok_err)] + +fn funcall() -> Result { + todo!() +} + +fn main() { + let _ = match funcall() { + //~^ manual_ok_err + Ok(v) => Some(v), + Err(_) => None, + }; + + let _ = match funcall() { + //~^ manual_ok_err + Ok(v) => Some(v), + _v => None, + }; + + let _ = match funcall() { + //~^ manual_ok_err + Err(v) => Some(v), + Ok(_) => None, + }; + + let _ = match funcall() { + //~^ manual_ok_err + Err(v) => Some(v), + _v => None, + }; + + let _ = if let Ok(v) = funcall() { + //~^ manual_ok_err + Some(v) + } else { + None + }; + + let _ = if let Err(v) = funcall() { + //~^ manual_ok_err + Some(v) + } else { + None + }; + + #[allow(clippy::redundant_pattern)] + let _ = match funcall() { + //~^ manual_ok_err + Ok(v) => Some(v), + _v @ _ => None, + }; + + struct S; + + impl std::ops::Neg for S { + type Output = Result; + + fn neg(self) -> Self::Output { + funcall() + } + } + + // Suggestion should be properly parenthesized + let _ = match -S { + //~^ manual_ok_err + Ok(v) => Some(v), + _ => None, + }; + + no_lint(); +} + +fn no_lint() { + let _ = match funcall() { + Ok(v) if v > 3 => Some(v), + _ => None, + }; + + let _ = match funcall() { + Err(_) => None, + Ok(3) => None, + Ok(v) => Some(v), + }; + + let _ = match funcall() { + _ => None, + Ok(v) => Some(v), + }; + + let _ = match funcall() { + Err(_) | Ok(3) => None, + Ok(v) => Some(v), + }; + + #[expect(clippy::redundant_pattern)] + let _ = match funcall() { + _v @ _ => None, + Ok(v) => Some(v), + }; + + // Content of `Option` and matching content of `Result` do + // not have the same type. + let _: Option<&dyn std::any::Any> = match Ok::<_, ()>(&1) { + Ok(v) => Some(v), + _ => None, + }; + + let _ = match Ok::<_, ()>(&1) { + _x => None, + Ok(v) => Some(v), + }; + + let _ = match Ok::<_, std::convert::Infallible>(1) { + Ok(3) => None, + Ok(v) => Some(v), + }; +} + +const fn cf(x: Result) -> Option { + // Do not lint in const code + match x { + Ok(v) => Some(v), + Err(_) => None, + } +} diff --git a/src/tools/clippy/tests/ui/manual_ok_err.stderr b/src/tools/clippy/tests/ui/manual_ok_err.stderr new file mode 100644 index 000000000000..d0d5e2c81e96 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_ok_err.stderr @@ -0,0 +1,95 @@ +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:8:13 + | +LL | let _ = match funcall() { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | Err(_) => None, +LL | | }; + | |_____^ help: replace with: `funcall().ok()` + | + = note: `-D clippy::manual-ok-err` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_ok_err)]` + +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:14:13 + | +LL | let _ = match funcall() { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | _v => None, +LL | | }; + | |_____^ help: replace with: `funcall().ok()` + +error: manual implementation of `err` + --> tests/ui/manual_ok_err.rs:20:13 + | +LL | let _ = match funcall() { + | _____________^ +LL | | +LL | | Err(v) => Some(v), +LL | | Ok(_) => None, +LL | | }; + | |_____^ help: replace with: `funcall().err()` + +error: manual implementation of `err` + --> tests/ui/manual_ok_err.rs:26:13 + | +LL | let _ = match funcall() { + | _____________^ +LL | | +LL | | Err(v) => Some(v), +LL | | _v => None, +LL | | }; + | |_____^ help: replace with: `funcall().err()` + +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:32:13 + | +LL | let _ = if let Ok(v) = funcall() { + | _____________^ +LL | | +LL | | Some(v) +LL | | } else { +LL | | None +LL | | }; + | |_____^ help: replace with: `funcall().ok()` + +error: manual implementation of `err` + --> tests/ui/manual_ok_err.rs:39:13 + | +LL | let _ = if let Err(v) = funcall() { + | _____________^ +LL | | +LL | | Some(v) +LL | | } else { +LL | | None +LL | | }; + | |_____^ help: replace with: `funcall().err()` + +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:47:13 + | +LL | let _ = match funcall() { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | _v @ _ => None, +LL | | }; + | |_____^ help: replace with: `funcall().ok()` + +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:64:13 + | +LL | let _ = match -S { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | _ => None, +LL | | }; + | |_____^ help: replace with: `(-S).ok()` + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_repeat_n.fixed b/src/tools/clippy/tests/ui/manual_repeat_n.fixed new file mode 100644 index 000000000000..4235b02a89e3 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_repeat_n.fixed @@ -0,0 +1,30 @@ +#![warn(clippy::manual_repeat_n)] + +use std::iter::repeat; + +fn main() { + let _ = std::iter::repeat_n(10, 3); + + let _ = std::iter::repeat_n(String::from("foo"), 4); + + for value in std::iter::repeat_n(5, 3) {} + + let _: Vec<_> = std::iter::repeat_n(String::from("bar"), 10).collect(); + + let _ = std::iter::repeat_n(vec![1, 2], 2); +} + +mod foo_lib { + pub fn iter() -> std::iter::Take> { + todo!() + } +} + +fn foo() { + let _ = match 1 { + 1 => foo_lib::iter(), + // Shouldn't lint because `external_lib::iter` doesn't return `std::iter::RepeatN`. + 2 => std::iter::repeat([1, 2].as_slice()).take(2), + _ => todo!(), + }; +} diff --git a/src/tools/clippy/tests/ui/manual_repeat_n.rs b/src/tools/clippy/tests/ui/manual_repeat_n.rs new file mode 100644 index 000000000000..dbf9ac6a14af --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_repeat_n.rs @@ -0,0 +1,30 @@ +#![warn(clippy::manual_repeat_n)] + +use std::iter::repeat; + +fn main() { + let _ = repeat(10).take(3); + + let _ = repeat(String::from("foo")).take(4); + + for value in std::iter::repeat(5).take(3) {} + + let _: Vec<_> = std::iter::repeat(String::from("bar")).take(10).collect(); + + let _ = repeat(vec![1, 2]).take(2); +} + +mod foo_lib { + pub fn iter() -> std::iter::Take> { + todo!() + } +} + +fn foo() { + let _ = match 1 { + 1 => foo_lib::iter(), + // Shouldn't lint because `external_lib::iter` doesn't return `std::iter::RepeatN`. + 2 => std::iter::repeat([1, 2].as_slice()).take(2), + _ => todo!(), + }; +} diff --git a/src/tools/clippy/tests/ui/manual_repeat_n.stderr b/src/tools/clippy/tests/ui/manual_repeat_n.stderr new file mode 100644 index 000000000000..87395b3f8bf1 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_repeat_n.stderr @@ -0,0 +1,35 @@ +error: this `repeat().take()` can be written more concisely + --> tests/ui/manual_repeat_n.rs:6:13 + | +LL | let _ = repeat(10).take(3); + | ^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(10, 3)` + | + = note: `-D clippy::manual-repeat-n` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_repeat_n)]` + +error: this `repeat().take()` can be written more concisely + --> tests/ui/manual_repeat_n.rs:8:13 + | +LL | let _ = repeat(String::from("foo")).take(4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(String::from("foo"), 4)` + +error: this `repeat().take()` can be written more concisely + --> tests/ui/manual_repeat_n.rs:10:18 + | +LL | for value in std::iter::repeat(5).take(3) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(5, 3)` + +error: this `repeat().take()` can be written more concisely + --> tests/ui/manual_repeat_n.rs:12:21 + | +LL | let _: Vec<_> = std::iter::repeat(String::from("bar")).take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(String::from("bar"), 10)` + +error: this `repeat().take()` can be written more concisely + --> tests/ui/manual_repeat_n.rs:14:13 + | +LL | let _ = repeat(vec![1, 2]).take(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(vec![1, 2], 2)` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed index 5f2f1bd9916d..da6f36f53b0d 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.fixed +++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed @@ -1,4 +1,4 @@ -#![allow(non_local_definitions)] +#![allow(non_local_definitions, clippy::manual_repeat_n)] #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs index 3e3c7f4db4a2..686ed4fee7d1 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.rs +++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs @@ -1,4 +1,4 @@ -#![allow(non_local_definitions)] +#![allow(non_local_definitions, clippy::manual_repeat_n)] #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed index cf520e71a64f..18716e93d1e9 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed @@ -14,7 +14,7 @@ fn do_something_interesting(x: usize, y: usize) -> usize { todo!() } -macro_rules! gen { +macro_rules! r#gen { () => { (0..10).map(|_| do_something()); }; @@ -45,7 +45,7 @@ fn main() { std::iter::repeat_with(|| do_something()).take(1); std::iter::repeat_with(|| do_something()).take((1 << 4) - 0); // These should not be raised - gen!(); + r#gen!(); let lower = 2; let lower_fn = || 2; (lower..upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs index 298eee9ca3fa..596afd51e61f 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs @@ -14,7 +14,7 @@ fn do_something_interesting(x: usize, y: usize) -> usize { todo!() } -macro_rules! gen { +macro_rules! r#gen { () => { (0..10).map(|_| do_something()); }; @@ -45,7 +45,7 @@ fn main() { (9..=9).map(|_| do_something()); (1..=1 << 4).map(|_| do_something()); // These should not be raised - gen!(); + r#gen!(); let lower = 2; let lower_fn = || 2; (lower..upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed new file mode 100644 index 000000000000..65e59774905c --- /dev/null +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed @@ -0,0 +1,8 @@ +#![warn(clippy::map_with_unused_argument_over_ranges)] +#![no_std] +extern crate alloc; +use alloc::vec::Vec; + +fn nostd(v: &mut [i32]) { + let _: Vec<_> = core::iter::repeat_n(3 + 1, 10).collect(); +} diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs new file mode 100644 index 000000000000..dda7a69b33f9 --- /dev/null +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs @@ -0,0 +1,8 @@ +#![warn(clippy::map_with_unused_argument_over_ranges)] +#![no_std] +extern crate alloc; +use alloc::vec::Vec; + +fn nostd(v: &mut [i32]) { + let _: Vec<_> = (0..10).map(|_| 3 + 1).collect(); +} diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.stderr b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.stderr new file mode 100644 index 000000000000..d47f3d09175b --- /dev/null +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.stderr @@ -0,0 +1,15 @@ +error: map of a closure that does not depend on its parameter over a range + --> tests/ui/map_with_unused_argument_over_ranges_nostd.rs:7:21 + | +LL | let _: Vec<_> = (0..10).map(|_| 3 + 1).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::map-with-unused-argument-over-ranges` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_with_unused_argument_over_ranges)]` +help: remove the explicit range and use `repeat_n` + | +LL | let _: Vec<_> = core::iter::repeat_n(3 + 1, 10).collect(); + | ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/match_bool.fixed b/src/tools/clippy/tests/ui/match_bool.fixed new file mode 100644 index 000000000000..61a8e54fa10c --- /dev/null +++ b/src/tools/clippy/tests/ui/match_bool.fixed @@ -0,0 +1,58 @@ +#![deny(clippy::match_bool)] +#![allow(clippy::nonminimal_bool, clippy::eq_op)] + +fn match_bool() { + let test: bool = true; + + if test { 0 } else { 42 }; + + let option = 1; + if option == 1 { 1 } else { 0 }; + + if !test { + println!("Noooo!"); + }; + + if !test { + println!("Noooo!"); + }; + + if !(test && test) { + println!("Noooo!"); + }; + + if !test { + println!("Noooo!"); + } else { + println!("Yes!"); + }; + + // Not linted + match option { + 1..=10 => 1, + 11..=20 => 2, + _ => 3, + }; + + // Don't lint + let _ = match test { + #[cfg(feature = "foo")] + true if option == 5 => 10, + true => 0, + false => 1, + }; + + let _ = if test && option == 5 { 10 } else { 1 }; + + let _ = if !test && option == 5 { 10 } else { 1 }; + + if test && option == 5 { println!("Hello") }; + + if !(test && option == 5) { println!("Hello") }; + + if !test && option == 5 { println!("Hello") }; + + if !(!test && option == 5) { println!("Hello") }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/match_bool.rs b/src/tools/clippy/tests/ui/match_bool.rs index f84af393e47f..9c81d2917869 100644 --- a/src/tools/clippy/tests/ui/match_bool.rs +++ b/src/tools/clippy/tests/ui/match_bool.rs @@ -1,24 +1,24 @@ -//@no-rustfix: overlapping suggestions #![deny(clippy::match_bool)] +#![allow(clippy::nonminimal_bool, clippy::eq_op)] fn match_bool() { let test: bool = true; match test { - //~^ ERROR: you seem to be trying to match on a boolean expression + //~^ ERROR: `match` on a boolean expression true => 0, false => 42, }; let option = 1; match option == 1 { - //~^ ERROR: you seem to be trying to match on a boolean expression + //~^ ERROR: `match` on a boolean expression true => 1, false => 0, }; match test { - //~^ ERROR: you seem to be trying to match on a boolean expression + //~^ ERROR: `match` on a boolean expression true => (), false => { println!("Noooo!"); @@ -26,7 +26,7 @@ fn match_bool() { }; match test { - //~^ ERROR: you seem to be trying to match on a boolean expression + //~^ ERROR: `match` on a boolean expression false => { println!("Noooo!"); }, @@ -34,11 +34,7 @@ fn match_bool() { }; match test && test { - //~^ ERROR: this boolean expression can be simplified - //~| NOTE: `-D clippy::nonminimal-bool` implied by `-D warnings` - //~| ERROR: you seem to be trying to match on a boolean expression - //~| ERROR: equal expressions as operands to `&&` - //~| NOTE: `#[deny(clippy::eq_op)]` on by default + //~^ ERROR: `match` on a boolean expression false => { println!("Noooo!"); }, @@ -46,7 +42,7 @@ fn match_bool() { }; match test { - //~^ ERROR: you seem to be trying to match on a boolean expression + //~^ ERROR: `match` on a boolean expression false => { println!("Noooo!"); }, @@ -69,6 +65,42 @@ fn match_bool() { true => 0, false => 1, }; + + let _ = match test { + //~^ ERROR: `match` on a boolean expression + true if option == 5 => 10, + _ => 1, + }; + + let _ = match test { + //~^ ERROR: `match` on a boolean expression + false if option == 5 => 10, + _ => 1, + }; + + match test { + //~^ ERROR: `match` on a boolean expression + true if option == 5 => println!("Hello"), + _ => (), + }; + + match test { + //~^ ERROR: `match` on a boolean expression + true if option == 5 => (), + _ => println!("Hello"), + }; + + match test { + //~^ ERROR: `match` on a boolean expression + false if option == 5 => println!("Hello"), + _ => (), + }; + + match test { + //~^ ERROR: `match` on a boolean expression + false if option == 5 => (), + _ => println!("Hello"), + }; } fn main() {} diff --git a/src/tools/clippy/tests/ui/match_bool.stderr b/src/tools/clippy/tests/ui/match_bool.stderr index fb24e67eceef..a4e504a0a82e 100644 --- a/src/tools/clippy/tests/ui/match_bool.stderr +++ b/src/tools/clippy/tests/ui/match_bool.stderr @@ -1,13 +1,4 @@ -error: this boolean expression can be simplified - --> tests/ui/match_bool.rs:36:11 - | -LL | match test && test { - | ^^^^^^^^^^^^ help: try: `test` - | - = note: `-D clippy::nonminimal-bool` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` - -error: you seem to be trying to match on a boolean expression +error: `match` on a boolean expression --> tests/ui/match_bool.rs:7:5 | LL | / match test { @@ -18,12 +9,12 @@ LL | | }; | |_____^ help: consider using an `if`/`else` expression: `if test { 0 } else { 42 }` | note: the lint level is defined here - --> tests/ui/match_bool.rs:2:9 + --> tests/ui/match_bool.rs:1:9 | LL | #![deny(clippy::match_bool)] | ^^^^^^^^^^^^^^^^^^ -error: you seem to be trying to match on a boolean expression +error: `match` on a boolean expression --> tests/ui/match_bool.rs:14:5 | LL | / match option == 1 { @@ -33,7 +24,7 @@ LL | | false => 0, LL | | }; | |_____^ help: consider using an `if`/`else` expression: `if option == 1 { 1 } else { 0 }` -error: you seem to be trying to match on a boolean expression +error: `match` on a boolean expression --> tests/ui/match_bool.rs:20:5 | LL | / match test { @@ -52,7 +43,7 @@ LL + println!("Noooo!"); LL ~ }; | -error: you seem to be trying to match on a boolean expression +error: `match` on a boolean expression --> tests/ui/match_bool.rs:28:5 | LL | / match test { @@ -71,11 +62,14 @@ LL + println!("Noooo!"); LL ~ }; | -error: you seem to be trying to match on a boolean expression +error: `match` on a boolean expression --> tests/ui/match_bool.rs:36:5 | LL | / match test && test { -... | +LL | | +LL | | false => { +LL | | println!("Noooo!"); +LL | | }, LL | | _ => (), LL | | }; | |_____^ @@ -87,16 +81,8 @@ LL + println!("Noooo!"); LL ~ }; | -error: equal expressions as operands to `&&` - --> tests/ui/match_bool.rs:36:11 - | -LL | match test && test { - | ^^^^^^^^^^^^ - | - = note: `#[deny(clippy::eq_op)]` on by default - -error: you seem to be trying to match on a boolean expression - --> tests/ui/match_bool.rs:48:5 +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:44:5 | LL | / match test { LL | | @@ -109,12 +95,74 @@ LL | | }; | help: consider using an `if`/`else` expression | -LL ~ if test { -LL + println!("Yes!"); -LL + } else { +LL ~ if !test { LL + println!("Noooo!"); +LL + } else { +LL + println!("Yes!"); LL ~ }; | -error: aborting due to 8 previous errors +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:69:13 + | +LL | let _ = match test { + | _____________^ +LL | | +LL | | true if option == 5 => 10, +LL | | _ => 1, +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if test && option == 5 { 10 } else { 1 }` + +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:75:13 + | +LL | let _ = match test { + | _____________^ +LL | | +LL | | false if option == 5 => 10, +LL | | _ => 1, +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if !test && option == 5 { 10 } else { 1 }` + +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:81:5 + | +LL | / match test { +LL | | +LL | | true if option == 5 => println!("Hello"), +LL | | _ => (), +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if test && option == 5 { println!("Hello") }` + +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:87:5 + | +LL | / match test { +LL | | +LL | | true if option == 5 => (), +LL | | _ => println!("Hello"), +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if !(test && option == 5) { println!("Hello") }` + +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:93:5 + | +LL | / match test { +LL | | +LL | | false if option == 5 => println!("Hello"), +LL | | _ => (), +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if !test && option == 5 { println!("Hello") }` + +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:99:5 + | +LL | / match test { +LL | | +LL | | false if option == 5 => (), +LL | | _ => println!("Hello"), +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if !(!test && option == 5) { println!("Hello") }` + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index fdde68790a8c..cdfdcd5007a8 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -210,3 +210,9 @@ mod with_ty_alias { let _: Foo = 1; } } + +// Do not lint because mutable references in const functions are unstable in 1.82 +#[clippy::msrv = "1.82"] +fn mut_add(x: &mut i32) { + *x += 1; +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed index dd9dedcdd044..689060468c57 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -213,3 +213,8 @@ mod extern_fn { const extern "system-unwind" fn system_unwind() {} //~^ ERROR: this could be a `const fn` } + +const fn mut_add(x: &mut i32) { + //~^ ERROR: this could be a `const fn` + *x += 1; +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index f974478540cd..492c47d7e49b 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -213,3 +213,8 @@ mod extern_fn { extern "system-unwind" fn system_unwind() {} //~^ ERROR: this could be a `const fn` } + +fn mut_add(x: &mut i32) { + //~^ ERROR: this could be a `const fn` + *x += 1; +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 33836bdfe9f8..a06703e2ebf2 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -316,5 +316,19 @@ help: make the function `const` LL | const extern "system-unwind" fn system_unwind() {} | +++++ -error: aborting due to 24 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:217:1 + | +LL | / fn mut_add(x: &mut i32) { +LL | | +LL | | *x += 1; +LL | | } + | |_^ + | +help: make the function `const` + | +LL | const fn mut_add(x: &mut i32) { + | +++++ + +error: aborting due to 25 previous errors diff --git a/src/tools/clippy/tests/ui/needless_as_bytes.fixed b/src/tools/clippy/tests/ui/needless_as_bytes.fixed index 042342311fdf..74b4ba5be798 100644 --- a/src/tools/clippy/tests/ui/needless_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/needless_as_bytes.fixed @@ -1,5 +1,6 @@ #![warn(clippy::needless_as_bytes)] #![allow(clippy::const_is_empty)] +#![feature(exact_size_is_empty)] struct S; @@ -7,6 +8,9 @@ impl S { fn as_bytes(&self) -> &[u8] { &[] } + fn bytes(&self) -> &[u8] { + &[] + } } fn main() { @@ -15,6 +19,11 @@ fn main() { println!("len = {}", "some string".len()); //~^ needless_as_bytes } + if "some string".is_empty() { + //~^ needless_as_bytes + println!("len = {}", "some string".len()); + //~^ needless_as_bytes + } let s = String::from("yet another string"); if s.is_empty() { @@ -22,6 +31,11 @@ fn main() { println!("len = {}", s.len()); //~^ needless_as_bytes } + if s.is_empty() { + //~^ needless_as_bytes + println!("len = {}", s.len()); + //~^ needless_as_bytes + } // Do not lint let _ = S.as_bytes().is_empty(); @@ -36,6 +50,18 @@ fn main() { }; } m!(1).as_bytes().len(); + let _ = S.bytes().is_empty(); + let _ = S.bytes().len(); + let _ = (&String::new() as &dyn Bytes).bytes().len(); + macro_rules! m { + (1) => { + "" + }; + (2) => { + "".bytes() + }; + } + m!(1).bytes().len(); m!(2).len(); } @@ -48,3 +74,13 @@ impl AsBytes for String { &[] } } + +pub trait Bytes { + fn bytes(&self) -> &[u8]; +} + +impl Bytes for String { + fn bytes(&self) -> &[u8] { + &[] + } +} diff --git a/src/tools/clippy/tests/ui/needless_as_bytes.rs b/src/tools/clippy/tests/ui/needless_as_bytes.rs index c481e041e0ab..ffcce60bbbef 100644 --- a/src/tools/clippy/tests/ui/needless_as_bytes.rs +++ b/src/tools/clippy/tests/ui/needless_as_bytes.rs @@ -1,5 +1,6 @@ #![warn(clippy::needless_as_bytes)] #![allow(clippy::const_is_empty)] +#![feature(exact_size_is_empty)] struct S; @@ -7,6 +8,9 @@ impl S { fn as_bytes(&self) -> &[u8] { &[] } + fn bytes(&self) -> &[u8] { + &[] + } } fn main() { @@ -15,6 +19,11 @@ fn main() { println!("len = {}", "some string".as_bytes().len()); //~^ needless_as_bytes } + if "some string".bytes().is_empty() { + //~^ needless_as_bytes + println!("len = {}", "some string".bytes().len()); + //~^ needless_as_bytes + } let s = String::from("yet another string"); if s.as_bytes().is_empty() { @@ -22,6 +31,11 @@ fn main() { println!("len = {}", s.as_bytes().len()); //~^ needless_as_bytes } + if s.bytes().is_empty() { + //~^ needless_as_bytes + println!("len = {}", s.bytes().len()); + //~^ needless_as_bytes + } // Do not lint let _ = S.as_bytes().is_empty(); @@ -36,6 +50,18 @@ fn main() { }; } m!(1).as_bytes().len(); + let _ = S.bytes().is_empty(); + let _ = S.bytes().len(); + let _ = (&String::new() as &dyn Bytes).bytes().len(); + macro_rules! m { + (1) => { + "" + }; + (2) => { + "".bytes() + }; + } + m!(1).bytes().len(); m!(2).len(); } @@ -48,3 +74,13 @@ impl AsBytes for String { &[] } } + +pub trait Bytes { + fn bytes(&self) -> &[u8]; +} + +impl Bytes for String { + fn bytes(&self) -> &[u8] { + &[] + } +} diff --git a/src/tools/clippy/tests/ui/needless_as_bytes.stderr b/src/tools/clippy/tests/ui/needless_as_bytes.stderr index 3391238a142b..138c6630ae7d 100644 --- a/src/tools/clippy/tests/ui/needless_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/needless_as_bytes.stderr @@ -1,5 +1,5 @@ -error: needless call to `as_bytes()` - --> tests/ui/needless_as_bytes.rs:13:8 +error: needless call to `as_bytes` + --> tests/ui/needless_as_bytes.rs:17:8 | LL | if "some string".as_bytes().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `"some string".is_empty()` @@ -7,23 +7,47 @@ LL | if "some string".as_bytes().is_empty() { = note: `-D clippy::needless-as-bytes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_as_bytes)]` -error: needless call to `as_bytes()` - --> tests/ui/needless_as_bytes.rs:15:30 +error: needless call to `as_bytes` + --> tests/ui/needless_as_bytes.rs:19:30 | LL | println!("len = {}", "some string".as_bytes().len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `"some string".len()` -error: needless call to `as_bytes()` - --> tests/ui/needless_as_bytes.rs:20:8 +error: needless call to `bytes` + --> tests/ui/needless_as_bytes.rs:22:8 + | +LL | if "some string".bytes().is_empty() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `"some string".is_empty()` + +error: needless call to `bytes` + --> tests/ui/needless_as_bytes.rs:24:30 + | +LL | println!("len = {}", "some string".bytes().len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `"some string".len()` + +error: needless call to `as_bytes` + --> tests/ui/needless_as_bytes.rs:29:8 | LL | if s.as_bytes().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `s.is_empty()` -error: needless call to `as_bytes()` - --> tests/ui/needless_as_bytes.rs:22:30 +error: needless call to `as_bytes` + --> tests/ui/needless_as_bytes.rs:31:30 | LL | println!("len = {}", s.as_bytes().len()); | ^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `s.len()` -error: aborting due to 4 previous errors +error: needless call to `bytes` + --> tests/ui/needless_as_bytes.rs:34:8 + | +LL | if s.bytes().is_empty() { + | ^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `s.is_empty()` + +error: needless call to `bytes` + --> tests/ui/needless_as_bytes.rs:36:30 + | +LL | println!("len = {}", s.bytes().len()); + | ^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `s.len()` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 6db870490445..b4bd53ce7bf7 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -270,3 +270,14 @@ fn issue8911() -> u32 { 3 } + +macro_rules! issue13776_mac { + ($var:expr, $val:literal) => { + $var = $val; + }; +} + +fn issue13776() { + let x; + issue13776_mac!(x, 10); // should not lint +} diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index c1e86212a08b..e25483625a68 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -270,3 +270,14 @@ fn issue8911() -> u32 { 3 } + +macro_rules! issue13776_mac { + ($var:expr, $val:literal) => { + $var = $val; + }; +} + +fn issue13776() { + let x; + issue13776_mac!(x, 10); // should not lint +} diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index 8196d608abd2..86cf9a9cdb63 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -6,6 +6,7 @@ clippy::boxed_local, clippy::extra_unused_type_parameters, clippy::needless_pass_by_value, + clippy::redundant_allocation, clippy::unnecessary_wraps, dyn_drop, clippy::get_first @@ -443,11 +444,20 @@ mod issue7296 { fn implicit_mut(&mut self) -> &() { &() } - - fn explicit<'a>(self: &'a Arc) -> &'a () { + #[clippy::msrv = "1.81"] + fn explicit(self: &Arc) -> &() { &() } - fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { + #[clippy::msrv = "1.81"] + fn explicit_mut(self: &mut Rc) -> &() { + &() + } + #[clippy::msrv = "1.80"] + fn explicit_older<'a>(self: &'a Arc) -> &'a () { + &() + } + #[clippy::msrv = "1.80"] + fn explicit_mut_older<'a>(self: &'a mut Rc) -> &'a () { &() } @@ -462,8 +472,16 @@ mod issue7296 { &() } - fn explicit<'a>(self: &'a Arc) -> &'a (); - fn explicit_provided<'a>(self: &'a Arc) -> &'a () { + #[clippy::msrv = "1.81"] + fn explicit(self: &Arc) -> &(); + #[clippy::msrv = "1.81"] + fn explicit_provided(self: &Arc) -> &() { + &() + } + #[clippy::msrv = "1.80"] + fn explicit_older<'a>(self: &'a Arc) -> &'a (); + #[clippy::msrv = "1.80"] + fn explicit_provided_older<'a>(self: &'a Arc) -> &'a () { &() } @@ -576,4 +594,85 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } +mod issue13923 { + struct Py<'py> { + data: &'py str, + } + + enum Content<'t, 'py> { + Py(Py<'py>), + T1(&'t str), + T2(&'t str), + } + + enum ContentString<'t> { + T1(&'t str), + T2(&'t str), + } + + impl<'t, 'py> ContentString<'t> { + // `'py` cannot be elided + fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t> ContentString<'t> { + // `'py` can be elided because of `&self` + fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t> ContentString<'t> { + // `'py` can be elided because of `&'_ self` + fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` + fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + impl<'t> ContentString<'t> { + // `'py` can be elided because of `&Self` + fn map_content5( + self: std::pin::Pin<&Self>, + f: impl FnOnce(&'t str) -> &'t str, + o: &'t str, + ) -> Content<'t, '_> { + match *self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + struct Cx<'a, 'b> { + a: &'a u32, + b: &'b u32, + } + + // `'c` cannot be elided because we have several input lifetimes + fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { + x.b + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index b55dd99c46d0..1ee0f4c6092a 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -6,6 +6,7 @@ clippy::boxed_local, clippy::extra_unused_type_parameters, clippy::needless_pass_by_value, + clippy::redundant_allocation, clippy::unnecessary_wraps, dyn_drop, clippy::get_first @@ -443,13 +444,22 @@ mod issue7296 { fn implicit_mut<'a>(&'a mut self) -> &'a () { &() } - + #[clippy::msrv = "1.81"] fn explicit<'a>(self: &'a Arc) -> &'a () { &() } + #[clippy::msrv = "1.81"] fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { &() } + #[clippy::msrv = "1.80"] + fn explicit_older<'a>(self: &'a Arc) -> &'a () { + &() + } + #[clippy::msrv = "1.80"] + fn explicit_mut_older<'a>(self: &'a mut Rc) -> &'a () { + &() + } fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { &() @@ -462,10 +472,18 @@ mod issue7296 { &() } + #[clippy::msrv = "1.81"] fn explicit<'a>(self: &'a Arc) -> &'a (); + #[clippy::msrv = "1.81"] fn explicit_provided<'a>(self: &'a Arc) -> &'a () { &() } + #[clippy::msrv = "1.80"] + fn explicit_older<'a>(self: &'a Arc) -> &'a (); + #[clippy::msrv = "1.80"] + fn explicit_provided_older<'a>(self: &'a Arc) -> &'a () { + &() + } fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { @@ -576,4 +594,85 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } +mod issue13923 { + struct Py<'py> { + data: &'py str, + } + + enum Content<'t, 'py> { + Py(Py<'py>), + T1(&'t str), + T2(&'t str), + } + + enum ContentString<'t> { + T1(&'t str), + T2(&'t str), + } + + impl<'t, 'py> ContentString<'t> { + // `'py` cannot be elided + fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` can be elided because of `&self` + fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` can be elided because of `&'_ self` + fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` + fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` can be elided because of `&Self` + fn map_content5( + self: std::pin::Pin<&Self>, + f: impl FnOnce(&'t str) -> &'t str, + o: &'t str, + ) -> Content<'t, 'py> { + match *self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + struct Cx<'a, 'b> { + a: &'a u32, + b: &'b u32, + } + + // `'c` cannot be elided because we have several input lifetimes + fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { + &x.b + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index e56c914cc86d..465d529bf16c 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -1,5 +1,5 @@ error: elided lifetime has a name - --> tests/ui/needless_lifetimes.rs:266:52 + --> tests/ui/needless_lifetimes.rs:267:52 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | -- ^ this elided lifetime gets resolved as `'a` @@ -10,7 +10,7 @@ LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]` error: the following explicit lifetimes could be elided: 'a, 'b - --> tests/ui/needless_lifetimes.rs:17:23 + --> tests/ui/needless_lifetimes.rs:18:23 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^ ^^ ^^ ^^ @@ -24,7 +24,7 @@ LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} | error: the following explicit lifetimes could be elided: 'a, 'b - --> tests/ui/needless_lifetimes.rs:19:24 + --> tests/ui/needless_lifetimes.rs:20:24 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^ ^^ ^^ ^^ @@ -36,7 +36,7 @@ LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:29:15 + --> tests/ui/needless_lifetimes.rs:30:15 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^ ^^ ^^ @@ -48,7 +48,7 @@ LL + fn in_and_out(x: &u8, _y: u8) -> &u8 { | error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:41:31 + --> tests/ui/needless_lifetimes.rs:42:31 | LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { | ^^ ^^ @@ -60,7 +60,7 @@ LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:48:27 + --> tests/ui/needless_lifetimes.rs:49:27 | LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 { | ^^ ^^ @@ -72,7 +72,7 @@ LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 { | error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:65:26 + --> tests/ui/needless_lifetimes.rs:66:26 | LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { | ^^ ^^ @@ -84,7 +84,7 @@ LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:72:22 + --> tests/ui/needless_lifetimes.rs:73:22 | LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> { | ^^ ^^ @@ -96,7 +96,7 @@ LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:81:21 + --> tests/ui/needless_lifetimes.rs:82:21 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^ ^^ ^^ @@ -108,7 +108,7 @@ LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:86:28 + --> tests/ui/needless_lifetimes.rs:87:28 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^ ^^ ^^ @@ -120,7 +120,7 @@ LL + fn where_clause_without_lt(x: &u8, _y: u8) -> Result<&u8, ()> | error: the following explicit lifetimes could be elided: 'a, 'b - --> tests/ui/needless_lifetimes.rs:98:21 + --> tests/ui/needless_lifetimes.rs:99:21 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^ ^^ ^^ ^^ @@ -132,7 +132,7 @@ LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:122:15 + --> tests/ui/needless_lifetimes.rs:123:15 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^ ^^ ^^ @@ -144,7 +144,7 @@ LL + fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> | error: the following explicit lifetimes could be elided: 's - --> tests/ui/needless_lifetimes.rs:152:21 + --> tests/ui/needless_lifetimes.rs:153:21 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^ ^^ ^^ @@ -156,7 +156,7 @@ LL + fn self_and_out(&self) -> &u8 { | error: the following explicit lifetimes could be elided: 't - --> tests/ui/needless_lifetimes.rs:159:30 + --> tests/ui/needless_lifetimes.rs:160:30 | LL | fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { | ^^ ^^ @@ -168,7 +168,7 @@ LL + fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 { | error: the following explicit lifetimes could be elided: 's - --> tests/ui/needless_lifetimes.rs:166:26 + --> tests/ui/needless_lifetimes.rs:167:26 | LL | fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 { | ^^ ^^ @@ -180,7 +180,7 @@ LL + fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 { | error: the following explicit lifetimes could be elided: 's, 't - --> tests/ui/needless_lifetimes.rs:170:29 + --> tests/ui/needless_lifetimes.rs:171:29 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^ ^^ ^^ ^^ @@ -192,7 +192,7 @@ LL + fn distinct_self_and_in(&self, _x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:189:19 + --> tests/ui/needless_lifetimes.rs:190:19 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^ ^^ ^^ @@ -204,7 +204,7 @@ LL + fn struct_with_lt(_foo: Foo<'_>) -> &str { | error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:207:25 + --> tests/ui/needless_lifetimes.rs:208:25 | LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { | ^^ ^^ @@ -216,7 +216,7 @@ LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:215:21 + --> tests/ui/needless_lifetimes.rs:216:21 | LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str { | ^^ ^^ @@ -228,7 +228,7 @@ LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:230:22 + --> tests/ui/needless_lifetimes.rs:231:22 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^ ^^ ^^ @@ -240,7 +240,7 @@ LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:236:18 + --> tests/ui/needless_lifetimes.rs:237:18 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^ ^^ ^^ @@ -252,7 +252,7 @@ LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str { | error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:254:24 + --> tests/ui/needless_lifetimes.rs:255:24 | LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { | ^^ ^^ @@ -264,7 +264,7 @@ LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:262:20 + --> tests/ui/needless_lifetimes.rs:263:20 | LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str { | ^^ ^^ @@ -276,7 +276,7 @@ LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:266:30 + --> tests/ui/needless_lifetimes.rs:267:30 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^ ^^ ^ @@ -288,7 +288,7 @@ LL + fn named_input_elided_output(_arg: &str) -> &str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:274:19 + --> tests/ui/needless_lifetimes.rs:275:19 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^ ^^ @@ -300,7 +300,7 @@ LL + fn trait_bound_ok>(_: &u8, _: T) { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:310:24 + --> tests/ui/needless_lifetimes.rs:311:24 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^ ^^ ^^ @@ -312,7 +312,7 @@ LL + fn out_return_type_lts(e: &str) -> Cow<'_> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:317:24 + --> tests/ui/needless_lifetimes.rs:318:24 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^ ^^ @@ -324,7 +324,7 @@ LL + fn needless_lt(x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:321:24 + --> tests/ui/needless_lifetimes.rs:322:24 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^ ^^ @@ -336,7 +336,7 @@ LL + fn needless_lt(_x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:332:10 + --> tests/ui/needless_lifetimes.rs:333:10 | LL | impl<'a> Foo for Baz<'a> {} | ^^ ^^ @@ -348,7 +348,7 @@ LL + impl Foo for Baz<'_> {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:334:16 + --> tests/ui/needless_lifetimes.rs:335:16 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^ ^^ ^^ @@ -360,7 +360,7 @@ LL + fn baz(&self) -> impl Foo + '_ { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:366:55 + --> tests/ui/needless_lifetimes.rs:367:55 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^ ^^ ^^ @@ -372,7 +372,7 @@ LL + fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(& | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:375:26 + --> tests/ui/needless_lifetimes.rs:376:26 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^ ^^ ^^ @@ -384,7 +384,7 @@ LL + fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:387:30 + --> tests/ui/needless_lifetimes.rs:388:30 | LL | fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^ ^^ ^^ @@ -396,7 +396,7 @@ LL + fn where_clause_elidable(i: &i32, f: T) -> &i32 | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:402:28 + --> tests/ui/needless_lifetimes.rs:403:28 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^ ^^ ^^ @@ -408,7 +408,7 @@ LL + fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:415:28 + --> tests/ui/needless_lifetimes.rs:416:28 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^ ^^ @@ -420,7 +420,7 @@ LL + fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:418:28 + --> tests/ui/needless_lifetimes.rs:419:28 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^ ^^ @@ -432,7 +432,7 @@ LL + fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:440:21 + --> tests/ui/needless_lifetimes.rs:441:21 | LL | fn implicit<'a>(&'a self) -> &'a () { | ^^ ^^ ^^ @@ -444,7 +444,7 @@ LL + fn implicit(&self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:443:25 + --> tests/ui/needless_lifetimes.rs:444:25 | LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { | ^^ ^^ ^^ @@ -456,7 +456,31 @@ LL + fn implicit_mut(&mut self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:454:31 + --> tests/ui/needless_lifetimes.rs:448:21 + | +LL | fn explicit<'a>(self: &'a Arc) -> &'a () { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn explicit<'a>(self: &'a Arc) -> &'a () { +LL + fn explicit(self: &Arc) -> &() { + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/needless_lifetimes.rs:452:25 + | +LL | fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { +LL + fn explicit_mut(self: &mut Rc) -> &() { + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/needless_lifetimes.rs:464:31 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { | ^^ ^^ ^^ @@ -468,7 +492,7 @@ LL + fn lifetime_elsewhere(self: Box, here: &()) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:460:21 + --> tests/ui/needless_lifetimes.rs:470:21 | LL | fn implicit<'a>(&'a self) -> &'a (); | ^^ ^^ ^^ @@ -480,7 +504,7 @@ LL + fn implicit(&self) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:461:30 + --> tests/ui/needless_lifetimes.rs:471:30 | LL | fn implicit_provided<'a>(&'a self) -> &'a () { | ^^ ^^ ^^ @@ -492,7 +516,31 @@ LL + fn implicit_provided(&self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:470:31 + --> tests/ui/needless_lifetimes.rs:476:21 + | +LL | fn explicit<'a>(self: &'a Arc) -> &'a (); + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn explicit<'a>(self: &'a Arc) -> &'a (); +LL + fn explicit(self: &Arc) -> &(); + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/needless_lifetimes.rs:478:30 + | +LL | fn explicit_provided<'a>(self: &'a Arc) -> &'a () { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn explicit_provided<'a>(self: &'a Arc) -> &'a () { +LL + fn explicit_provided(self: &Arc) -> &() { + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/needless_lifetimes.rs:488:31 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); | ^^ ^^ ^^ @@ -504,7 +552,7 @@ LL + fn lifetime_elsewhere(self: Box, here: &()) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:471:40 + --> tests/ui/needless_lifetimes.rs:489:40 | LL | fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { | ^^ ^^ ^^ @@ -516,7 +564,7 @@ LL + fn lifetime_elsewhere_provided(self: Box, here: &()) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:480:12 + --> tests/ui/needless_lifetimes.rs:498:12 | LL | fn foo<'a>(x: &'a u8, y: &'_ u8) {} | ^^ ^^ @@ -528,7 +576,7 @@ LL + fn foo(x: &u8, y: &'_ u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:482:12 + --> tests/ui/needless_lifetimes.rs:500:12 | LL | fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} | ^^ ^^ @@ -540,7 +588,7 @@ LL + fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:489:18 + --> tests/ui/needless_lifetimes.rs:507:18 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { | ^^ ^^ ^^ @@ -552,7 +600,7 @@ LL + fn one_input(x: &u8) -> &u8 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:494:42 + --> tests/ui/needless_lifetimes.rs:512:42 | LL | fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 { | ^^ ^^ @@ -564,7 +612,7 @@ LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:510:22 + --> tests/ui/needless_lifetimes.rs:528:22 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { | ^^ ^^ ^^ @@ -576,5 +624,64 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { LL + fn one_input(x: &u8) -> &u8 { | -error: aborting due to 48 previous errors +error: the following explicit lifetimes could be elided: 'py + --> tests/ui/needless_lifetimes.rs:623:14 + | +LL | impl<'t, 'py> ContentString<'t> { + | ^^^ +LL | // `'py` can be elided because of `&self` +LL | fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + | ^^^ + | +help: elide the lifetimes + | +LL ~ impl<'t> ContentString<'t> { +LL | // `'py` can be elided because of `&self` +LL ~ fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + | + +error: the following explicit lifetimes could be elided: 'py + --> tests/ui/needless_lifetimes.rs:633:14 + | +LL | impl<'t, 'py> ContentString<'t> { + | ^^^ +LL | // `'py` can be elided because of `&'_ self` +LL | fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + | ^^^ + | +help: elide the lifetimes + | +LL ~ impl<'t> ContentString<'t> { +LL | // `'py` can be elided because of `&'_ self` +LL ~ fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + | + +error: the following explicit lifetimes could be elided: 'py + --> tests/ui/needless_lifetimes.rs:653:14 + | +LL | impl<'t, 'py> ContentString<'t> { + | ^^^ +... +LL | ) -> Content<'t, 'py> { + | ^^^ + | +help: elide the lifetimes + | +LL ~ impl<'t> ContentString<'t> { +LL | // `'py` can be elided because of `&Self` +... +LL | o: &'t str, +LL ~ ) -> Content<'t, '_> { + | + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_lifetimes.rs:674:9 + | +LL | &x.b + | ^^^^ help: change this to: `x.b` + | + = note: `-D clippy::needless-borrow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` + +error: aborting due to 56 previous errors diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/auxiliary/lazy_static.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/auxiliary/lazy_static.rs new file mode 100644 index 000000000000..85fb4e66079f --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/auxiliary/lazy_static.rs @@ -0,0 +1,20 @@ +//! **FAKE** lazy_static crate. + +#[macro_export] +macro_rules! lazy_static { + (static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { + static $N : &::core::marker::PhantomData<$T> = &::core::marker::PhantomData; + + $crate::lazy_static! { $($t)* } + }; + () => () +} + +#[macro_export] +macro_rules! external { + () => { + $crate::lazy_static! { + static ref LZ_DERP: u32 = 12; + } + }; +} diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/auxiliary/once_cell.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/auxiliary/once_cell.rs new file mode 100644 index 000000000000..e860a0f7572c --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/auxiliary/once_cell.rs @@ -0,0 +1,55 @@ +//! **FAKE** once_cell crate. + +pub mod sync { + use std::marker::PhantomData; + + pub struct Lazy T> { + cell: PhantomData, + init: F, + } + unsafe impl Sync for Lazy {} + impl Lazy { + pub const fn new(f: F) -> Lazy { + Lazy { + cell: PhantomData, + init: f, + } + } + + pub fn into_value(this: Lazy) -> Result { + unimplemented!() + } + + pub fn force(_this: &Lazy) -> &T { + unimplemented!() + } + + pub fn force_mut(_this: &mut Lazy) -> &mut T { + unimplemented!() + } + + pub fn get(_this: &Lazy) -> Option<&T> { + unimplemented!() + } + + pub fn get_mut(_this: &mut Lazy) -> Option<&mut T> { + unimplemented!() + } + } +} +pub mod race { + pub struct OnceBox(T); + + impl OnceBox { + pub fn get(&self) -> Option<&T> { + Some(&self.0) + } + } +} + +#[macro_export] +macro_rules! external { + () => { + static OC_DERP: $crate::sync::Lazy = $crate::sync::Lazy::new(|| 12); + }; +} diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed new file mode 100644 index 000000000000..f7c56b6fffe8 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed @@ -0,0 +1,72 @@ +//@aux-build:once_cell.rs +//@aux-build:lazy_static.rs + +#![warn(clippy::non_std_lazy_statics)] +#![allow(static_mut_refs)] + +use once_cell::sync::Lazy; + +fn main() {} + +static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); +//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| { + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + let x = "bar"; + x.to_uppercase() +}); +static LAZY_BAZ: std::sync::LazyLock = { std::sync::LazyLock::new(|| "baz".to_uppercase()) }; +//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +static LAZY_QUX: std::sync::LazyLock = { + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + if "qux".len() == 3 { + std::sync::LazyLock::new(|| "qux".to_uppercase()) + } else if "qux".is_ascii() { + std::sync::LazyLock::new(|| "qux".to_lowercase()) + } else { + std::sync::LazyLock::new(|| "qux".to_string()) + } +}; + +fn non_static() { + let _: Lazy = Lazy::new(|| 1); + let _: Lazy = Lazy::new(|| String::from("hello")); + #[allow(clippy::declare_interior_mutable_const)] + const DONT_DO_THIS: Lazy = Lazy::new(|| 1); +} + +mod once_cell_lazy_with_fns { + use once_cell::sync::Lazy; + + static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "bar".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + static mut LAZY_BAZ: std::sync::LazyLock = std::sync::LazyLock::new(|| "baz".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + + fn calling_replaceable_fns() { + let _ = std::sync::LazyLock::force(&LAZY_FOO); + let _ = std::sync::LazyLock::force(&LAZY_BAR); + unsafe { + let _ = std::sync::LazyLock::force(&LAZY_BAZ); + } + } +} + +#[clippy::msrv = "1.79"] +mod msrv_not_meet { + use lazy_static::lazy_static; + use once_cell::sync::Lazy; + + static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + + lazy_static! { + static ref LAZY_BAZ: f64 = 12.159 * 548; + } +} + +mod external_macros { + once_cell::external!(); + lazy_static::external!(); +} diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs new file mode 100644 index 000000000000..90bc428137ce --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs @@ -0,0 +1,72 @@ +//@aux-build:once_cell.rs +//@aux-build:lazy_static.rs + +#![warn(clippy::non_std_lazy_statics)] +#![allow(static_mut_refs)] + +use once_cell::sync::Lazy; + +fn main() {} + +static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); +//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +static LAZY_BAR: Lazy = Lazy::new(|| { + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + let x = "bar"; + x.to_uppercase() +}); +static LAZY_BAZ: Lazy = { Lazy::new(|| "baz".to_uppercase()) }; +//~^ ERROR: this type has been superceded by `LazyLock` in the standard library +static LAZY_QUX: Lazy = { + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + if "qux".len() == 3 { + Lazy::new(|| "qux".to_uppercase()) + } else if "qux".is_ascii() { + Lazy::new(|| "qux".to_lowercase()) + } else { + Lazy::new(|| "qux".to_string()) + } +}; + +fn non_static() { + let _: Lazy = Lazy::new(|| 1); + let _: Lazy = Lazy::new(|| String::from("hello")); + #[allow(clippy::declare_interior_mutable_const)] + const DONT_DO_THIS: Lazy = Lazy::new(|| 1); +} + +mod once_cell_lazy_with_fns { + use once_cell::sync::Lazy; + + static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + static LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + + fn calling_replaceable_fns() { + let _ = Lazy::force(&LAZY_FOO); + let _ = Lazy::force(&LAZY_BAR); + unsafe { + let _ = Lazy::force(&LAZY_BAZ); + } + } +} + +#[clippy::msrv = "1.79"] +mod msrv_not_meet { + use lazy_static::lazy_static; + use once_cell::sync::Lazy; + + static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + + lazy_static! { + static ref LAZY_BAZ: f64 = 12.159 * 548; + } +} + +mod external_macros { + once_cell::external!(); + lazy_static::external!(); +} diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr new file mode 100644 index 000000000000..f956f4b8d52a --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr @@ -0,0 +1,100 @@ +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:11:18 + | +LL | static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + | ^^^^ + | + = note: `-D clippy::non-std-lazy-statics` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_std_lazy_statics)]` +help: use `std::sync::LazyLock` instead + | +LL | static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:13:18 + | +LL | static LAZY_BAR: Lazy = Lazy::new(|| { + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL | static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| { + | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:18:18 + | +LL | static LAZY_BAZ: Lazy = { Lazy::new(|| "baz".to_uppercase()) }; + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL | static LAZY_BAZ: std::sync::LazyLock = { std::sync::LazyLock::new(|| "baz".to_uppercase()) }; + | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:20:18 + | +LL | static LAZY_QUX: Lazy = { + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL ~ static LAZY_QUX: std::sync::LazyLock = { +LL | +LL | if "qux".len() == 3 { +LL ~ std::sync::LazyLock::new(|| "qux".to_uppercase()) +LL | } else if "qux".is_ascii() { +LL ~ std::sync::LazyLock::new(|| "qux".to_lowercase()) +LL | } else { +LL ~ std::sync::LazyLock::new(|| "qux".to_string()) + | + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:41:22 + | +LL | static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL ~ static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); +LL | +... +LL | fn calling_replaceable_fns() { +LL ~ let _ = std::sync::LazyLock::force(&LAZY_FOO); + | + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:43:22 + | +LL | static LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL ~ static LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "bar".to_uppercase()); +LL | +... +LL | let _ = Lazy::force(&LAZY_FOO); +LL ~ let _ = std::sync::LazyLock::force(&LAZY_BAR); + | + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:45:26 + | +LL | static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL ~ static mut LAZY_BAZ: std::sync::LazyLock = std::sync::LazyLock::new(|| "baz".to_uppercase()); +LL | +... +LL | unsafe { +LL ~ let _ = std::sync::LazyLock::force(&LAZY_BAZ); + | + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs new file mode 100644 index 000000000000..6208612c6983 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs @@ -0,0 +1,20 @@ +//@aux-build:once_cell.rs +//@aux-build:lazy_static.rs + +#![warn(clippy::non_std_lazy_statics)] +#![no_std] + +use lazy_static::lazy_static; +use once_cell::sync::Lazy; + +fn main() {} + +static LAZY_FOO: Lazy = Lazy::new(|| 42); +static LAZY_BAR: Lazy = Lazy::new(|| { + let x: i32 = 0; + x.saturating_add(100) +}); + +lazy_static! { + static ref LAZY_BAZ: f64 = 12.159 * 548; +} diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs new file mode 100644 index 000000000000..8701a4b7729a --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs @@ -0,0 +1,12 @@ +//@aux-build:once_cell.rs + +#![warn(clippy::non_std_lazy_statics)] + +// Should not error, since we used a type besides `sync::Lazy` +fn use_once_cell_race(x: once_cell::race::OnceBox) { + let _foo = x.get(); +} + +use once_cell::sync::Lazy; + +static LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs new file mode 100644 index 000000000000..34f8dd1ccb2e --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs @@ -0,0 +1,43 @@ +//@aux-build:once_cell.rs +//@aux-build:lazy_static.rs +//@no-rustfix + +#![warn(clippy::non_std_lazy_statics)] +#![allow(static_mut_refs)] + +mod once_cell_lazy { + use once_cell::sync::Lazy; + + static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + static mut LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); + //~^ ERROR: this type has been superceded by `LazyLock` in the standard library + + fn calling_irreplaceable_fns() { + let _ = Lazy::get(&LAZY_FOO); + + unsafe { + let _ = Lazy::get_mut(&mut LAZY_BAR); + let _ = Lazy::force_mut(&mut LAZY_BAZ); + } + } +} + +mod lazy_static_lazy_static { + use lazy_static::lazy_static; + + lazy_static! { + static ref LAZY_FOO: String = "foo".to_uppercase(); + } + //~^^^ ERROR: this macro has been superceded by `std::sync::LazyLock` + lazy_static! { + static ref LAZY_BAR: String = "bar".to_uppercase(); + static ref LAZY_BAZ: String = "baz".to_uppercase(); + } + //~^^^^ ERROR: this macro has been superceded by `std::sync::LazyLock` + //~| ERROR: this macro has been superceded by `std::sync::LazyLock` +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr new file mode 100644 index 000000000000..66dc435f9823 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr @@ -0,0 +1,66 @@ +error: this macro has been superceded by `std::sync::LazyLock` + --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:31:5 + | +LL | / lazy_static! { +LL | | static ref LAZY_FOO: String = "foo".to_uppercase(); +LL | | } + | |_____^ + | + = note: `-D clippy::non-std-lazy-statics` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_std_lazy_statics)]` + +error: this macro has been superceded by `std::sync::LazyLock` + --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:35:5 + | +LL | / lazy_static! { +LL | | static ref LAZY_BAR: String = "bar".to_uppercase(); +LL | | static ref LAZY_BAZ: String = "baz".to_uppercase(); +LL | | } + | |_____^ + +error: this macro has been superceded by `std::sync::LazyLock` + --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:35:5 + | +LL | / lazy_static! { +LL | | static ref LAZY_BAR: String = "bar".to_uppercase(); +LL | | static ref LAZY_BAZ: String = "baz".to_uppercase(); +LL | | } + | |_____^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:11:22 + | +LL | static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL | static LAZY_FOO: std::sync::LazyLock = std::sync::LazyLock::new(|| "foo".to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:13:26 + | +LL | static mut LAZY_BAR: Lazy = Lazy::new(|| "bar".to_uppercase()); + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL | static mut LAZY_BAR: std::sync::LazyLock = std::sync::LazyLock::new(|| "bar".to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: this type has been superceded by `LazyLock` in the standard library + --> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:15:26 + | +LL | static mut LAZY_BAZ: Lazy = Lazy::new(|| "baz".to_uppercase()); + | ^^^^ + | +help: use `std::sync::LazyLock` instead + | +LL | static mut LAZY_BAZ: std::sync::LazyLock = std::sync::LazyLock::new(|| "baz".to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed index c5ee569800ab..bfe1c5e10cf8 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed @@ -1,5 +1,18 @@ #![warn(clippy::obfuscated_if_else)] +#![allow(clippy::unnecessary_lazy_evaluations, clippy::unit_arg, clippy::unused_unit)] fn main() { if true { "a" } else { "b" }; + if true { "a" } else { "b" }; + + let a = 1; + if a == 1 { "a" } else { "b" }; + if a == 1 { "a" } else { "b" }; + + let partial = (a == 1).then_some("a"); + partial.unwrap_or("b"); // not lint + + let mut a = 0; + if true { a += 1 } else { () }; + if true { () } else { a += 2 }; } diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.rs b/src/tools/clippy/tests/ui/obfuscated_if_else.rs index 2b60c855a555..0ded2a2ceedf 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.rs +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.rs @@ -1,5 +1,18 @@ #![warn(clippy::obfuscated_if_else)] +#![allow(clippy::unnecessary_lazy_evaluations, clippy::unit_arg, clippy::unused_unit)] fn main() { true.then_some("a").unwrap_or("b"); + true.then(|| "a").unwrap_or("b"); + + let a = 1; + (a == 1).then_some("a").unwrap_or("b"); + (a == 1).then(|| "a").unwrap_or("b"); + + let partial = (a == 1).then_some("a"); + partial.unwrap_or("b"); // not lint + + let mut a = 0; + true.then_some(a += 1).unwrap_or(()); + true.then_some(()).unwrap_or(a += 2); } diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr index d4c2f9b331a8..9ce1f475c480 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr @@ -1,5 +1,5 @@ -error: use of `.then_some(..).unwrap_or(..)` can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:4:5 +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:5:5 | LL | true.then_some("a").unwrap_or("b"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` @@ -7,5 +7,35 @@ LL | true.then_some("a").unwrap_or("b"); = note: `-D clippy::obfuscated-if-else` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::obfuscated_if_else)]` -error: aborting due to 1 previous error +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:6:5 + | +LL | true.then(|| "a").unwrap_or("b"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:9:5 + | +LL | (a == 1).then_some("a").unwrap_or("b"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:10:5 + | +LL | (a == 1).then(|| "a").unwrap_or("b"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:16:5 + | +LL | true.then_some(a += 1).unwrap_or(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { a += 1 } else { () }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:17:5 + | +LL | true.then_some(()).unwrap_or(a += 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { a += 2 }` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/precedence.stderr b/src/tools/clippy/tests/ui/precedence.stderr index 0d63e827d66e..329422cb8a69 100644 --- a/src/tools/clippy/tests/ui/precedence.stderr +++ b/src/tools/clippy/tests/ui/precedence.stderr @@ -1,4 +1,4 @@ -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:16:5 | LL | 1 << 2 + 3; @@ -7,61 +7,61 @@ LL | 1 << 2 + 3; = note: `-D clippy::precedence` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::precedence)]` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:17:5 | LL | 1 + 2 << 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:18:5 | LL | 4 >> 1 + 1; | ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:19:5 | LL | 1 + 3 >> 2; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:20:5 | LL | 1 ^ 1 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:21:5 | LL | 3 | 2 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:22:5 | LL | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:23:5 | LL | 0x0F00 & 0x00F0 << 4; | ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0x00F0 << 4)` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:24:5 | LL | 0x0F00 & 0xF000 >> 4; | ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:25:5 | LL | 0x0F00 << 1 ^ 3; | ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3` -error: operator precedence can trip the unwary +error: operator precedence might not be obvious --> tests/ui/precedence.rs:26:5 | LL | 0x0F00 << 1 | 2; diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed index e1d845721a9c..8882a4d50a5f 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] @@ -113,4 +114,10 @@ mod issue_8732 { pub(crate) use some_macro; // ok: macro exports are exempt } +proc_macros::external! { + mod priv_mod { + pub(crate) fn dummy() {} + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.rs b/src/tools/clippy/tests/ui/redundant_pub_crate.rs index 4d7f44892d0c..5c8cab9be161 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.rs +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] @@ -113,4 +114,10 @@ mod issue_8732 { pub(crate) use some_macro; // ok: macro exports are exempt } +proc_macros::external! { + mod priv_mod { + pub(crate) fn dummy() {} + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr index 8f1005ab9b73..699e19b1abcf 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr @@ -1,5 +1,5 @@ error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:6:5 + --> tests/ui/redundant_pub_crate.rs:7:5 | LL | pub(crate) fn g() {} // private due to m1 | ----------^^^^^ @@ -10,7 +10,7 @@ LL | pub(crate) fn g() {} // private due to m1 = help: to override `-D warnings` add `#[allow(clippy::redundant_pub_crate)]` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:11:9 + --> tests/ui/redundant_pub_crate.rs:12:9 | LL | pub(crate) fn g() {} // private due to m1_1 and m1 | ----------^^^^^ @@ -18,7 +18,7 @@ LL | pub(crate) fn g() {} // private due to m1_1 and m1 | help: consider using: `pub` error: pub(crate) module inside private module - --> tests/ui/redundant_pub_crate.rs:15:5 + --> tests/ui/redundant_pub_crate.rs:16:5 | LL | pub(crate) mod m1_2 { | ----------^^^^^^^^^ @@ -26,7 +26,7 @@ LL | pub(crate) mod m1_2 { | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:18:9 + --> tests/ui/redundant_pub_crate.rs:19:9 | LL | pub(crate) fn g() {} // private due to m1_2 and m1 | ----------^^^^^ @@ -34,7 +34,7 @@ LL | pub(crate) fn g() {} // private due to m1_2 and m1 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:24:9 + --> tests/ui/redundant_pub_crate.rs:25:9 | LL | pub(crate) fn g() {} // private due to m1 | ----------^^^^^ @@ -42,7 +42,7 @@ LL | pub(crate) fn g() {} // private due to m1 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:31:5 + --> tests/ui/redundant_pub_crate.rs:32:5 | LL | pub(crate) fn g() {} // already crate visible due to m2 | ----------^^^^^ @@ -50,7 +50,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:36:9 + --> tests/ui/redundant_pub_crate.rs:37:9 | LL | pub(crate) fn g() {} // private due to m2_1 | ----------^^^^^ @@ -58,7 +58,7 @@ LL | pub(crate) fn g() {} // private due to m2_1 | help: consider using: `pub` error: pub(crate) module inside private module - --> tests/ui/redundant_pub_crate.rs:40:5 + --> tests/ui/redundant_pub_crate.rs:41:5 | LL | pub(crate) mod m2_2 { | ----------^^^^^^^^^ @@ -66,7 +66,7 @@ LL | pub(crate) mod m2_2 { | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:43:9 + --> tests/ui/redundant_pub_crate.rs:44:9 | LL | pub(crate) fn g() {} // already crate visible due to m2_2 and m2 | ----------^^^^^ @@ -74,7 +74,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m2_2 and m2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:49:9 + --> tests/ui/redundant_pub_crate.rs:50:9 | LL | pub(crate) fn g() {} // already crate visible due to m2 | ----------^^^^^ @@ -82,7 +82,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:61:9 + --> tests/ui/redundant_pub_crate.rs:62:9 | LL | pub(crate) fn g() {} // private due to m3_1 | ----------^^^^^ @@ -90,7 +90,7 @@ LL | pub(crate) fn g() {} // private due to m3_1 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:68:9 + --> tests/ui/redundant_pub_crate.rs:69:9 | LL | pub(crate) fn g() {} // already crate visible due to m3_2 | ----------^^^^^ @@ -98,7 +98,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m3_2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:81:5 + --> tests/ui/redundant_pub_crate.rs:82:5 | LL | pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` | ----------^^^^^ @@ -106,7 +106,7 @@ LL | pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:86:9 + --> tests/ui/redundant_pub_crate.rs:87:9 | LL | pub(crate) fn g() {} // private due to m4_1 | ----------^^^^^ @@ -114,7 +114,7 @@ LL | pub(crate) fn g() {} // private due to m4_1 | help: consider using: `pub` error: pub(crate) module inside private module - --> tests/ui/redundant_pub_crate.rs:90:5 + --> tests/ui/redundant_pub_crate.rs:91:5 | LL | pub(crate) mod m4_2 { | ----------^^^^^^^^^ @@ -122,7 +122,7 @@ LL | pub(crate) mod m4_2 { | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:93:9 + --> tests/ui/redundant_pub_crate.rs:94:9 | LL | pub(crate) fn g() {} // private due to m4_2 | ----------^^^^^ diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed new file mode 100644 index 000000000000..ef316f1def41 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed @@ -0,0 +1,10 @@ +#![warn(clippy::repeat_vec_with_capacity)] +#![allow(clippy::manual_repeat_n)] +#![no_std] +use core::iter; +extern crate alloc; +use alloc::vec::Vec; + +fn nostd() { + let _: Vec> = core::iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect(); +} diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs new file mode 100644 index 000000000000..83b418a56674 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs @@ -0,0 +1,10 @@ +#![warn(clippy::repeat_vec_with_capacity)] +#![allow(clippy::manual_repeat_n)] +#![no_std] +use core::iter; +extern crate alloc; +use alloc::vec::Vec; + +fn nostd() { + let _: Vec> = iter::repeat(Vec::with_capacity(42)).take(123).collect(); +} diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.stderr b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.stderr new file mode 100644 index 000000000000..39364d09b961 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.stderr @@ -0,0 +1,16 @@ +error: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity + --> tests/ui/repeat_vec_with_capacity_nostd.rs:9:27 + | +LL | let _: Vec> = iter::repeat(Vec::with_capacity(42)).take(123).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: none of the yielded `Vec`s will have the requested capacity + = note: `-D clippy::repeat-vec-with-capacity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeat_vec_with_capacity)]` +help: if you intended to create an iterator that yields `Vec`s with an initial capacity, try + | +LL | let _: Vec> = core::iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/same_item_push.rs b/src/tools/clippy/tests/ui/same_item_push.rs index df9c2817f508..87fd59ad3179 100644 --- a/src/tools/clippy/tests/ui/same_item_push.rs +++ b/src/tools/clippy/tests/ui/same_item_push.rs @@ -21,33 +21,43 @@ fn main() { let item = 2; for _ in 5..=20 { vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this Vec + //~^ ERROR: it looks like the same item is being pushed into this `Vec` } let mut vec: Vec = Vec::new(); for _ in 0..15 { let item = 2; vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this Vec + //~^ ERROR: it looks like the same item is being pushed into this `Vec` } let mut vec: Vec = Vec::new(); for _ in 0..15 { vec.push(13); - //~^ ERROR: it looks like the same item is being pushed into this Vec + //~^ ERROR: it looks like the same item is being pushed into this `Vec` } let mut vec = Vec::new(); for _ in 0..20 { vec.push(VALUE); - //~^ ERROR: it looks like the same item is being pushed into this Vec + //~^ ERROR: it looks like the same item is being pushed into this `Vec` } let mut vec = Vec::new(); let item = VALUE; for _ in 0..20 { vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this Vec + //~^ ERROR: it looks like the same item is being pushed into this `Vec` + } + + #[clippy::msrv = "1.81"] + fn older_msrv() { + let mut vec = Vec::new(); + let item = VALUE; + for _ in 0..20 { + vec.push(item); + //~^ ERROR: it looks like the same item is being pushed into this `Vec` + } } // ** non-linted cases ** diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr index eb296ed4ce4a..e3fa4f9cbcec 100644 --- a/src/tools/clippy/tests/ui/same_item_push.stderr +++ b/src/tools/clippy/tests/ui/same_item_push.stderr @@ -1,44 +1,58 @@ -error: it looks like the same item is being pushed into this Vec +error: it looks like the same item is being pushed into this `Vec` --> tests/ui/same_item_push.rs:23:9 | LL | vec.push(item); | ^^^ | - = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using `vec![item;SIZE]` + = help: or `vec.extend(std::iter::repeat_n(item, SIZE))` = note: `-D clippy::same-item-push` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::same_item_push)]` -error: it looks like the same item is being pushed into this Vec +error: it looks like the same item is being pushed into this `Vec` --> tests/ui/same_item_push.rs:30:9 | LL | vec.push(item); | ^^^ | - = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using `vec![item;SIZE]` + = help: or `vec.extend(std::iter::repeat_n(item, SIZE))` -error: it looks like the same item is being pushed into this Vec +error: it looks like the same item is being pushed into this `Vec` --> tests/ui/same_item_push.rs:36:9 | LL | vec.push(13); | ^^^ | - = help: consider using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) + = help: consider using `vec![13;SIZE]` + = help: or `vec.extend(std::iter::repeat_n(13, SIZE))` -error: it looks like the same item is being pushed into this Vec +error: it looks like the same item is being pushed into this `Vec` --> tests/ui/same_item_push.rs:42:9 | LL | vec.push(VALUE); | ^^^ | - = help: consider using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) + = help: consider using `vec![VALUE;SIZE]` + = help: or `vec.extend(std::iter::repeat_n(VALUE, SIZE))` -error: it looks like the same item is being pushed into this Vec +error: it looks like the same item is being pushed into this `Vec` --> tests/ui/same_item_push.rs:49:9 | LL | vec.push(item); | ^^^ | - = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using `vec![item;SIZE]` + = help: or `vec.extend(std::iter::repeat_n(item, SIZE))` -error: aborting due to 5 previous errors +error: it looks like the same item is being pushed into this `Vec` + --> tests/ui/same_item_push.rs:58:13 + | +LL | vec.push(item); + | ^^^ + | + = help: consider using `vec![item;SIZE]` + = help: or `vec.resize(NEW_SIZE, item)` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.fixed b/src/tools/clippy/tests/ui/short_circuit_statement.fixed index a9930ef4dbb6..a2bf07ac6052 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.fixed +++ b/src/tools/clippy/tests/ui/short_circuit_statement.fixed @@ -3,8 +3,35 @@ fn main() { if f() { g(); } + //~^ ERROR: boolean short circuit operator in statement if !f() { g(); } + //~^ ERROR: boolean short circuit operator in statement if 1 != 2 { g(); } + //~^ ERROR: boolean short circuit operator in statement + if f() || g() { H * 2; } + //~^ ERROR: boolean short circuit operator in statement + if !(f() || g()) { H * 2; } + //~^ ERROR: boolean short circuit operator in statement + + macro_rules! mac { + ($f:ident or $g:ident) => { + $f() || $g() + }; + ($f:ident and $g:ident) => { + $f() && $g() + }; + () => { + f() && g() + }; + } + + if mac!() { mac!(); } + //~^ ERROR: boolean short circuit operator in statement + if !mac!() { mac!(); } + //~^ ERROR: boolean short circuit operator in statement + + // Do not lint if the expression comes from a macro + mac!(); } fn f() -> bool { @@ -14,3 +41,12 @@ fn f() -> bool { fn g() -> bool { false } + +struct H; + +impl std::ops::Mul for H { + type Output = bool; + fn mul(self, other: u32) -> Self::Output { + true + } +} diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.rs b/src/tools/clippy/tests/ui/short_circuit_statement.rs index 71f7c7f2abf7..bdba546ad8f6 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.rs +++ b/src/tools/clippy/tests/ui/short_circuit_statement.rs @@ -3,8 +3,35 @@ fn main() { f() && g(); + //~^ ERROR: boolean short circuit operator in statement f() || g(); + //~^ ERROR: boolean short circuit operator in statement 1 == 2 || g(); + //~^ ERROR: boolean short circuit operator in statement + (f() || g()) && (H * 2); + //~^ ERROR: boolean short circuit operator in statement + (f() || g()) || (H * 2); + //~^ ERROR: boolean short circuit operator in statement + + macro_rules! mac { + ($f:ident or $g:ident) => { + $f() || $g() + }; + ($f:ident and $g:ident) => { + $f() && $g() + }; + () => { + f() && g() + }; + } + + mac!() && mac!(); + //~^ ERROR: boolean short circuit operator in statement + mac!() || mac!(); + //~^ ERROR: boolean short circuit operator in statement + + // Do not lint if the expression comes from a macro + mac!(); } fn f() -> bool { @@ -14,3 +41,12 @@ fn f() -> bool { fn g() -> bool { false } + +struct H; + +impl std::ops::Mul for H { + type Output = bool; + fn mul(self, other: u32) -> Self::Output { + true + } +} diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.stderr b/src/tools/clippy/tests/ui/short_circuit_statement.stderr index e7a8f2ca60ca..ecf6676405b4 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.stderr +++ b/src/tools/clippy/tests/ui/short_circuit_statement.stderr @@ -8,16 +8,40 @@ LL | f() && g(); = help: to override `-D warnings` add `#[allow(clippy::short_circuit_statement)]` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:6:5 + --> tests/ui/short_circuit_statement.rs:7:5 | LL | f() || g(); | ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:7:5 + --> tests/ui/short_circuit_statement.rs:9:5 | LL | 1 == 2 || g(); | ^^^^^^^^^^^^^^ help: replace it with: `if 1 != 2 { g(); }` -error: aborting due to 3 previous errors +error: boolean short circuit operator in statement may be clearer using an explicit test + --> tests/ui/short_circuit_statement.rs:11:5 + | +LL | (f() || g()) && (H * 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `if f() || g() { H * 2; }` + +error: boolean short circuit operator in statement may be clearer using an explicit test + --> tests/ui/short_circuit_statement.rs:13:5 + | +LL | (f() || g()) || (H * 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `if !(f() || g()) { H * 2; }` + +error: boolean short circuit operator in statement may be clearer using an explicit test + --> tests/ui/short_circuit_statement.rs:28:5 + | +LL | mac!() && mac!(); + | ^^^^^^^^^^^^^^^^^ help: replace it with: `if mac!() { mac!(); }` + +error: boolean short circuit operator in statement may be clearer using an explicit test + --> tests/ui/short_circuit_statement.rs:30:5 + | +LL | mac!() || mac!(); + | ^^^^^^^^^^^^^^^^^ help: replace it with: `if !mac!() { mac!(); }` + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index 8468d1d7c7d4..39d550398d70 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -832,4 +832,36 @@ fn should_trigger_lint_in_while_let() { } } +async fn foo_async(mutex: &Mutex) -> Option> { + Some(mutex.lock().unwrap()) +} + +async fn should_trigger_lint_for_async(mutex: Mutex) -> i32 { + match *foo_async(&mutex).await.unwrap() { + n if n < 10 => n, + _ => 10, + } +} + +async fn should_not_trigger_lint_in_async_expansion(mutex: Mutex) -> i32 { + match foo_async(&mutex).await { + Some(guard) => *guard, + _ => 0, + } +} + +fn should_trigger_lint_in_match_expr() { + let mutex = Mutex::new(State {}); + + // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it + // is preserved until the end of the match, but there is no clear indication that this is the + // case. + let _ = match mutex.lock().unwrap().foo() { + //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + true => 0, + false => 1, + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index 62030cbe70e7..f99d862aa6b2 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -568,5 +568,37 @@ LL | } | = note: this might lead to deadlocks or other unexpected behavior -error: aborting due to 29 previous errors +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> tests/ui/significant_drop_in_scrutinee.rs:840:11 + | +LL | match *foo_async(&mutex).await.unwrap() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = *foo_async(&mutex).await.unwrap(); +LL ~ match value { + | + +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> tests/ui/significant_drop_in_scrutinee.rs:859:19 + | +LL | let _ = match mutex.lock().unwrap().foo() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().foo(); +LL ~ let _ = match value { + | + +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed b/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed new file mode 100644 index 000000000000..469ad27a99b9 --- /dev/null +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed @@ -0,0 +1,34 @@ +#![allow(unused)] +#![warn(clippy::sliced_string_as_bytes)] + +use std::ops::{Index, Range}; + +struct Foo; + +struct Bar; + +impl Bar { + fn as_bytes(&self) -> &[u8] { + &[0, 1, 2, 3] + } +} + +impl Index> for Foo { + type Output = Bar; + + fn index(&self, _: Range) -> &Self::Output { + &Bar + } +} + +fn main() { + let s = "Lorem ipsum"; + let string: String = "dolor sit amet".to_owned(); + + let bytes = &s.as_bytes()[1..5]; + let bytes = &string.as_bytes()[1..]; + let bytes = &"consectetur adipiscing".as_bytes()[..=5]; + + let f = Foo; + let bytes = f[0..4].as_bytes(); +} diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs b/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs new file mode 100644 index 000000000000..4a4605e5a1ae --- /dev/null +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs @@ -0,0 +1,34 @@ +#![allow(unused)] +#![warn(clippy::sliced_string_as_bytes)] + +use std::ops::{Index, Range}; + +struct Foo; + +struct Bar; + +impl Bar { + fn as_bytes(&self) -> &[u8] { + &[0, 1, 2, 3] + } +} + +impl Index> for Foo { + type Output = Bar; + + fn index(&self, _: Range) -> &Self::Output { + &Bar + } +} + +fn main() { + let s = "Lorem ipsum"; + let string: String = "dolor sit amet".to_owned(); + + let bytes = s[1..5].as_bytes(); + let bytes = string[1..].as_bytes(); + let bytes = "consectetur adipiscing"[..=5].as_bytes(); + + let f = Foo; + let bytes = f[0..4].as_bytes(); +} diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr b/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr new file mode 100644 index 000000000000..1342f4c01a48 --- /dev/null +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr @@ -0,0 +1,23 @@ +error: calling `as_bytes` after slicing a string + --> tests/ui/sliced_string_as_bytes.rs:28:17 + | +LL | let bytes = s[1..5].as_bytes(); + | ^^^^^^^^^^^^^^^^^^ help: try: `&s.as_bytes()[1..5]` + | + = note: `-D clippy::sliced-string-as-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::sliced_string_as_bytes)]` + +error: calling `as_bytes` after slicing a string + --> tests/ui/sliced_string_as_bytes.rs:29:17 + | +LL | let bytes = string[1..].as_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&string.as_bytes()[1..]` + +error: calling `as_bytes` after slicing a string + --> tests/ui/sliced_string_as_bytes.rs:30:17 + | +LL | let bytes = "consectetur adipiscing"[..=5].as_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&"consectetur adipiscing".as_bytes()[..=5]` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.fixed b/src/tools/clippy/tests/ui/slow_vector_initialization.fixed new file mode 100644 index 000000000000..a8570366e646 --- /dev/null +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.fixed @@ -0,0 +1,86 @@ +#![allow(clippy::useless_vec, clippy::manual_repeat_n)] + +use std::iter::repeat; +fn main() { + resize_vector(); + extend_vector(); + mixed_extend_resize_vector(); + from_empty_vec(); +} + +fn extend_vector() { + // Extend with constant expression + let len = 300; + let mut vec1 = vec![0; len]; + + // Extend with len expression + let mut vec2 = vec![0; len - 10]; + + // Extend with mismatching expression should not be warned + let mut vec3 = Vec::with_capacity(24322); + vec3.extend(repeat(0).take(2)); + + let mut vec4 = vec![0; len]; +} + +fn mixed_extend_resize_vector() { + // Mismatching len + let mut mismatching_len = Vec::with_capacity(30); + mismatching_len.extend(repeat(0).take(40)); + + // Slow initialization + let mut resized_vec = vec![0; 30]; + + let mut extend_vec = vec![0; 30]; +} + +fn resize_vector() { + // Resize with constant expression + let len = 300; + let mut vec1 = vec![0; len]; + + // Resize mismatch len + let mut vec2 = Vec::with_capacity(200); + vec2.resize(10, 0); + + // Resize with len expression + let mut vec3 = vec![0; len - 10]; + + let mut vec4 = vec![0; len]; + + // Reinitialization should be warned + vec1 = vec![0; 10]; +} + +fn from_empty_vec() { + // Resize with constant expression + let len = 300; + let mut vec1 = vec![0; len]; + + // Resize with len expression + let mut vec3 = vec![0; len - 10]; + + // Reinitialization should be warned + vec1 = vec![0; 10]; + + vec1 = vec![0; 10]; + + macro_rules! x { + () => { + vec![] + }; + } + + // `vec![]` comes from another macro, don't warn + vec1 = x!(); + vec1.resize(10, 0); +} + +fn do_stuff(vec: &mut [u8]) {} + +fn extend_vector_with_manipulations_between() { + let len = 300; + let mut vec1: Vec = Vec::with_capacity(len); + do_stuff(&mut vec1); + vec1.extend(repeat(0).take(len)); +} diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs index 2ba87f412500..4b30fad409e3 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs @@ -1,4 +1,5 @@ -//@no-rustfix +#![allow(clippy::useless_vec, clippy::manual_repeat_n)] + use std::iter::repeat; fn main() { resize_vector(); diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr index 7f4b9f7b67a4..4a25cafcddf2 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr @@ -1,5 +1,5 @@ error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:13:20 + --> tests/ui/slow_vector_initialization.rs:14:20 | LL | let mut vec1 = Vec::with_capacity(len); | ____________________^ @@ -11,7 +11,7 @@ LL | | vec1.extend(repeat(0).take(len)); = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:19:20 + --> tests/ui/slow_vector_initialization.rs:20:20 | LL | let mut vec2 = Vec::with_capacity(len - 10); | ____________________^ @@ -20,7 +20,7 @@ LL | | vec2.extend(repeat(0).take(len - 10)); | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:27:20 + --> tests/ui/slow_vector_initialization.rs:28:20 | LL | let mut vec4 = Vec::with_capacity(len); | ____________________^ @@ -29,7 +29,7 @@ LL | | vec4.extend(repeat(0).take(vec4.capacity())); | |________________________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:38:27 + --> tests/ui/slow_vector_initialization.rs:39:27 | LL | let mut resized_vec = Vec::with_capacity(30); | ___________________________^ @@ -38,7 +38,7 @@ LL | | resized_vec.resize(30, 0); | |_____________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:42:26 + --> tests/ui/slow_vector_initialization.rs:43:26 | LL | let mut extend_vec = Vec::with_capacity(30); | __________________________^ @@ -47,7 +47,7 @@ LL | | extend_vec.extend(repeat(0).take(30)); | |_________________________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:50:20 + --> tests/ui/slow_vector_initialization.rs:51:20 | LL | let mut vec1 = Vec::with_capacity(len); | ____________________^ @@ -56,7 +56,7 @@ LL | | vec1.resize(len, 0); | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:59:20 + --> tests/ui/slow_vector_initialization.rs:60:20 | LL | let mut vec3 = Vec::with_capacity(len - 10); | ____________________^ @@ -65,7 +65,7 @@ LL | | vec3.resize(len - 10, 0); | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:63:20 + --> tests/ui/slow_vector_initialization.rs:64:20 | LL | let mut vec4 = Vec::with_capacity(len); | ____________________^ @@ -74,7 +74,7 @@ LL | | vec4.resize(vec4.capacity(), 0); | |___________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:68:12 + --> tests/ui/slow_vector_initialization.rs:69:12 | LL | vec1 = Vec::with_capacity(10); | ____________^ @@ -83,7 +83,7 @@ LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:76:20 + --> tests/ui/slow_vector_initialization.rs:77:20 | LL | let mut vec1 = Vec::new(); | ____________________^ @@ -92,7 +92,7 @@ LL | | vec1.resize(len, 0); | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:81:20 + --> tests/ui/slow_vector_initialization.rs:82:20 | LL | let mut vec3 = Vec::new(); | ____________________^ @@ -101,7 +101,7 @@ LL | | vec3.resize(len - 10, 0); | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:86:12 + --> tests/ui/slow_vector_initialization.rs:87:12 | LL | vec1 = Vec::new(); | ____________^ @@ -110,7 +110,7 @@ LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:90:12 + --> tests/ui/slow_vector_initialization.rs:91:12 | LL | vec1 = vec![]; | ____________^ diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed index efea28e7045c..5a6e77a06b8f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed @@ -82,3 +82,20 @@ fn msrv_1_81() { // is_none_or added in 1.82.0 let _ = Some(5).map_or(true, |n| n == if 2 > 1 { n } else { 0 }); } + +fn with_refs(o: &mut Option) -> bool { + o.is_none_or(|n| n > 5) || (o as &Option).is_none_or(|n| n < 5) +} + +struct S; + +impl std::ops::Deref for S { + type Target = Option; + fn deref(&self) -> &Self::Target { + &Some(0) + } +} + +fn with_deref(o: &S) -> bool { + o.is_none_or(|n| n > 5) +} diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs index 05a0ca816ef6..5ba63121659f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.rs +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs @@ -85,3 +85,20 @@ fn msrv_1_81() { // is_none_or added in 1.82.0 let _ = Some(5).map_or(true, |n| n == if 2 > 1 { n } else { 0 }); } + +fn with_refs(o: &mut Option) -> bool { + o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) +} + +struct S; + +impl std::ops::Deref for S { + type Target = Option; + fn deref(&self) -> &Self::Target { + &Some(0) + } +} + +fn with_deref(o: &S) -> bool { + o.map_or(true, |n| n > 5) +} diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr index 2b78996d5f3e..2ae327f0bf88 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr @@ -2,16 +2,25 @@ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:13:13 | LL | let _ = Some(5).map_or(false, |n| n == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) == Some(5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-map-or` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]` +help: use a standard comparison instead + | +LL | let _ = Some(5) == Some(5); + | ~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:14:13 | LL | let _ = Some(5).map_or(true, |n| n != 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) != Some(5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = Some(5) != Some(5); + | ~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:15:13 @@ -21,7 +30,12 @@ LL | let _ = Some(5).map_or(false, |n| { LL | | let _ = 1; LL | | n == 5 LL | | }); - | |______^ help: use a standard comparison instead: `Some(5) == Some(5)` + | |______^ + | +help: use a standard comparison instead + | +LL | let _ = Some(5) == Some(5); + | ~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:19:13 @@ -35,113 +49,243 @@ LL | | }); | help: use is_some_and instead | -LL ~ let _ = Some(5).is_some_and(|n| { -LL + let _ = n; -LL + 6 >= 5 -LL ~ }); +LL - let _ = Some(5).map_or(false, |n| { +LL + let _ = Some(5).is_some_and(|n| { | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:23:13 | LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - let _ = Some(vec![5]).map_or(false, |n| n == [5]); +LL + let _ = Some(vec![5]).is_some_and(|n| n == [5]); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:24:13 | LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); +LL + let _ = Some(vec![1]).is_some_and(|n| vec![2] == n); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:25:13 | LL | let _ = Some(5).map_or(false, |n| n == n); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - let _ = Some(5).map_or(false, |n| n == n); +LL + let _ = Some(5).is_some_and(|n| n == n); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:26:13 | LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); +LL + let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:27:13 | LL | let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::, i32>(vec![5]).is_ok_and(|n| n == [5])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_ok_and instead + | +LL - let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); +LL + let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:28:13 | LL | let _ = Ok::(5).map_or(false, |n| n == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Ok::(5) == Ok(5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = Ok::(5) == Ok(5); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:29:13 | LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = (Some(5) == Some(5)).then(|| 1); + | ~~~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:30:13 | LL | let _ = Some(5).map_or(true, |n| n == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - let _ = Some(5).map_or(true, |n| n == 5); +LL + let _ = Some(5).is_none_or(|n| n == 5); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:31:13 | LL | let _ = Some(5).map_or(true, |n| 5 == n); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - let _ = Some(5).map_or(true, |n| 5 == n); +LL + let _ = Some(5).is_none_or(|n| 5 == n); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:32:14 | LL | let _ = !Some(5).map_or(false, |n| n == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = !(Some(5) == Some(5)); + | ~~~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:33:13 | LL | let _ = Some(5).map_or(false, |n| n == 5) || false; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = (Some(5) == Some(5)) || false; + | ~~~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:34:13 | LL | let _ = Some(5).map_or(false, |n| n == 5) as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = (Some(5) == Some(5)) as usize; + | ~~~~~~~~~~~~~~~~~~~~ error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:58:13 | LL | let _ = r.map_or(false, |x| x == 7); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_ok_and instead + | +LL - let _ = r.map_or(false, |x| x == 7); +LL + let _ = r.is_ok_and(|x| x == 7); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:63:13 | LL | let _ = r.map_or(false, func); - | ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_ok_and instead + | +LL - let _ = r.map_or(false, func); +LL + let _ = r.is_ok_and(func); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:64:13 | LL | let _ = Some(5).map_or(false, func); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - let _ = Some(5).map_or(false, func); +LL + let _ = Some(5).is_some_and(func); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:65:13 | LL | let _ = Some(5).map_or(true, func); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - let _ = Some(5).map_or(true, func); +LL + let _ = Some(5).is_none_or(func); + | error: this `map_or` can be simplified --> tests/ui/unnecessary_map_or.rs:70:13 | LL | let _ = r.map_or(false, |x| x == 8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `r == Ok(8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use a standard comparison instead + | +LL | let _ = r == Ok(8); + | ~~~~~~~~~~ -error: aborting due to 21 previous errors +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:90:5 + | +LL | o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) +LL + o.is_none_or(|n| n > 5) || (o as &Option).map_or(true, |n| n < 5) + | + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:90:34 + | +LL | o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) +LL + o.map_or(true, |n| n > 5) || (o as &Option).is_none_or(|n| n < 5) + | + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:103:5 + | +LL | o.map_or(true, |n| n > 5) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - o.map_or(true, |n| n > 5) +LL + o.is_none_or(|n| n > 5) + | + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed new file mode 100644 index 000000000000..7a3b79553dea --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed @@ -0,0 +1,57 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +#![warn(clippy::unnecessary_semicolon)] +#![feature(postfix_match)] +#![allow(clippy::single_match)] + +fn no_lint(mut x: u32) -> Option { + Some(())?; + + { + let y = 3; + dbg!(x + y) + }; + + { + let (mut a, mut b) = (10, 20); + (a, b) = (b + 1, a + 1); + } + + Some(0) +} + +fn main() { + let mut a = 3; + if a == 2 { + println!("This is weird"); + } + //~^ ERROR: unnecessary semicolon + + a.match { + 3 => println!("three"), + _ => println!("not three"), + } + //~^ ERROR: unnecessary semicolon +} + +// This is a problem in edition 2021 and below +fn borrow_issue() { + let v = std::cell::RefCell::new(Some(vec![1])); + match &*v.borrow() { + Some(v) => { + dbg!(v); + }, + None => {}, + }; +} + +fn no_borrow_issue(a: u32, b: u32) { + match Some(a + b) { + Some(v) => { + dbg!(v); + }, + None => {}, + } +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr new file mode 100644 index 000000000000..ccff33084172 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr @@ -0,0 +1,23 @@ +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:29:6 + | +LL | }; + | ^ help: remove + | + = note: `-D clippy::unnecessary-semicolon` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_semicolon)]` + +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:35:6 + | +LL | }; + | ^ help: remove + +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:56:6 + | +LL | }; + | ^ help: remove + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed new file mode 100644 index 000000000000..d186d5e7ebc4 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed @@ -0,0 +1,57 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +#![warn(clippy::unnecessary_semicolon)] +#![feature(postfix_match)] +#![allow(clippy::single_match)] + +fn no_lint(mut x: u32) -> Option { + Some(())?; + + { + let y = 3; + dbg!(x + y) + }; + + { + let (mut a, mut b) = (10, 20); + (a, b) = (b + 1, a + 1); + } + + Some(0) +} + +fn main() { + let mut a = 3; + if a == 2 { + println!("This is weird"); + } + //~^ ERROR: unnecessary semicolon + + a.match { + 3 => println!("three"), + _ => println!("not three"), + } + //~^ ERROR: unnecessary semicolon +} + +// This is a problem in edition 2021 and below +fn borrow_issue() { + let v = std::cell::RefCell::new(Some(vec![1])); + match &*v.borrow() { + Some(v) => { + dbg!(v); + }, + None => {}, + } +} + +fn no_borrow_issue(a: u32, b: u32) { + match Some(a + b) { + Some(v) => { + dbg!(v); + }, + None => {}, + } +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr new file mode 100644 index 000000000000..4e526af2147d --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr @@ -0,0 +1,29 @@ +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:29:6 + | +LL | }; + | ^ help: remove + | + = note: `-D clippy::unnecessary-semicolon` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_semicolon)]` + +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:35:6 + | +LL | }; + | ^ help: remove + +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:47:6 + | +LL | }; + | ^ help: remove + +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:56:6 + | +LL | }; + | ^ help: remove + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.fixed new file mode 100644 index 000000000000..36d5c7806fe8 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.fixed @@ -0,0 +1,32 @@ +#![warn(clippy::unnecessary_semicolon)] +#![feature(postfix_match)] + +fn no_lint(mut x: u32) -> Option { + Some(())?; + + { + let y = 3; + dbg!(x + y) + }; + + { + let (mut a, mut b) = (10, 20); + (a, b) = (b + 1, a + 1); + } + + Some(0) +} + +fn main() { + let mut a = 3; + if a == 2 { + println!("This is weird"); + } + //~^ ERROR: unnecessary semicolon + + a.match { + 3 => println!("three"), + _ => println!("not three"), + } + //~^ ERROR: unnecessary semicolon +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs new file mode 100644 index 000000000000..3028c5b27b34 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs @@ -0,0 +1,57 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +#![warn(clippy::unnecessary_semicolon)] +#![feature(postfix_match)] +#![allow(clippy::single_match)] + +fn no_lint(mut x: u32) -> Option { + Some(())?; + + { + let y = 3; + dbg!(x + y) + }; + + { + let (mut a, mut b) = (10, 20); + (a, b) = (b + 1, a + 1); + } + + Some(0) +} + +fn main() { + let mut a = 3; + if a == 2 { + println!("This is weird"); + }; + //~^ ERROR: unnecessary semicolon + + a.match { + 3 => println!("three"), + _ => println!("not three"), + }; + //~^ ERROR: unnecessary semicolon +} + +// This is a problem in edition 2021 and below +fn borrow_issue() { + let v = std::cell::RefCell::new(Some(vec![1])); + match &*v.borrow() { + Some(v) => { + dbg!(v); + }, + None => {}, + }; +} + +fn no_borrow_issue(a: u32, b: u32) { + match Some(a + b) { + Some(v) => { + dbg!(v); + }, + None => {}, + }; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.stderr b/src/tools/clippy/tests/ui/unnecessary_semicolon.stderr new file mode 100644 index 000000000000..e6bf36e81e88 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.stderr @@ -0,0 +1,17 @@ +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:24:6 + | +LL | }; + | ^ help: remove + | + = note: `-D clippy::unnecessary-semicolon` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_semicolon)]` + +error: unnecessary semicolon + --> tests/ui/unnecessary_semicolon.rs:30:6 + | +LL | }; + | ^ help: remove + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed index fdcac8fb08dc..027dac419375 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed @@ -585,3 +585,9 @@ fn borrow_checks() { HashSet::::new().foo::<&str>(&"".to_owned()); HashSet::::new().get(&1.to_string()); } + +fn issue13624() -> impl IntoIterator { + let cow: Cow<'_, Vec> = Cow::Owned(vec![String::from("foo")]); + + cow.into_owned().into_iter() +} diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs index 10a9727a9a79..b89f3d552f84 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs @@ -585,3 +585,9 @@ fn borrow_checks() { HashSet::::new().foo::<&str>(&"".to_owned()); HashSet::::new().get(&1.to_string()); } + +fn issue13624() -> impl IntoIterator { + let cow: Cow<'_, Vec> = Cow::Owned(vec![String::from("foo")]); + + cow.into_owned().into_iter() +} diff --git a/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed b/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed new file mode 100644 index 000000000000..5bd269896a6b --- /dev/null +++ b/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed @@ -0,0 +1,177 @@ +//@aux-build:non-exhaustive-enum.rs +#![allow( + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or, + clippy::redundant_pattern_matching +)] +#![warn(clippy::unneeded_struct_pattern)] + +extern crate non_exhaustive_enum; +use non_exhaustive_enum::*; + +fn noop() {} + +fn main() { + match Some(114514) { + Some(v) => v, + None => 0, + }; + + match Some(1919810) { + Some(v) => v, + None => 0, + }; + + match Some(123456) { + Some(v) => v, + None => 0, + }; + + match Some(Some(123456)) { + Some(Some(v)) => v, + Some(None) => 0, + None => 0, + }; + + if let None = Some(0) {} + if let None = Some(0) {} + if let Some(None) = Some(Some(0)) {} + let None = Some(0) else { panic!() }; + let None = Some(0) else { panic!() }; + let Some(None) = Some(Some(0)) else { panic!() }; + + enum Custom { + HasFields { + field: i32, + }, + HasBracketsNoFields {}, + NoBrackets, + #[non_exhaustive] + NoBracketsNonExhaustive, + Init, + }; + + match Custom::Init { + Custom::HasFields { field: value } => value, + Custom::HasBracketsNoFields {} => 0, + Custom::NoBrackets => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBracketsNonExhaustive => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match Custom::Init { + Custom::HasFields { field: value } => value, + Custom::HasBracketsNoFields { .. } => 0, + Custom::NoBrackets => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBracketsNonExhaustive => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match Custom::Init { + Custom::NoBrackets if true => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match Custom::Init { + Custom::NoBrackets | Custom::NoBracketsNonExhaustive => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + if let Custom::HasFields { field: value } = Custom::Init { + noop(); + } + if let Custom::HasBracketsNoFields {} = Custom::Init { + noop(); + } + if let Custom::HasBracketsNoFields { .. } = Custom::Init { + noop(); + } + if let Custom::NoBrackets = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBrackets = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBrackets | Custom::NoBracketsNonExhaustive = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBracketsNonExhaustive = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBracketsNonExhaustive = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + + let Custom::HasFields { field: value } = Custom::Init else { + panic!() + }; + + let Custom::HasBracketsNoFields {} = Custom::Init else { + panic!() + }; + + let Custom::HasBracketsNoFields { .. } = Custom::Init else { + panic!() + }; + let Custom::NoBrackets = Custom::Init else { panic!() }; //~ ERROR: struct pattern is not needed for a unit variant + + let Custom::NoBrackets = Custom::Init else { + //~^ ERROR: struct pattern is not needed for a unit variant + panic!() + }; + let Custom::NoBracketsNonExhaustive = Custom::Init else { + //~^ ERROR: struct pattern is not needed for a unit variant + panic!() + }; + let Custom::NoBracketsNonExhaustive = Custom::Init else { + //~^ ERROR: struct pattern is not needed for a unit variant + panic!() + }; + + enum Refutable { + Variant, + } + + fn pat_in_fn_param_1(Refutable::Variant: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant + fn pat_in_fn_param_2(Refutable::Variant: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant + + for Refutable::Variant in [] {} //~ ERROR: struct pattern is not needed for a unit variant + for Refutable::Variant in [] {} //~ ERROR: struct pattern is not needed for a unit variant +} + +fn external_crate() { + use ExtNonExhaustiveVariant::*; + + match ExhaustiveUnit { + // Expected + ExhaustiveUnit => 0, + _ => 0, + }; + + match ExhaustiveUnit { + // Exhaustive variant + ExhaustiveUnit => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match ExhaustiveUnit { + // Exhaustive variant + ExhaustiveUnit => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match ExhaustiveUnit { + ExhaustiveUnit => 0, + // vvvvv Non-exhaustive variants, should all be ignored + Unit { .. } => 0, + Tuple { 0: field, .. } => field, + StructNoField { .. } => 0, + Struct { field, .. } => field, + _ => 0, + }; +} diff --git a/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs b/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs new file mode 100644 index 000000000000..c7658617ad37 --- /dev/null +++ b/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs @@ -0,0 +1,177 @@ +//@aux-build:non-exhaustive-enum.rs +#![allow( + clippy::manual_unwrap_or_default, + clippy::manual_unwrap_or, + clippy::redundant_pattern_matching +)] +#![warn(clippy::unneeded_struct_pattern)] + +extern crate non_exhaustive_enum; +use non_exhaustive_enum::*; + +fn noop() {} + +fn main() { + match Some(114514) { + Some(v) => v, + None {} => 0, + }; + + match Some(1919810) { + Some(v) => v, + None { .. } => 0, + }; + + match Some(123456) { + Some(v) => v, + None => 0, + }; + + match Some(Some(123456)) { + Some(Some(v)) => v, + Some(None {}) => 0, + None {} => 0, + }; + + if let None {} = Some(0) {} + if let None { .. } = Some(0) {} + if let Some(None {}) = Some(Some(0)) {} + let None {} = Some(0) else { panic!() }; + let None { .. } = Some(0) else { panic!() }; + let Some(None {}) = Some(Some(0)) else { panic!() }; + + enum Custom { + HasFields { + field: i32, + }, + HasBracketsNoFields {}, + NoBrackets, + #[non_exhaustive] + NoBracketsNonExhaustive, + Init, + }; + + match Custom::Init { + Custom::HasFields { field: value } => value, + Custom::HasBracketsNoFields {} => 0, + Custom::NoBrackets {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBracketsNonExhaustive {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match Custom::Init { + Custom::HasFields { field: value } => value, + Custom::HasBracketsNoFields { .. } => 0, + Custom::NoBrackets { .. } => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBracketsNonExhaustive { .. } => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match Custom::Init { + Custom::NoBrackets {} if true => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match Custom::Init { + Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + if let Custom::HasFields { field: value } = Custom::Init { + noop(); + } + if let Custom::HasBracketsNoFields {} = Custom::Init { + noop(); + } + if let Custom::HasBracketsNoFields { .. } = Custom::Init { + noop(); + } + if let Custom::NoBrackets {} = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBrackets { .. } = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBracketsNonExhaustive {} = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + if let Custom::NoBracketsNonExhaustive { .. } = Custom::Init { + //~^ ERROR: struct pattern is not needed for a unit variant + noop(); + } + + let Custom::HasFields { field: value } = Custom::Init else { + panic!() + }; + + let Custom::HasBracketsNoFields {} = Custom::Init else { + panic!() + }; + + let Custom::HasBracketsNoFields { .. } = Custom::Init else { + panic!() + }; + let Custom::NoBrackets {} = Custom::Init else { panic!() }; //~ ERROR: struct pattern is not needed for a unit variant + + let Custom::NoBrackets { .. } = Custom::Init else { + //~^ ERROR: struct pattern is not needed for a unit variant + panic!() + }; + let Custom::NoBracketsNonExhaustive {} = Custom::Init else { + //~^ ERROR: struct pattern is not needed for a unit variant + panic!() + }; + let Custom::NoBracketsNonExhaustive { .. } = Custom::Init else { + //~^ ERROR: struct pattern is not needed for a unit variant + panic!() + }; + + enum Refutable { + Variant, + } + + fn pat_in_fn_param_1(Refutable::Variant {}: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant + fn pat_in_fn_param_2(Refutable::Variant { .. }: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant + + for Refutable::Variant {} in [] {} //~ ERROR: struct pattern is not needed for a unit variant + for Refutable::Variant { .. } in [] {} //~ ERROR: struct pattern is not needed for a unit variant +} + +fn external_crate() { + use ExtNonExhaustiveVariant::*; + + match ExhaustiveUnit { + // Expected + ExhaustiveUnit => 0, + _ => 0, + }; + + match ExhaustiveUnit { + // Exhaustive variant + ExhaustiveUnit { .. } => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match ExhaustiveUnit { + // Exhaustive variant + ExhaustiveUnit {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + _ => 0, + }; + + match ExhaustiveUnit { + ExhaustiveUnit => 0, + // vvvvv Non-exhaustive variants, should all be ignored + Unit { .. } => 0, + Tuple { 0: field, .. } => field, + StructNoField { .. } => 0, + Struct { field, .. } => field, + _ => 0, + }; +} diff --git a/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr new file mode 100644 index 000000000000..3a7f59583802 --- /dev/null +++ b/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr @@ -0,0 +1,203 @@ +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:17:13 + | +LL | None {} => 0, + | ^^^ help: remove the struct pattern + | + = note: `-D clippy::unneeded-struct-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unneeded_struct_pattern)]` + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:22:13 + | +LL | None { .. } => 0, + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:32:18 + | +LL | Some(None {}) => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:33:13 + | +LL | None {} => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:36:16 + | +LL | if let None {} = Some(0) {} + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:37:16 + | +LL | if let None { .. } = Some(0) {} + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:38:21 + | +LL | if let Some(None {}) = Some(Some(0)) {} + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:39:13 + | +LL | let None {} = Some(0) else { panic!() }; + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:40:13 + | +LL | let None { .. } = Some(0) else { panic!() }; + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:41:18 + | +LL | let Some(None {}) = Some(Some(0)) else { panic!() }; + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:57:27 + | +LL | Custom::NoBrackets {} => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:58:40 + | +LL | Custom::NoBracketsNonExhaustive {} => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:65:27 + | +LL | Custom::NoBrackets { .. } => 0, + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:66:40 + | +LL | Custom::NoBracketsNonExhaustive { .. } => 0, + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:71:27 + | +LL | Custom::NoBrackets {} if true => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:76:27 + | +LL | Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:76:64 + | +LL | Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:89:30 + | +LL | if let Custom::NoBrackets {} = Custom::Init { + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:93:30 + | +LL | if let Custom::NoBrackets { .. } = Custom::Init { + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:97:30 + | +LL | if let Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} = Custom::Init { + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:97:67 + | +LL | if let Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} = Custom::Init { + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:101:43 + | +LL | if let Custom::NoBracketsNonExhaustive {} = Custom::Init { + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:105:43 + | +LL | if let Custom::NoBracketsNonExhaustive { .. } = Custom::Init { + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:121:27 + | +LL | let Custom::NoBrackets {} = Custom::Init else { panic!() }; + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:123:27 + | +LL | let Custom::NoBrackets { .. } = Custom::Init else { + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:127:40 + | +LL | let Custom::NoBracketsNonExhaustive {} = Custom::Init else { + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:131:40 + | +LL | let Custom::NoBracketsNonExhaustive { .. } = Custom::Init else { + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:140:44 + | +LL | fn pat_in_fn_param_1(Refutable::Variant {}: Refutable) {} + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:141:44 + | +LL | fn pat_in_fn_param_2(Refutable::Variant { .. }: Refutable) {} + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:143:27 + | +LL | for Refutable::Variant {} in [] {} + | ^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:144:27 + | +LL | for Refutable::Variant { .. } in [] {} + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:158:23 + | +LL | ExhaustiveUnit { .. } => 0, + | ^^^^^^^ help: remove the struct pattern + +error: struct pattern is not needed for a unit variant + --> tests/ui/unneeded_struct_pattern.rs:164:23 + | +LL | ExhaustiveUnit {} => 0, + | ^^^ help: remove the struct pattern + +error: aborting due to 33 previous errors + diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 2f7edd92bb7c..697d437b3885 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -342,3 +342,56 @@ fn gen_identity(x: [T; 3]) -> Vec { x.into_iter().collect() //~^ useless_conversion } + +mod issue11819 { + fn takes_into_iter(_: impl IntoIterator) {} + + pub struct MyStruct { + my_field: T, + } + + impl MyStruct { + pub fn with_ref<'a>(&'a mut self) + where + &'a T: IntoIterator, + { + takes_into_iter(&self.my_field); + //~^ useless_conversion + } + + pub fn with_ref_mut<'a>(&'a mut self) + where + &'a mut T: IntoIterator, + { + takes_into_iter(&mut self.my_field); + //~^ useless_conversion + } + + pub fn with_deref(&mut self) + where + T: std::ops::Deref, + Y: IntoIterator + Copy, + { + takes_into_iter(*self.my_field); + //~^ useless_conversion + } + + pub fn with_reborrow<'a, Y: 'a>(&'a mut self) + where + T: std::ops::Deref, + &'a Y: IntoIterator, + { + takes_into_iter(&*self.my_field); + //~^ useless_conversion + } + + pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self) + where + T: std::ops::Deref + std::ops::DerefMut, + &'a mut Y: IntoIterator, + { + takes_into_iter(&mut *self.my_field); + //~^ useless_conversion + } + } +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index eacdf77f9052..4d8ad61a8c99 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -342,3 +342,56 @@ fn gen_identity(x: [T; 3]) -> Vec { x.into_iter().map(Into::into).collect() //~^ useless_conversion } + +mod issue11819 { + fn takes_into_iter(_: impl IntoIterator) {} + + pub struct MyStruct { + my_field: T, + } + + impl MyStruct { + pub fn with_ref<'a>(&'a mut self) + where + &'a T: IntoIterator, + { + takes_into_iter(self.my_field.into_iter()); + //~^ useless_conversion + } + + pub fn with_ref_mut<'a>(&'a mut self) + where + &'a mut T: IntoIterator, + { + takes_into_iter(self.my_field.into_iter()); + //~^ useless_conversion + } + + pub fn with_deref(&mut self) + where + T: std::ops::Deref, + Y: IntoIterator + Copy, + { + takes_into_iter(self.my_field.into_iter()); + //~^ useless_conversion + } + + pub fn with_reborrow<'a, Y: 'a>(&'a mut self) + where + T: std::ops::Deref, + &'a Y: IntoIterator, + { + takes_into_iter(self.my_field.into_iter()); + //~^ useless_conversion + } + + pub fn with_reborrow_mut<'a, Y: 'a>(&'a mut self) + where + T: std::ops::Deref + std::ops::DerefMut, + &'a mut Y: IntoIterator, + { + takes_into_iter(self.my_field.into_iter()); + //~^ useless_conversion + } + } +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 6aeb382902ba..ed50f3071862 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -122,7 +122,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:189:7 | LL | b(vec![1, 2].into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` + | ^^^^^^^^^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:179:13 @@ -134,7 +136,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:190:7 | LL | c(vec![1, 2].into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` + | ^^^^^^^^^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:180:18 @@ -146,7 +150,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:191:7 | LL | d(vec![1, 2].into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` + | ^^^^^^^^^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:183:12 @@ -158,7 +164,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:194:7 | LL | b(vec![1, 2].into_iter().into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` + | ^^^^^^^^^^------------------------ + | | + | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:179:13 @@ -170,7 +178,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:195:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` + | ^^^^^^^^^^------------------------------------ + | | + | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:179:13 @@ -182,7 +192,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:241:24 | LL | foo2::([1, 2, 3].into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]` + | ^^^^^^^^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:220:12 @@ -194,7 +206,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:249:14 | LL | foo3([1, 2, 3].into_iter()); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]` + | ^^^^^^^^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:229:12 @@ -206,7 +220,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:258:16 | LL | S1.foo([1, 2].into_iter()); - | ^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2]` + | ^^^^^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:255:27 @@ -218,7 +234,9 @@ error: explicit call to `.into_iter()` in function argument accepting `IntoItera --> tests/ui/useless_conversion.rs:277:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); - | ^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `v1` + | ^^------------ + | | + | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` --> tests/ui/useless_conversion.rs:264:20 @@ -274,5 +292,90 @@ error: useless conversion to the same type: `T` LL | x.into_iter().map(Into::into).collect() | ^^^^^^^^^^^^^^^^ help: consider removing -error: aborting due to 36 previous errors +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:358:29 + | +LL | takes_into_iter(self.my_field.into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:347:32 + | +LL | fn takes_into_iter(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter(self.my_field.into_iter()); +LL + takes_into_iter(&self.my_field); + | + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:366:29 + | +LL | takes_into_iter(self.my_field.into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:347:32 + | +LL | fn takes_into_iter(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter(self.my_field.into_iter()); +LL + takes_into_iter(&mut self.my_field); + | + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:375:29 + | +LL | takes_into_iter(self.my_field.into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:347:32 + | +LL | fn takes_into_iter(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter(self.my_field.into_iter()); +LL + takes_into_iter(*self.my_field); + | + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:384:29 + | +LL | takes_into_iter(self.my_field.into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:347:32 + | +LL | fn takes_into_iter(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter(self.my_field.into_iter()); +LL + takes_into_iter(&*self.my_field); + | + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:393:29 + | +LL | takes_into_iter(self.my_field.into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:347:32 + | +LL | fn takes_into_iter(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter(self.my_field.into_iter()); +LL + takes_into_iter(&mut *self.my_field); + | + +error: aborting due to 41 previous errors diff --git a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed new file mode 100644 index 000000000000..03b34afa54ec --- /dev/null +++ b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed @@ -0,0 +1,52 @@ +#![warn(clippy::useless_nonzero_new_unchecked)] + +use std::num::{NonZero, NonZeroUsize}; + +#[clippy::msrv = "1.83"] +const fn func() -> NonZeroUsize { + const { NonZeroUsize::new(3).unwrap() } + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context +} + +#[clippy::msrv = "1.82"] +const fn func_older() -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(3) } +} + +const fn func_performance_hit_if_linted() -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(3) } +} + +const fn func_may_panic_at_run_time_if_linted(x: usize) -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(x) } +} + +macro_rules! uns { + ($expr:expr) => { + unsafe { $expr } + }; +} + +macro_rules! nzu { + () => { + NonZeroUsize::new_unchecked(1) + }; +} + +fn main() { + const _A: NonZeroUsize = NonZeroUsize::new(3).unwrap(); + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + static _B: NonZero = NonZero::::new(42).unwrap(); + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + const _C: usize = unsafe { NonZeroUsize::new(3).unwrap().get() }; + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + const AUX: usize = 3; + const _D: NonZeroUsize = NonZeroUsize::new(AUX).unwrap(); + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + const _X: NonZeroUsize = uns!(NonZeroUsize::new_unchecked(3)); + const _Y: NonZeroUsize = unsafe { nzu!() }; +} diff --git a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs new file mode 100644 index 000000000000..d450e3a03ec5 --- /dev/null +++ b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs @@ -0,0 +1,52 @@ +#![warn(clippy::useless_nonzero_new_unchecked)] + +use std::num::{NonZero, NonZeroUsize}; + +#[clippy::msrv = "1.83"] +const fn func() -> NonZeroUsize { + const { unsafe { NonZeroUsize::new_unchecked(3) } } + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context +} + +#[clippy::msrv = "1.82"] +const fn func_older() -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(3) } +} + +const fn func_performance_hit_if_linted() -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(3) } +} + +const fn func_may_panic_at_run_time_if_linted(x: usize) -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(x) } +} + +macro_rules! uns { + ($expr:expr) => { + unsafe { $expr } + }; +} + +macro_rules! nzu { + () => { + NonZeroUsize::new_unchecked(1) + }; +} + +fn main() { + const _A: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) }; + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + static _B: NonZero = unsafe { NonZero::::new_unchecked(42) }; + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + const _C: usize = unsafe { NonZeroUsize::new_unchecked(3).get() }; + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + const AUX: usize = 3; + const _D: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(AUX) }; + //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + + const _X: NonZeroUsize = uns!(NonZeroUsize::new_unchecked(3)); + const _Y: NonZeroUsize = unsafe { nzu!() }; +} diff --git a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.stderr b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.stderr new file mode 100644 index 000000000000..adb146167633 --- /dev/null +++ b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.stderr @@ -0,0 +1,37 @@ +error: `NonZeroUsize::new()` and `Option::unwrap()` can be safely used in a `const` context + --> tests/ui/useless_nonzero_new_unchecked.rs:7:13 + | +LL | const { unsafe { NonZeroUsize::new_unchecked(3) } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use instead: `NonZeroUsize::new(3).unwrap()` + | + = note: `-D clippy::useless-nonzero-new-unchecked` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_nonzero_new_unchecked)]` + +error: `NonZeroUsize::new()` and `Option::unwrap()` can be safely used in a `const` context + --> tests/ui/useless_nonzero_new_unchecked.rs:37:30 + | +LL | const _A: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use instead: `NonZeroUsize::new(3).unwrap()` + +error: `NonZero::::new()` and `Option::unwrap()` can be safely used in a `const` context + --> tests/ui/useless_nonzero_new_unchecked.rs:40:30 + | +LL | static _B: NonZero = unsafe { NonZero::::new_unchecked(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use instead: `NonZero::::new(42).unwrap()` + +error: `NonZeroUsize::new()` and `Option::unwrap()` can be safely used in a `const` context + --> tests/ui/useless_nonzero_new_unchecked.rs:43:32 + | +LL | const _C: usize = unsafe { NonZeroUsize::new_unchecked(3).get() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use instead: `NonZeroUsize::new(3).unwrap()` + | + = note: the fixed expression does not require an `unsafe` context + +error: `NonZeroUsize::new()` and `Option::unwrap()` can be safely used in a `const` context + --> tests/ui/useless_nonzero_new_unchecked.rs:47:30 + | +LL | const _D: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(AUX) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use instead: `NonZeroUsize::new(AUX).unwrap()` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs index e29898f068d3..ed357137095b 100644 --- a/src/tools/clippy/tests/versioncheck.rs +++ b/src/tools/clippy/tests/versioncheck.rs @@ -88,5 +88,5 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() { _ => { panic!("Failed to parse rustc version: {vsplit:?}"); }, - }; + } } diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index eadfd7107c77..3d35116ebc17 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -29,7 +29,6 @@ users_on_vacation = [ "*" = [ "@Manishearth", "@llogiq", - "@xFrednet", "@Alexendoo", "@dswij", "@Jarcho", diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index c2197b89c566..34d76ad642ec 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -341,8 +341,8 @@ window.filters = { || !filters.levels_filter[lint.level] || !filters.applicabilities_filter[lint.applicability] || !(filters.version_filter["="] === null || lint.version === filters.version_filter["="]) - || !(filters.version_filter["≥"] === null || lint.version > filters.version_filter["≥"]) - || !(filters.version_filter["≤"] === null || lint.version < filters.version_filter["≤"]) + || !(filters.version_filter["≥"] === null || lint.version >= filters.version_filter["≥"]) + || !(filters.version_filter["≤"] === null || lint.version <= filters.version_filter["≤"]) ); if (lint.filteredOut || lint.searchFilteredOut) { lint.elem.style.display = "none"; diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e548b44d8c2c..7f46e2f5ddb1 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2f348cb7ce4063fa4eb40038e6ada3c5214717bd +122fb29eb639aae852b9dcba0fd7aefc691be118 diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index bcc8668dbc12..2c4cb4bfce7b 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -865,7 +865,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this); let cause = match kind { - RetagKind::TwoPhase { .. } => RetagCause::TwoPhase, + RetagKind::TwoPhase => RetagCause::TwoPhase, RetagKind::FnEntry => unreachable!(), RetagKind::Raw | RetagKind::Default => RetagCause::Normal, }; @@ -880,7 +880,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields; let retag_cause = match kind { - RetagKind::TwoPhase { .. } => unreachable!(), // can only happen in `retag_ptr_value` + RetagKind::TwoPhase => unreachable!(), // can only happen in `retag_ptr_value` RetagKind::FnEntry => RetagCause::FnEntry, RetagKind::Default | RetagKind::Raw => RetagCause::Normal, }; diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index c8f04e252072..36b15dbf623d 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -558,15 +558,15 @@ where match chars.next() { Some('"') => { - cmd.extend(iter::repeat('\\').take(nslashes * 2 + 1)); + cmd.extend(iter::repeat_n('\\', nslashes * 2 + 1)); cmd.push('"'); } Some(c) => { - cmd.extend(iter::repeat('\\').take(nslashes)); + cmd.extend(iter::repeat_n('\\', nslashes)); cmd.push(c); } None => { - cmd.extend(iter::repeat('\\').take(nslashes * 2)); + cmd.extend(iter::repeat_n('\\', nslashes * 2)); break; } } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 2955dc38a8c2..914583df2fab 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -36,6 +36,9 @@ clippy::needless_question_mark, clippy::needless_lifetimes, clippy::too_long_first_doc_paragraph, + // Temporarily disabled as fixing it would cause conflicts + clippy::manual_repeat_n, + // We don't use translatable diagnostics rustc::diagnostic_outside_of_impl, // We are not implementing queries here so it's fine rustc::potential_query_instability, diff --git a/src/tools/miri/tests/pass/disjoint-array-accesses.rs b/src/tools/miri/tests/pass/disjoint-array-accesses.rs new file mode 100644 index 000000000000..50d0ea52ad4a --- /dev/null +++ b/src/tools/miri/tests/pass/disjoint-array-accesses.rs @@ -0,0 +1,35 @@ +// This is a regression test for issue #135671 where a MIR refactor about arrays and their lengths +// unexpectedly caused borrowck errors for disjoint borrows of array elements, for which we had no +// tests. This is a collection of a few code samples from that issue. + +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + +struct Test { + a: i32, + b: i32, +} + +fn one() { + let inputs: &mut [_] = &mut [Test { a: 0, b: 0 }]; + let a = &mut inputs[0].a; + let b = &mut inputs[0].b; + + *a = 0; + *b = 1; +} + +fn two() { + let slice = &mut [(0, 0)][..]; + std::mem::swap(&mut slice[0].0, &mut slice[0].1); +} + +fn three(a: &mut [(i32, i32)], i: usize, j: usize) -> (&mut i32, &mut i32) { + (&mut a[i].0, &mut a[j].1) +} + +fn main() { + one(); + two(); + three(&mut [(1, 2), (3, 4)], 0, 1); +} diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index aa05b5f0e76c..04de3493ea29 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -148,18 +148,15 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> let is_aarch64 = target_triple.starts_with("aarch64"); - let mut skip_tests = vec![ - // Fails because of linker errors, as of June 2023. - "tests/ui/process/nofile-limit.rs".to_string(), - ]; - - if is_aarch64 { - skip_tests.extend([ + let skip_tests = if is_aarch64 { + vec![ // Those tests fail only inside of Docker on aarch64, as of December 2024 "tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs".to_string(), "tests/ui/consts/large_const_alloc.rs".to_string(), - ]); - } + ] + } else { + vec![] + }; let checkout_dir = Utf8PathBuf::from("/checkout"); let env = EnvironmentBuilder::default() @@ -191,10 +188,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .build_dir(checkout_dir) .shared_llvm(false) .use_bolt(false) - .skipped_tests(vec![ - // Fails as of June 2023. - "tests\\codegen\\vec-shrink-panik.rs".to_string(), - ]) + .skipped_tests(vec![]) .build()?; (env, shared.build_args) diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs index e1887b93b93a..a57b102a5fd2 100644 --- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -1,7 +1,6 @@ -// //@ compile-flags:-Zprint-mono-items=eager -//@ compile-flags:-Zinline-in-all-cgus //@ compile-flags:-Zinline-mir=no +//@ compile-flags: -O #![crate_type = "lib"] diff --git a/tests/codegen-units/item-collection/generic-drop-glue.rs b/tests/codegen-units/item-collection/generic-drop-glue.rs index 6ecf98a032f5..c0d2e899bbc8 100644 --- a/tests/codegen-units/item-collection/generic-drop-glue.rs +++ b/tests/codegen-units/item-collection/generic-drop-glue.rs @@ -1,6 +1,5 @@ -// //@ compile-flags:-Zprint-mono-items=eager -//@ compile-flags:-Zinline-in-all-cgus +//@ compile-flags: -O #![deny(dead_code)] #![crate_type = "lib"] diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs index 9087fc6410ab..ee0b5dc1dd2c 100644 --- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs @@ -1,5 +1,4 @@ -// -//@ compile-flags:-Zprint-mono-items=eager -Zinline-in-all-cgus -Zmir-opt-level=0 +//@ compile-flags:-Zprint-mono-items=eager -Zmir-opt-level=0 #![deny(dead_code)] #![crate_type = "lib"] diff --git a/tests/codegen-units/item-collection/non-generic-drop-glue.rs b/tests/codegen-units/item-collection/non-generic-drop-glue.rs index c4d7942ba1ed..2eeccd2e99f2 100644 --- a/tests/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/tests/codegen-units/item-collection/non-generic-drop-glue.rs @@ -1,6 +1,5 @@ -// //@ compile-flags:-Zprint-mono-items=eager -//@ compile-flags:-Zinline-in-all-cgus +//@ compile-flags: -O #![deny(dead_code)] #![crate_type = "lib"] diff --git a/tests/codegen-units/item-collection/transitive-drop-glue.rs b/tests/codegen-units/item-collection/transitive-drop-glue.rs index 18954fab86f6..b999e466d54b 100644 --- a/tests/codegen-units/item-collection/transitive-drop-glue.rs +++ b/tests/codegen-units/item-collection/transitive-drop-glue.rs @@ -1,6 +1,5 @@ -// //@ compile-flags:-Zprint-mono-items=eager -//@ compile-flags:-Zinline-in-all-cgus +//@ compile-flags: -O #![deny(dead_code)] #![crate_type = "lib"] diff --git a/tests/codegen-units/item-collection/tuple-drop-glue.rs b/tests/codegen-units/item-collection/tuple-drop-glue.rs index 2e70d0151eb7..5e97fbb43368 100644 --- a/tests/codegen-units/item-collection/tuple-drop-glue.rs +++ b/tests/codegen-units/item-collection/tuple-drop-glue.rs @@ -1,6 +1,5 @@ -// //@ compile-flags:-Zprint-mono-items=eager -//@ compile-flags:-Zinline-in-all-cgus +//@ compile-flags: -O #![deny(dead_code)] #![crate_type = "lib"] diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs index 23e6003dc19f..97adf72ce2c9 100644 --- a/tests/codegen-units/item-collection/unsizing.rs +++ b/tests/codegen-units/item-collection/unsizing.rs @@ -1,5 +1,4 @@ //@ compile-flags:-Zprint-mono-items=eager -//@ compile-flags:-Zinline-in-all-cgus //@ compile-flags:-Zmir-opt-level=0 #![deny(dead_code)] diff --git a/tests/codegen-units/partitioning/README.md b/tests/codegen-units/partitioning/README.md new file mode 100644 index 000000000000..5dd6b1281fd9 --- /dev/null +++ b/tests/codegen-units/partitioning/README.md @@ -0,0 +1,14 @@ +# codegen-units/partitioning tests + +This test suite is designed to test that codegen unit partitioning works as intended. +Note that it does not evaluate whether CGU partitioning is *good*. That is the job of the compiler benchmark suite. + +All tests in this suite use the flag `-Zprint-mono-items=lazy`, which makes the compiler print a machine-readable summary of all MonoItems that were collected, which CGUs they were assigned to, and the linkage in each CGU. The output looks like: +``` +MONO_ITEM @@ [] [] +``` +DO NOT add tests to this suite that use `-Zprint-mono-items=eager`. That flag changes the way that MonoItem collection works in rather fundamental ways that are otherwise only used by `-Clink-dead-code`, and thus the MonoItems collected and their linkage under `-Zprint-mono-items=eager` does not correlate very well with normal compilation behavior. + +The current CGU partitioning algorithm essentially groups MonoItems by which module they are defined in, then merges small CGUs. There are a lot of inline modules in this test suite because that's the only way to observe the partitioning. + +Currently, the test suite is very heavily biased towards incremental builds with -Copt-level=0. This is mostly an accident of history; the entire test suite was added as part of supporting incremental compilation in #32779. But also CGU partitioning is *mostly* valuable because the CGU is the unit of incrementality to the codegen backend (cached queries are the unit of incrementality for the rest of the compiler). diff --git a/tests/codegen-units/partitioning/auxiliary/shared_generics_aux.rs b/tests/codegen-units/partitioning/auxiliary/shared_generics_aux.rs index b6c568ed387a..d3517df03763 100644 --- a/tests/codegen-units/partitioning/auxiliary/shared_generics_aux.rs +++ b/tests/codegen-units/partitioning/auxiliary/shared_generics_aux.rs @@ -1,7 +1,6 @@ // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels // prevent drop-glue from participating in share-generics. -//@ compile-flags:-Zshare-generics=yes -Copt-level=0 -//@ no-prefer-dynamic +//@ compile-flags: -Zshare-generics=yes -Copt-level=0 #![crate_type = "rlib"] diff --git a/tests/codegen-units/partitioning/extern-drop-glue.rs b/tests/codegen-units/partitioning/extern-drop-glue.rs index d3bce7b4223c..ca78c175dbf3 100644 --- a/tests/codegen-units/partitioning/extern-drop-glue.rs +++ b/tests/codegen-units/partitioning/extern-drop-glue.rs @@ -1,15 +1,14 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation -// We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus -Copt-level=0 +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -#![allow(dead_code)] #![crate_type = "rlib"] //@ aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; +// This test checks that drop glue is generated, even for types not defined in this crate, and all +// drop glue is put in the fallback CGU. + //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(cgu_extern_drop_glue::Struct)) @@ extern_drop_glue-fallback.cgu[External] struct LocalStruct(cgu_extern_drop_glue::Struct); diff --git a/tests/codegen-units/partitioning/extern-generic.rs b/tests/codegen-units/partitioning/extern-generic.rs index 602a5240283b..875ebb3098e5 100644 --- a/tests/codegen-units/partitioning/extern-generic.rs +++ b/tests/codegen-units/partitioning/extern-generic.rs @@ -1,51 +1,36 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=eager -Zshare-generics=y +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -#![allow(dead_code)] #![crate_type = "lib"] //@ aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ MONO_ITEM fn user @@ extern_generic[Internal] -fn user() { +// This test checks that, in an unoptimized build, a generic function and its callees are only +// instantiated once in this crate. + +//~ MONO_ITEM fn user @@ extern_generic[External] +pub fn user() { let _ = cgu_generic_function::foo("abc"); } -mod mod1 { +pub mod mod1 { use cgu_generic_function; - //~ MONO_ITEM fn mod1::user @@ extern_generic-mod1[Internal] - fn user() { + //~ MONO_ITEM fn mod1::user @@ extern_generic-mod1[External] + pub fn user() { let _ = cgu_generic_function::foo("abc"); } - mod mod1 { + pub mod mod1 { use cgu_generic_function; - //~ MONO_ITEM fn mod1::mod1::user @@ extern_generic-mod1-mod1[Internal] - fn user() { + //~ MONO_ITEM fn mod1::mod1::user @@ extern_generic-mod1-mod1[External] + pub fn user() { let _ = cgu_generic_function::foo("abc"); } } } -mod mod2 { - use cgu_generic_function; - - //~ MONO_ITEM fn mod2::user @@ extern_generic-mod2[Internal] - fn user() { - let _ = cgu_generic_function::foo("abc"); - } -} - -mod mod3 { - //~ MONO_ITEM fn mod3::non_user @@ extern_generic-mod3[Internal] - fn non_user() {} -} - -// Make sure the two generic functions from the extern crate get instantiated -// once for the current crate //~ MONO_ITEM fn cgu_generic_function::foo::<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] //~ MONO_ITEM fn cgu_generic_function::bar::<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] diff --git a/tests/codegen-units/partitioning/incremental-merging.rs b/tests/codegen-units/partitioning/incremental-merging.rs index 6834bb2bebf5..68eee803e5f2 100644 --- a/tests/codegen-units/partitioning/incremental-merging.rs +++ b/tests/codegen-units/partitioning/incremental-merging.rs @@ -1,7 +1,5 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Ccodegen-units=3 +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -Ccodegen-units=3 #![crate_type = "rlib"] @@ -9,8 +7,9 @@ // compilation but at the same time does not modify names of CGUs that were not // affected by merging. // -// We expect CGUs `aaa` and `bbb` to be merged (because they are the smallest), -// while `ccc` and `ddd` are supposed to stay untouched. +// CGU partitioning creates one CGU per module, so with 4 modules and codegen-units=3, +// two of the modules should be merged. We expect CGUs `aaa` and `bbb` to be merged +// (because they are the smallest), while `ccc` and `ddd` should stay untouched. pub mod aaa { //~ MONO_ITEM fn aaa::foo @@ incremental_merging-aaa--incremental_merging-bbb[External] diff --git a/tests/codegen-units/partitioning/inline-always.rs b/tests/codegen-units/partitioning/inline-always.rs new file mode 100644 index 000000000000..5e8cce0ac337 --- /dev/null +++ b/tests/codegen-units/partitioning/inline-always.rs @@ -0,0 +1,38 @@ +//@ incremental +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 + +#![crate_type = "lib"] + +// This test checks that a monomorphic inline(always) function is instantiated in every CGU that +// references it, even though this is an unoptimized incremental build. +// It also checks that an inline(always) function is only placed in CGUs that reference it. + +mod inline { + //~ MONO_ITEM fn inline::inlined_function @@ inline_always-user1[Internal] inline_always-user2[Internal] + #[inline(always)] + pub fn inlined_function() {} +} + +pub mod user1 { + use super::inline; + + //~ MONO_ITEM fn user1::foo @@ inline_always-user1[External] + pub fn foo() { + inline::inlined_function(); + } +} + +pub mod user2 { + use super::inline; + + //~ MONO_ITEM fn user2::bar @@ inline_always-user2[External] + pub fn bar() { + inline::inlined_function(); + } +} + +pub mod non_user { + + //~ MONO_ITEM fn non_user::baz @@ inline_always-non_user[External] + pub fn baz() {} +} diff --git a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs index b007ffe1cb51..d321c88d03a6 100644 --- a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -1,7 +1,5 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=1 #![crate_type = "lib"] diff --git a/tests/codegen-units/partitioning/local-drop-glue.rs b/tests/codegen-units/partitioning/local-drop-glue.rs index 5fa1df95cbc8..240f64e4f702 100644 --- a/tests/codegen-units/partitioning/local-drop-glue.rs +++ b/tests/codegen-units/partitioning/local-drop-glue.rs @@ -1,14 +1,14 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation -// We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus -Copt-level=0 +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -#![allow(dead_code)] #![crate_type = "rlib"] +// This test checks that drop glue is generated for types defined in this crate, and that all drop +// glue is put in the fallback CGU. +// This is rather similar to extern-drop-glue.rs. + //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(Struct)) @@ local_drop_glue-fallback.cgu[External] -struct Struct { +pub struct Struct { _a: u32, } @@ -18,7 +18,7 @@ impl Drop for Struct { } //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(Outer)) @@ local_drop_glue-fallback.cgu[External] -struct Outer { +pub struct Outer { _a: Struct, } @@ -33,7 +33,7 @@ pub mod mod1 { //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(mod1::Struct2)) @@ local_drop_glue-fallback.cgu[External] struct Struct2 { _a: Struct, - //~ MONO_ITEM fn std::ptr::drop_in_place::<(u32, Struct)> - shim(Some((u32, Struct))) @@ local_drop_glue-fallback.cgu[Internal] + //~ MONO_ITEM fn std::ptr::drop_in_place::<(u32, Struct)> - shim(Some((u32, Struct))) @@ local_drop_glue-fallback.cgu[External] _b: (u32, Struct), } diff --git a/tests/codegen-units/partitioning/local-generic.rs b/tests/codegen-units/partitioning/local-generic.rs index 0cfc572650c1..177eb2632f64 100644 --- a/tests/codegen-units/partitioning/local-generic.rs +++ b/tests/codegen-units/partitioning/local-generic.rs @@ -1,10 +1,11 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=eager +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -#![allow(dead_code)] #![crate_type = "lib"] +// This test checks that all the instantiations of a local generic fn are placed in the same CGU, +// regardless of where it is called. + //~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] //~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] //~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] @@ -13,34 +14,34 @@ pub fn generic(x: T) -> T { x } -//~ MONO_ITEM fn user @@ local_generic[Internal] -fn user() { +//~ MONO_ITEM fn user @@ local_generic[External] +pub fn user() { let _ = generic(0u32); } -mod mod1 { +pub mod mod1 { pub use super::generic; - //~ MONO_ITEM fn mod1::user @@ local_generic-mod1[Internal] - fn user() { + //~ MONO_ITEM fn mod1::user @@ local_generic-mod1[External] + pub fn user() { let _ = generic(0u64); } - mod mod1 { + pub mod mod1 { use super::generic; - //~ MONO_ITEM fn mod1::mod1::user @@ local_generic-mod1-mod1[Internal] - fn user() { + //~ MONO_ITEM fn mod1::mod1::user @@ local_generic-mod1-mod1[External] + pub fn user() { let _ = generic('c'); } } } -mod mod2 { +pub mod mod2 { use super::generic; - //~ MONO_ITEM fn mod2::user @@ local_generic-mod2[Internal] - fn user() { + //~ MONO_ITEM fn mod2::user @@ local_generic-mod2[External] + pub fn user() { let _ = generic("abc"); } } diff --git a/tests/codegen-units/partitioning/local-inlining-but-not-all.rs b/tests/codegen-units/partitioning/local-inlining-but-not-all.rs deleted file mode 100644 index 454de255254a..000000000000 --- a/tests/codegen-units/partitioning/local-inlining-but-not-all.rs +++ /dev/null @@ -1,38 +0,0 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation -//@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus=no - -#![allow(dead_code)] -#![crate_type = "lib"] - -mod inline { - - //~ MONO_ITEM fn inline::inlined_function @@ local_inlining_but_not_all-inline[External] - #[inline] - pub fn inlined_function() {} -} - -pub mod user1 { - use super::inline; - - //~ MONO_ITEM fn user1::foo @@ local_inlining_but_not_all-user1[External] - pub fn foo() { - inline::inlined_function(); - } -} - -pub mod user2 { - use super::inline; - - //~ MONO_ITEM fn user2::bar @@ local_inlining_but_not_all-user2[External] - pub fn bar() { - inline::inlined_function(); - } -} - -pub mod non_user { - - //~ MONO_ITEM fn non_user::baz @@ local_inlining_but_not_all-non_user[External] - pub fn baz() {} -} diff --git a/tests/codegen-units/partitioning/local-inlining.rs b/tests/codegen-units/partitioning/local-inlining.rs deleted file mode 100644 index 42c68b5c6218..000000000000 --- a/tests/codegen-units/partitioning/local-inlining.rs +++ /dev/null @@ -1,39 +0,0 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation -//@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus - -#![allow(dead_code)] -#![crate_type = "lib"] - -mod inline { - - // Important: This function should show up in all codegen units where it is inlined - //~ MONO_ITEM fn inline::inlined_function @@ local_inlining-user1[Internal] local_inlining-user2[Internal] - #[inline(always)] - pub fn inlined_function() {} -} - -pub mod user1 { - use super::inline; - - //~ MONO_ITEM fn user1::foo @@ local_inlining-user1[External] - pub fn foo() { - inline::inlined_function(); - } -} - -pub mod user2 { - use super::inline; - - //~ MONO_ITEM fn user2::bar @@ local_inlining-user2[External] - pub fn bar() { - inline::inlined_function(); - } -} - -pub mod non_user { - - //~ MONO_ITEM fn non_user::baz @@ local_inlining-non_user[External] - pub fn baz() {} -} diff --git a/tests/codegen-units/partitioning/local-transitive-inlining.rs b/tests/codegen-units/partitioning/local-transitive-inlining.rs index 0d279ebe7404..bcd32bd2e264 100644 --- a/tests/codegen-units/partitioning/local-transitive-inlining.rs +++ b/tests/codegen-units/partitioning/local-transitive-inlining.rs @@ -1,11 +1,13 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -#![allow(dead_code)] #![crate_type = "rlib"] +// This test checks that a monomorphic inline(always) function is instantiated in every CGU that +// references it, even if it is only referenced via another module. +// The modules `inline` and `direct_user` do not get CGUs because they only define inline(always) +// functions, which always get lazy codegen. + mod inline { //~ MONO_ITEM fn inline::inlined_function @@ local_transitive_inlining-indirect_user[Internal] @@ -13,7 +15,7 @@ mod inline { pub fn inlined_function() {} } -mod direct_user { +pub mod direct_user { use super::inline; //~ MONO_ITEM fn direct_user::foo @@ local_transitive_inlining-indirect_user[Internal] diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs index 94d06829c6c3..4d3f946fd953 100644 --- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs @@ -1,9 +1,11 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 #![crate_type = "lib"] +// This test ensures that methods are assigned to the module where their self-type is defined, not +// where the method is defined. + pub struct SomeType; struct SomeGenericType(T1, T2); diff --git a/tests/codegen-units/partitioning/regular-modules.rs b/tests/codegen-units/partitioning/regular-modules.rs index 294971464155..d59074e7e347 100644 --- a/tests/codegen-units/partitioning/regular-modules.rs +++ b/tests/codegen-units/partitioning/regular-modules.rs @@ -1,71 +1,71 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=eager +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -#![allow(dead_code)] #![crate_type = "lib"] -//~ MONO_ITEM fn foo @@ regular_modules[Internal] -fn foo() {} +// This test ensures that regular fn items and statics are assigned to the CGU of their module. -//~ MONO_ITEM fn bar @@ regular_modules[Internal] -fn bar() {} +//~ MONO_ITEM fn foo @@ regular_modules[External] +pub fn foo() {} -//~ MONO_ITEM static BAZ @@ regular_modules[Internal] -static BAZ: u64 = 0; +//~ MONO_ITEM fn bar @@ regular_modules[External] +pub fn bar() {} -mod mod1 { +//~ MONO_ITEM static BAZ @@ regular_modules[External] +pub static BAZ: u64 = 0; - //~ MONO_ITEM fn mod1::foo @@ regular_modules-mod1[Internal] - fn foo() {} - //~ MONO_ITEM fn mod1::bar @@ regular_modules-mod1[Internal] - fn bar() {} - //~ MONO_ITEM static mod1::BAZ @@ regular_modules-mod1[Internal] - static BAZ: u64 = 0; +pub mod mod1 { - mod mod1 { - //~ MONO_ITEM fn mod1::mod1::foo @@ regular_modules-mod1-mod1[Internal] - fn foo() {} - //~ MONO_ITEM fn mod1::mod1::bar @@ regular_modules-mod1-mod1[Internal] - fn bar() {} - //~ MONO_ITEM static mod1::mod1::BAZ @@ regular_modules-mod1-mod1[Internal] - static BAZ: u64 = 0; + //~ MONO_ITEM fn mod1::foo @@ regular_modules-mod1[External] + pub fn foo() {} + //~ MONO_ITEM fn mod1::bar @@ regular_modules-mod1[External] + pub fn bar() {} + //~ MONO_ITEM static mod1::BAZ @@ regular_modules-mod1[External] + pub static BAZ: u64 = 0; + + pub mod mod1 { + //~ MONO_ITEM fn mod1::mod1::foo @@ regular_modules-mod1-mod1[External] + pub fn foo() {} + //~ MONO_ITEM fn mod1::mod1::bar @@ regular_modules-mod1-mod1[External] + pub fn bar() {} + //~ MONO_ITEM static mod1::mod1::BAZ @@ regular_modules-mod1-mod1[External] + pub static BAZ: u64 = 0; } - mod mod2 { - //~ MONO_ITEM fn mod1::mod2::foo @@ regular_modules-mod1-mod2[Internal] - fn foo() {} - //~ MONO_ITEM fn mod1::mod2::bar @@ regular_modules-mod1-mod2[Internal] - fn bar() {} - //~ MONO_ITEM static mod1::mod2::BAZ @@ regular_modules-mod1-mod2[Internal] - static BAZ: u64 = 0; + pub mod mod2 { + //~ MONO_ITEM fn mod1::mod2::foo @@ regular_modules-mod1-mod2[External] + pub fn foo() {} + //~ MONO_ITEM fn mod1::mod2::bar @@ regular_modules-mod1-mod2[External] + pub fn bar() {} + //~ MONO_ITEM static mod1::mod2::BAZ @@ regular_modules-mod1-mod2[External] + pub static BAZ: u64 = 0; } } -mod mod2 { +pub mod mod2 { - //~ MONO_ITEM fn mod2::foo @@ regular_modules-mod2[Internal] - fn foo() {} - //~ MONO_ITEM fn mod2::bar @@ regular_modules-mod2[Internal] - fn bar() {} - //~ MONO_ITEM static mod2::BAZ @@ regular_modules-mod2[Internal] - static BAZ: u64 = 0; + //~ MONO_ITEM fn mod2::foo @@ regular_modules-mod2[External] + pub fn foo() {} + //~ MONO_ITEM fn mod2::bar @@ regular_modules-mod2[External] + pub fn bar() {} + //~ MONO_ITEM static mod2::BAZ @@ regular_modules-mod2[External] + pub static BAZ: u64 = 0; - mod mod1 { - //~ MONO_ITEM fn mod2::mod1::foo @@ regular_modules-mod2-mod1[Internal] - fn foo() {} - //~ MONO_ITEM fn mod2::mod1::bar @@ regular_modules-mod2-mod1[Internal] - fn bar() {} - //~ MONO_ITEM static mod2::mod1::BAZ @@ regular_modules-mod2-mod1[Internal] - static BAZ: u64 = 0; + pub mod mod1 { + //~ MONO_ITEM fn mod2::mod1::foo @@ regular_modules-mod2-mod1[External] + pub fn foo() {} + //~ MONO_ITEM fn mod2::mod1::bar @@ regular_modules-mod2-mod1[External] + pub fn bar() {} + //~ MONO_ITEM static mod2::mod1::BAZ @@ regular_modules-mod2-mod1[External] + pub static BAZ: u64 = 0; } - mod mod2 { - //~ MONO_ITEM fn mod2::mod2::foo @@ regular_modules-mod2-mod2[Internal] - fn foo() {} - //~ MONO_ITEM fn mod2::mod2::bar @@ regular_modules-mod2-mod2[Internal] - fn bar() {} - //~ MONO_ITEM static mod2::mod2::BAZ @@ regular_modules-mod2-mod2[Internal] - static BAZ: u64 = 0; + pub mod mod2 { + //~ MONO_ITEM fn mod2::mod2::foo @@ regular_modules-mod2-mod2[External] + pub fn foo() {} + //~ MONO_ITEM fn mod2::mod2::bar @@ regular_modules-mod2-mod2[External] + pub fn bar() {} + //~ MONO_ITEM static mod2::mod2::BAZ @@ regular_modules-mod2-mod2[External] + pub static BAZ: u64 = 0; } } diff --git a/tests/codegen-units/partitioning/shared-generics.rs b/tests/codegen-units/partitioning/shared-generics.rs index ea312719ac91..b5bf376a6134 100644 --- a/tests/codegen-units/partitioning/shared-generics.rs +++ b/tests/codegen-units/partitioning/shared-generics.rs @@ -2,13 +2,19 @@ // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels // prevent drop-glue from participating in share-generics. //@ incremental -//@ compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Copt-level=0 +//@ compile-flags: -Zprint-mono-items=lazy -Zshare-generics=yes -Copt-level=0 #![crate_type = "rlib"] //@ aux-build:shared_generics_aux.rs extern crate shared_generics_aux; +// This test ensures that when a crate and a dependency are compiled with -Zshare-generics, the +// downstream crate reuses generic instantiations from the dependency, but will still instantiate +// its own copy when instantiating with arguments that the dependency did not. +// Drop glue has a lot of special handling in the compiler, so we check that drop glue is also +// shared. + //~ MONO_ITEM fn foo pub fn foo() { //~ MONO_ITEM fn shared_generics_aux::generic_fn:: @@ shared_generics_aux-in-shared_generics.volatile[External] diff --git a/tests/codegen-units/partitioning/statics.rs b/tests/codegen-units/partitioning/statics.rs index 00dd6d877e1e..72bca4c5ed36 100644 --- a/tests/codegen-units/partitioning/statics.rs +++ b/tests/codegen-units/partitioning/statics.rs @@ -1,9 +1,11 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 #![crate_type = "rlib"] +// This test ensures that statics are assigned to the correct module when they are defined inside +// of a function. + //~ MONO_ITEM static FOO @@ statics[Internal] static FOO: u32 = 0; diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs index 3880bba6f6b3..fd73e3fe9238 100644 --- a/tests/codegen-units/partitioning/vtable-through-const.rs +++ b/tests/codegen-units/partitioning/vtable-through-const.rs @@ -1,14 +1,11 @@ -// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental -//@ compile-flags:-Zprint-mono-items=lazy -//@ compile-flags:-Zinline-in-all-cgus // Need to disable optimizations to ensure consistent output across all CI runners. -//@ compile-flags:-Copt-level=0 +//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -// This test case makes sure, that references made through constants are -// recorded properly in the InliningMap. +#![crate_type = "rlib"] -#![crate_type = "lib"] +// This test case makes sure that references made through constants cause trait associated methods +// to be monomorphized when required. mod mod1 { struct NeedsDrop; @@ -43,7 +40,7 @@ mod mod1 { x } - // These are referenced, so they produce mono-items (see start()) + // These are referenced, so they produce mono-items (see main) pub const TRAIT1_REF: &'static Trait1 = &NeedsDrop as &Trait1; pub const TRAIT1_GEN_REF: &'static Trait1Gen = &NeedsDrop as &Trait1Gen; pub const ID_CHAR: fn(char) -> char = id::; @@ -77,9 +74,8 @@ mod mod1 { pub const ID_I64: fn(i64) -> i64 = id::; } -//~ MONO_ITEM fn start -#[no_mangle] -pub fn start(_: isize, _: *const *const u8) -> isize { +//~ MONO_ITEM fn main @@ vtable_through_const[External] +pub fn main() { //~ MONO_ITEM fn ::drop @@ vtable_through_const-fallback.cgu[External] //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(mod1::NeedsDrop)) @@ vtable_through_const-fallback.cgu[External] @@ -103,6 +99,4 @@ pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn mod1::id:: @@ vtable_through_const-mod1.volatile[External] mod1::ID_CHAR('x'); - - 0 } diff --git a/tests/codegen/i128-x86-callconv.rs b/tests/codegen/i128-x86-callconv.rs new file mode 100644 index 000000000000..9a9c9002fc02 --- /dev/null +++ b/tests/codegen/i128-x86-callconv.rs @@ -0,0 +1,79 @@ +//! Verify that Rust implements the expected calling convention for `i128`/`u128`. + +// Eliminate intermediate instructions during `nop` tests +//@ compile-flags: -Copt-level=1 + +//@ add-core-stubs +//@ revisions: MSVC MINGW +//@ [MSVC] needs-llvm-components: x86 +//@ [MINGW] needs-llvm-components: x86 +//@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc +//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu +//@ [MSVC] filecheck-flags: --check-prefix=WIN +//@ [MINGW] filecheck-flags: --check-prefix=WIN + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core, lang_items)] + +extern crate minicore; + +extern "C" { + fn extern_call(arg0: i128); + fn extern_ret() -> i128; +} + +#[no_mangle] +pub extern "C" fn pass(_arg0: u32, arg1: i128) { + // CHECK-LABEL: @pass( + // i128 is passed indirectly on Windows. It should load the pointer to the stack and pass + // a pointer to that allocation. + // WIN-SAME: %_arg0, ptr{{.*}} %arg1) + // WIN: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16 + // WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 + // WIN: store i128 [[LOADED]], ptr [[PASS]] + // WIN: call void @extern_call + unsafe { extern_call(arg1) }; +} + +// Check that we produce the correct return ABI +#[no_mangle] +pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 { + // CHECK-LABEL: @ret( + // i128 is returned in xmm0 on Windows + // FIXME(#134288): This may change for the `-msvc` targets in the future. + // WIN-SAME: i32{{.*}} %_arg0, ptr{{.*}} %arg1) + // WIN: [[LOADED:%[_0-9]+]] = load <16 x i8>, ptr %arg1 + // WIN-NEXT: ret <16 x i8> [[LOADED]] + arg1 +} + +// Check that we consume the correct return ABI +#[no_mangle] +pub extern "C" fn forward(dst: *mut i128) { + // CHECK-LABEL: @forward + // WIN-SAME: ptr{{.*}} %dst) + // WIN: [[RETURNED:%[_0-9]+]] = tail call <16 x i8> @extern_ret() + // WIN: store <16 x i8> [[RETURNED]], ptr %dst + // WIN: ret void + unsafe { *dst = extern_ret() }; +} + +#[repr(C)] +struct RetAggregate { + a: i32, + b: i128, +} + +#[no_mangle] +pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate { + // CHECK-LABEL: @ret_aggregate( + // Aggregates should also be returned indirectly + // WIN-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1) + // WIN: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 + // WIN: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]] + // WIN: store i128 [[LOADED]], ptr [[GEP]] + // WIN: ret void + RetAggregate { a: 1, b: arg1 } +} diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir index a467987e8861..8d9176ef301f 100644 --- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir +++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir @@ -7,8 +7,7 @@ fn main() -> () { let mut _5: u32; let mut _6: *mut usize; let _7: usize; - let mut _8: usize; - let mut _9: bool; + let mut _8: bool; scope 1 { debug x => _1; let mut _2: usize; @@ -41,9 +40,8 @@ fn main() -> () { StorageDead(_6); StorageLive(_7); _7 = copy _2; - _8 = Len(_1); - _9 = Lt(copy _7, copy _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable]; + _8 = Lt(copy _7, const 3_usize); + assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir index bd7365543bdc..e1df0e3e2a3b 100644 --- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir +++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir @@ -7,8 +7,7 @@ fn main() -> () { let mut _5: u32; let mut _6: *mut usize; let _7: usize; - let mut _8: usize; - let mut _9: bool; + let mut _8: bool; scope 1 { debug x => _1; let mut _2: usize; @@ -41,9 +40,8 @@ fn main() -> () { StorageDead(_6); StorageLive(_7); _7 = copy _2; - _8 = Len(_1); - _9 = Lt(copy _7, copy _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue]; + _8 = Lt(copy _7, const 3_usize); + assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind continue]; } bb2: { diff --git a/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir new file mode 100644 index 000000000000..d28a2031013f --- /dev/null +++ b/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir @@ -0,0 +1,31 @@ +// MIR for `index_array` after built + +fn index_array(_1: &[i32; 7], _2: usize) -> &i32 { + debug array => _1; + debug index => _2; + let mut _0: &i32; + let _3: &i32; + let _4: usize; + let mut _5: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = copy _2; + FakeRead(ForIndex, (*_1)); + _5 = Lt(copy _4, const 7_usize); + assert(move _5, "index out of bounds: the length is {} but the index is {}", const 7_usize, copy _4) -> [success: bb1, unwind: bb2]; + } + + bb1: { + _3 = &(*_1)[_4]; + _0 = &(*_3); + StorageDead(_4); + StorageDead(_3); + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir new file mode 100644 index 000000000000..e9627532c382 --- /dev/null +++ b/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir @@ -0,0 +1,31 @@ +// MIR for `index_const_generic_array` after built + +fn index_const_generic_array(_1: &[i32; N], _2: usize) -> &i32 { + debug array => _1; + debug index => _2; + let mut _0: &i32; + let _3: &i32; + let _4: usize; + let mut _5: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = copy _2; + FakeRead(ForIndex, (*_1)); + _5 = Lt(copy _4, const N); + assert(move _5, "index out of bounds: the length is {} but the index is {}", const N, copy _4) -> [success: bb1, unwind: bb2]; + } + + bb1: { + _3 = &(*_1)[_4]; + _0 = &(*_3); + StorageDead(_4); + StorageDead(_3); + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir new file mode 100644 index 000000000000..e6745ddbf298 --- /dev/null +++ b/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir @@ -0,0 +1,34 @@ +// MIR for `index_custom` after built + +fn index_custom(_1: &WithSliceTail, _2: usize) -> &i32 { + debug custom => _1; + debug index => _2; + let mut _0: &i32; + let _3: &i32; + let _4: usize; + let mut _5: *const [i32]; + let mut _6: usize; + let mut _7: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = copy _2; + _5 = &raw const (fake) ((*_1).1: [i32]); + _6 = PtrMetadata(move _5); + _7 = Lt(copy _4, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2]; + } + + bb1: { + _3 = &((*_1).1: [i32])[_4]; + _0 = &(*_3); + StorageDead(_4); + StorageDead(_3); + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir new file mode 100644 index 000000000000..c96bcdfc918a --- /dev/null +++ b/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir @@ -0,0 +1,34 @@ +// MIR for `index_mut_slice` after built + +fn index_mut_slice(_1: &mut [i32], _2: usize) -> &i32 { + debug slice => _1; + debug index => _2; + let mut _0: &i32; + let _3: &i32; + let _4: usize; + let mut _5: *const [i32]; + let mut _6: usize; + let mut _7: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = copy _2; + _5 = &raw const (fake) (*_1); + _6 = PtrMetadata(move _5); + _7 = Lt(copy _4, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2]; + } + + bb1: { + _3 = &(*_1)[_4]; + _0 = &(*_3); + StorageDead(_4); + StorageDead(_3); + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir new file mode 100644 index 000000000000..0911df590497 --- /dev/null +++ b/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir @@ -0,0 +1,32 @@ +// MIR for `index_slice` after built + +fn index_slice(_1: &[i32], _2: usize) -> &i32 { + debug slice => _1; + debug index => _2; + let mut _0: &i32; + let _3: &i32; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = copy _2; + _5 = PtrMetadata(copy _1); + _6 = Lt(copy _4, copy _5); + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb2]; + } + + bb1: { + _3 = &(*_1)[_4]; + _0 = &(*_3); + StorageDead(_4); + StorageDead(_3); + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/index_array_and_slice.rs b/tests/mir-opt/building/index_array_and_slice.rs new file mode 100644 index 000000000000..f91b37567f79 --- /dev/null +++ b/tests/mir-opt/building/index_array_and_slice.rs @@ -0,0 +1,71 @@ +//@ compile-flags: -C opt-level=0 + +// EMIT_MIR index_array_and_slice.index_array.built.after.mir +fn index_array(array: &[i32; 7], index: usize) -> &i32 { + // CHECK: bb0: + // CHECK: [[LT:_.+]] = Lt(copy _2, const 7_usize); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const 7_usize, copy _2) -> [success: bb1, unwind + + // CHECK: bb1: + // CHECK: _0 = &(*_1)[_2]; + &array[index] +} + +// EMIT_MIR index_array_and_slice.index_const_generic_array.built.after.mir +fn index_const_generic_array(array: &[i32; N], index: usize) -> &i32 { + // CHECK: bb0: + // CHECK: [[LT:_.+]] = Lt(copy _2, const N); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const N, copy _2) -> [success: bb1, unwind + + // CHECK: bb1: + // CHECK: _0 = &(*_1)[_2]; + &array[index] +} + +// EMIT_MIR index_array_and_slice.index_slice.built.after.mir +fn index_slice(slice: &[i32], index: usize) -> &i32 { + // CHECK: bb0: + // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); + // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, + + // CHECK: bb1: + // CHECK: _0 = &(*_1)[_2]; + &slice[index] +} + +// EMIT_MIR index_array_and_slice.index_mut_slice.built.after.mir +fn index_mut_slice(slice: &mut [i32], index: usize) -> &i32 { + // While the filecheck here is identical to the above test, the emitted MIR is different. + // This cannot `copy _1` in the *built* MIR, only in the *runtime* MIR. + + // CHECK: bb0: + // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); + // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, + + // CHECK: bb1: + // CHECK: _0 = &(*_1)[_2]; + &slice[index] +} + +struct WithSliceTail(f64, [i32]); + +// EMIT_MIR index_array_and_slice.index_custom.built.after.mir +fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 { + // CHECK: bb0: + // CHECK: [[PTR:_.+]] = &raw const (fake) ((*_1).1: [i32]); + // CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]); + // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); + // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, + + // CHECK: bb1: + // CHECK: _0 = &((*_1).1: [i32])[_2]; + &custom.1[index] +} + +fn main() { + index_array(&[1, 2, 3, 4, 5, 6, 7], 3); + index_slice(&[1, 2, 3, 4, 5, 6, 7][..], 3); + _ = index_custom; +} diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff index e754af95ce39..3a5a8d009912 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff index e15a35c7fe94..62d6e6007e5c 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff index e754af95ce39..3a5a8d009912 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index e15a35c7fe94..62d6e6007e5c 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff index 15d301403671..b7cb37a335fa 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff @@ -32,11 +32,12 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = Len((*_1)); +- _7 = PtrMetadata(copy _1); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _8 = Lt(const 3_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const false; ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff index dd411d84f9fb..50388cbac361 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff @@ -32,11 +32,12 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = Len((*_1)); +- _7 = PtrMetadata(copy _1); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _8 = Lt(const 3_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const false; ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff index 15d301403671..b7cb37a335fa 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff @@ -32,11 +32,12 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = Len((*_1)); +- _7 = PtrMetadata(copy _1); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _8 = Lt(const 3_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const false; ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff index dd411d84f9fb..50388cbac361 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff @@ -32,11 +32,12 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = Len((*_1)); +- _7 = PtrMetadata(copy _1); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _8 = Lt(const 3_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const false; ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff index 49ea51deed69..3569998b13fa 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff index 103bfbcaf642..50b31c9ac136 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff index 49ea51deed69..3569998b13fa 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff index 103bfbcaf642..50b31c9ac136 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff index f7c1c2da01fc..a41668b6fa36 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff index 436773c85563..2313084b49e6 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff index f7c1c2da01fc..a41668b6fa36 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff index 436773c85563..2313084b49e6 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff index 8a8ea5b7e200..0798b3039295 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff @@ -30,11 +30,12 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; - _7 = Len((*_2)); +- _7 = PtrMetadata(copy _2); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _8 = Lt(const 1_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff index f0c844884f67..c0b3d4d32190 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff @@ -30,11 +30,12 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; - _7 = Len((*_2)); +- _7 = PtrMetadata(copy _2); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _8 = Lt(const 1_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff index 8a8ea5b7e200..0798b3039295 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff @@ -30,11 +30,12 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; - _7 = Len((*_2)); +- _7 = PtrMetadata(copy _2); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _8 = Lt(const 1_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff index f0c844884f67..c0b3d4d32190 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff @@ -30,11 +30,12 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; - _7 = Len((*_2)); +- _7 = PtrMetadata(copy _2); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _8 = Lt(const 1_usize, copy _7); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff index 6d967257df1f..689083dfc1d3 100644 --- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff +++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff @@ -18,8 +18,7 @@ let mut _15: !; let mut _17: i32; let _18: usize; - let mut _19: usize; - let mut _20: bool; + let mut _19: bool; scope 1 { debug sum => _1; let _2: [i32; 4]; @@ -92,11 +91,10 @@ StorageLive(_17); - StorageLive(_18); - _18 = copy _16; - _19 = Len(_2); -- _20 = Lt(copy _18, copy _19); -- assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind unreachable]; -+ _20 = Lt(copy _16, copy _19); -+ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind unreachable]; +- _19 = Lt(copy _18, const 4_usize); +- assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind unreachable]; ++ _19 = Lt(copy _16, const 4_usize); ++ assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind unreachable]; } bb7: { diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff index 3580c87c4699..7f768a9f834d 100644 --- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff +++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff @@ -18,8 +18,7 @@ let mut _15: !; let mut _17: i32; let _18: usize; - let mut _19: usize; - let mut _20: bool; + let mut _19: bool; scope 1 { debug sum => _1; let _2: [i32; 4]; @@ -92,11 +91,10 @@ StorageLive(_17); - StorageLive(_18); - _18 = copy _16; - _19 = Len(_2); -- _20 = Lt(copy _18, copy _19); -- assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind continue]; -+ _20 = Lt(copy _16, copy _19); -+ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind continue]; +- _19 = Lt(copy _18, const 4_usize); +- assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind continue]; ++ _19 = Lt(copy _16, const 4_usize); ++ assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind continue]; } bb7: { diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff index a46daef435f3..0275d7e8a0d4 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff index 1a4e15b45faa..490ed4b55a1d 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff index a46daef435f3..0275d7e8a0d4 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff index 1a4e15b45faa..490ed4b55a1d 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 4_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 4_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs index e442ef99f79e..1aa8dcd28f4e 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/array_index.rs @@ -11,9 +11,10 @@ fn main() { // CHECK: [[array_lit]] = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = PtrMetadata( // CHECK-NOT: {{_.*}} = Lt( // CHECK-NOT: assert(move _ - // CHECK: {{_.*}} = const 4_usize; + // CHECK: {{_.*}} = const 2_usize; // CHECK: {{_.*}} = const true; // CHECK: assert(const true // CHECK: [[x]] = copy [[array_lit]][2 of 3]; diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff index b7ff0b671f7b..f0d59ef5923f 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff index af6e3626142f..959c3e75214f 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff index b7ff0b671f7b..f0d59ef5923f 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff index af6e3626142f..959c3e75214f 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -6,8 +6,7 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: usize; - let mut _5: bool; + let mut _4: bool; scope 1 { debug x => _1; } @@ -18,11 +17,9 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Len(_2); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const 5000_usize; -+ _5 = const true; +- _4 = Lt(copy _3, const 5000_usize); +- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs index e9f2fa2badf9..e490cfde2472 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs @@ -10,7 +10,7 @@ fn main() { // CHECK: debug x => [[x:_.*]]; // CHECK: [[array_lit:_.*]] = [const 0_u8; 5000]; - // CHECK: {{_.*}} = const 5000_usize; + // CHECK: {{_.*}} = const 2_usize; // CHECK: {{_.*}} = const true; // CHECK: assert(const true // CHECK: [[x]] = copy [[array_lit]][2 of 3]; diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff index dfa541b1200d..618121ea6326 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff index 9ede3c5f7ac2..1788f58432b8 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff index dfa541b1200d..618121ea6326 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff index 9ede3c5f7ac2..1788f58432b8 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff @@ -7,8 +7,7 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: bool; scope 1 { debug x => _1; } @@ -20,11 +19,9 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Len(_3); -- _6 = Lt(copy _4, copy _5); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const 8_usize; -+ _6 = const true; +- _5 = Lt(copy _4, const 8_usize); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs index 2067aa3d709e..1bc2cb82a606 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.rs +++ b/tests/mir-opt/dataflow-const-prop/repeat.rs @@ -9,8 +9,9 @@ fn main() { // CHECK: [[array_lit:_.*]] = [const 42_u32; 8]; // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = PtrMetadata( // CHECK-NOT: {{_.*}} = Lt( - // CHECK: {{_.*}} = const 8_usize; + // CHECK: {{_.*}} = const 2_usize; // CHECK: {{_.*}} = const true; // CHECK: assert(const true diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff deleted file mode 100644 index e71992316dcf..000000000000 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `main` before DataflowConstProp -+ // MIR for `main` after DataflowConstProp - - fn main() -> () { - let mut _0: (); - let _1: u32; - let mut _2: &[u32]; - let mut _3: &[u32; 3]; - let _4: &[u32; 3]; - let _5: [u32; 3]; - let _6: usize; - let mut _7: usize; - let mut _8: bool; - let mut _10: &[u32]; - let _11: usize; - let mut _12: usize; - let mut _13: bool; - let mut _14: &[u32; 3]; - scope 1 { - debug local => _1; - let _9: u32; - scope 2 { - debug constant => _9; - } - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); - _14 = const main::promoted[0]; - _4 = copy _14; - _3 = copy _4; - _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); - StorageDead(_3); - StorageLive(_6); - _6 = const 1_usize; -- _7 = Len((*_2)); -- _8 = Lt(copy _6, copy _7); -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; - } - - bb1: { -- _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; - StorageDead(_6); - StorageDead(_4); - StorageDead(_2); - StorageLive(_9); - StorageLive(_10); - _10 = const main::SLICE; - StorageLive(_11); - _11 = const 1_usize; -- _12 = Len((*_10)); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable]; -+ _12 = const 3_usize; -+ _13 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable]; - } - - bb2: { -- _9 = copy (*_10)[_11]; -+ _9 = copy (*_10)[1 of 2]; - StorageDead(_11); - StorageDead(_10); - _0 = const (); - StorageDead(_9); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff deleted file mode 100644 index 26de85957689..000000000000 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `main` before DataflowConstProp -+ // MIR for `main` after DataflowConstProp - - fn main() -> () { - let mut _0: (); - let _1: u32; - let mut _2: &[u32]; - let mut _3: &[u32; 3]; - let _4: &[u32; 3]; - let _5: [u32; 3]; - let _6: usize; - let mut _7: usize; - let mut _8: bool; - let mut _10: &[u32]; - let _11: usize; - let mut _12: usize; - let mut _13: bool; - let mut _14: &[u32; 3]; - scope 1 { - debug local => _1; - let _9: u32; - scope 2 { - debug constant => _9; - } - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); - _14 = const main::promoted[0]; - _4 = copy _14; - _3 = copy _4; - _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); - StorageDead(_3); - StorageLive(_6); - _6 = const 1_usize; -- _7 = Len((*_2)); -- _8 = Lt(copy _6, copy _7); -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; - } - - bb1: { -- _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; - StorageDead(_6); - StorageDead(_4); - StorageDead(_2); - StorageLive(_9); - StorageLive(_10); - _10 = const main::SLICE; - StorageLive(_11); - _11 = const 1_usize; -- _12 = Len((*_10)); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue]; -+ _12 = const 3_usize; -+ _13 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue]; - } - - bb2: { -- _9 = copy (*_10)[_11]; -+ _9 = copy (*_10)[1 of 2]; - StorageDead(_11); - StorageDead(_10); - _0 = const (); - StorageDead(_9); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff deleted file mode 100644 index e71992316dcf..000000000000 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `main` before DataflowConstProp -+ // MIR for `main` after DataflowConstProp - - fn main() -> () { - let mut _0: (); - let _1: u32; - let mut _2: &[u32]; - let mut _3: &[u32; 3]; - let _4: &[u32; 3]; - let _5: [u32; 3]; - let _6: usize; - let mut _7: usize; - let mut _8: bool; - let mut _10: &[u32]; - let _11: usize; - let mut _12: usize; - let mut _13: bool; - let mut _14: &[u32; 3]; - scope 1 { - debug local => _1; - let _9: u32; - scope 2 { - debug constant => _9; - } - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); - _14 = const main::promoted[0]; - _4 = copy _14; - _3 = copy _4; - _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); - StorageDead(_3); - StorageLive(_6); - _6 = const 1_usize; -- _7 = Len((*_2)); -- _8 = Lt(copy _6, copy _7); -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; - } - - bb1: { -- _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; - StorageDead(_6); - StorageDead(_4); - StorageDead(_2); - StorageLive(_9); - StorageLive(_10); - _10 = const main::SLICE; - StorageLive(_11); - _11 = const 1_usize; -- _12 = Len((*_10)); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable]; -+ _12 = const 3_usize; -+ _13 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable]; - } - - bb2: { -- _9 = copy (*_10)[_11]; -+ _9 = copy (*_10)[1 of 2]; - StorageDead(_11); - StorageDead(_10); - _0 = const (); - StorageDead(_9); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff deleted file mode 100644 index 26de85957689..000000000000 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `main` before DataflowConstProp -+ // MIR for `main` after DataflowConstProp - - fn main() -> () { - let mut _0: (); - let _1: u32; - let mut _2: &[u32]; - let mut _3: &[u32; 3]; - let _4: &[u32; 3]; - let _5: [u32; 3]; - let _6: usize; - let mut _7: usize; - let mut _8: bool; - let mut _10: &[u32]; - let _11: usize; - let mut _12: usize; - let mut _13: bool; - let mut _14: &[u32; 3]; - scope 1 { - debug local => _1; - let _9: u32; - scope 2 { - debug constant => _9; - } - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); - _14 = const main::promoted[0]; - _4 = copy _14; - _3 = copy _4; - _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); - StorageDead(_3); - StorageLive(_6); - _6 = const 1_usize; -- _7 = Len((*_2)); -- _8 = Lt(copy _6, copy _7); -- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; - } - - bb1: { -- _1 = copy (*_2)[_6]; -+ _1 = copy (*_2)[1 of 2]; - StorageDead(_6); - StorageDead(_4); - StorageDead(_2); - StorageLive(_9); - StorageLive(_10); - _10 = const main::SLICE; - StorageLive(_11); - _11 = const 1_usize; -- _12 = Len((*_10)); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue]; -+ _12 = const 3_usize; -+ _13 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue]; - } - - bb2: { -- _9 = copy (*_10)[_11]; -+ _9 = copy (*_10)[1 of 2]; - StorageDead(_11); - StorageDead(_10); - _0 = const (); - StorageDead(_9); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs deleted file mode 100644 index e0e68f9fde54..000000000000 --- a/tests/mir-opt/dataflow-const-prop/slice_len.rs +++ /dev/null @@ -1,34 +0,0 @@ -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ test-mir-pass: DataflowConstProp -//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg -// EMIT_MIR_FOR_EACH_BIT_WIDTH - -// EMIT_MIR slice_len.main.DataflowConstProp.diff - -// CHECK-LABEL: fn main( -fn main() { - // CHECK: debug local => [[local:_.*]]; - // CHECK: debug constant => [[constant:_.*]]; - - // CHECK-NOT: {{_.*}} = Len( - // CHECK-NOT: {{_.*}} = Lt( - // CHECK-NOT: assert(move _ - // CHECK: {{_.*}} = const 3_usize; - // CHECK: {{_.*}} = const true; - // CHECK: assert(const true, - - // CHECK: [[local]] = copy (*{{_.*}})[1 of 2]; - let local = (&[1u32, 2, 3] as &[u32])[1]; - - // CHECK-NOT: {{_.*}} = Len( - // CHECK-NOT: {{_.*}} = Lt( - // CHECK-NOT: assert(move _ - const SLICE: &[u32] = &[1, 2, 3]; - // CHECK: {{_.*}} = const 3_usize; - // CHECK: {{_.*}} = const true; - // CHECK: assert(const true, - - // CHECK-NOT: [[constant]] = {{copy|move}} (*{{_.*}})[_ - // CHECK: [[constant]] = copy (*{{_.*}})[1 of 2]; - let constant = SLICE[1]; -} diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff index 3f052ee19fdf..183b4d2599f5 100644 --- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff @@ -53,7 +53,7 @@ StorageLive(_8); - _8 = copy _2; + _8 = const usize::MAX; - _9 = Len((*_1)); + _9 = PtrMetadata(copy _1); - _10 = Lt(copy _8, copy _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable]; + _10 = Lt(const usize::MAX, copy _9); @@ -72,7 +72,7 @@ StorageDead(_5); StorageLive(_11); _11 = const 0_usize; - _12 = Len((*_1)); + _12 = PtrMetadata(copy _1); - _13 = Lt(copy _11, copy _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable]; + _13 = Lt(const 0_usize, copy _12); diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff index 84b738c7804e..03e8aa3bd9b9 100644 --- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff @@ -53,7 +53,7 @@ StorageLive(_8); - _8 = copy _2; + _8 = const usize::MAX; - _9 = Len((*_1)); + _9 = PtrMetadata(copy _1); - _10 = Lt(copy _8, copy _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; + _10 = Lt(const usize::MAX, copy _9); @@ -72,7 +72,7 @@ StorageDead(_5); StorageLive(_11); _11 = const 0_usize; - _12 = Len((*_1)); + _12 = PtrMetadata(copy _1); - _13 = Lt(copy _11, copy _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue]; + _13 = Lt(const 0_usize, copy _12); diff --git a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff new file mode 100644 index 000000000000..4b077f580f10 --- /dev/null +++ b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff @@ -0,0 +1,72 @@ +- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN ++ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN + + fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] { + debug x => _1; + let mut _0: [i32; 3]; + let mut _2: i32; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + let mut _6: i32; + let _7: usize; + let mut _8: usize; + let mut _9: bool; + let mut _10: i32; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 42_usize; + _4 = PtrMetadata(copy _1); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _5 = Lt(const 42_usize, copy _4); ++ assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _2 = copy (*_1)[_3]; ++ _2 = copy (*_1)[42 of 43]; + StorageLive(_6); + StorageLive(_7); + _7 = const 13_usize; +- _8 = PtrMetadata(copy _1); +- _9 = Lt(copy _7, copy _8); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable]; ++ _8 = copy _4; ++ _9 = Lt(const 13_usize, copy _4); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _6 = copy (*_1)[_7]; ++ _6 = copy (*_1)[13 of 14]; + StorageLive(_10); + StorageLive(_11); + _11 = const 7_usize; +- _12 = PtrMetadata(copy _1); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind unreachable]; ++ _12 = copy _4; ++ _13 = Lt(const 7_usize, copy _4); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind unreachable]; + } + + bb3: { +- _10 = copy (*_1)[_11]; ++ _10 = copy (*_1)[7 of 8]; + _0 = [move _2, move _6, move _10]; + StorageDead(_10); + StorageDead(_6); + StorageDead(_2); + StorageDead(_11); + StorageDead(_7); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff new file mode 100644 index 000000000000..87e69d440069 --- /dev/null +++ b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff @@ -0,0 +1,72 @@ +- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN ++ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN + + fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] { + debug x => _1; + let mut _0: [i32; 3]; + let mut _2: i32; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + let mut _6: i32; + let _7: usize; + let mut _8: usize; + let mut _9: bool; + let mut _10: i32; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 42_usize; + _4 = PtrMetadata(copy _1); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _5 = Lt(const 42_usize, copy _4); ++ assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _2 = copy (*_1)[_3]; ++ _2 = copy (*_1)[42 of 43]; + StorageLive(_6); + StorageLive(_7); + _7 = const 13_usize; +- _8 = PtrMetadata(copy _1); +- _9 = Lt(copy _7, copy _8); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue]; ++ _8 = copy _4; ++ _9 = Lt(const 13_usize, copy _4); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _6 = copy (*_1)[_7]; ++ _6 = copy (*_1)[13 of 14]; + StorageLive(_10); + StorageLive(_11); + _11 = const 7_usize; +- _12 = PtrMetadata(copy _1); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind continue]; ++ _12 = copy _4; ++ _13 = Lt(const 7_usize, copy _4); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind continue]; + } + + bb3: { +- _10 = copy (*_1)[_11]; ++ _10 = copy (*_1)[7 of 8]; + _0 = [move _2, move _6, move _10]; + StorageDead(_10); + StorageDead(_6); + StorageDead(_2); + StorageDead(_11); + StorageDead(_7); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff index d4b22d05f6c7..7f44176b7568 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff @@ -10,13 +10,11 @@ let _5: (); let mut _6: T; let _7: usize; - let mut _8: usize; - let mut _9: bool; - let _10: (); - let mut _11: T; - let _12: usize; - let mut _13: usize; - let mut _14: bool; + let mut _8: bool; + let _9: (); + let mut _10: T; + let _11: usize; + let mut _12: bool; scope 1 { debug a => _3; } @@ -32,12 +30,10 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; -- _8 = Len(_3); -- _9 = Lt(copy _7, copy _8); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind unreachable]; -+ _8 = const N; -+ _9 = Lt(const 0_usize, const N); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable]; +- _8 = Lt(copy _7, const N); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 0_usize, const N); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable]; } bb1: { @@ -51,29 +47,27 @@ StorageDead(_6); StorageDead(_7); StorageDead(_5); + StorageLive(_9); StorageLive(_10); StorageLive(_11); - StorageLive(_12); - _12 = copy _2; -- _13 = Len(_3); -- _14 = Lt(copy _12, copy _13); -- assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind unreachable]; -+ _13 = const N; -+ _14 = Lt(copy _2, const N); -+ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable]; + _11 = copy _2; +- _12 = Lt(copy _11, const N); +- assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind unreachable]; ++ _12 = Lt(copy _2, const N); ++ assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable]; } bb3: { -- _11 = copy _3[_12]; -- _10 = opaque::(move _11) -> [return: bb4, unwind unreachable]; -+ _11 = copy _1; -+ _10 = opaque::(copy _1) -> [return: bb4, unwind unreachable]; +- _10 = copy _3[_11]; +- _9 = opaque::(move _10) -> [return: bb4, unwind unreachable]; ++ _10 = copy _1; ++ _9 = opaque::(copy _1) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_11); - StorageDead(_12); StorageDead(_10); + StorageDead(_11); + StorageDead(_9); _0 = const (); StorageDead(_3); return; diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff index 708c0f92e542..d34882d725f4 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff @@ -10,13 +10,11 @@ let _5: (); let mut _6: T; let _7: usize; - let mut _8: usize; - let mut _9: bool; - let _10: (); - let mut _11: T; - let _12: usize; - let mut _13: usize; - let mut _14: bool; + let mut _8: bool; + let _9: (); + let mut _10: T; + let _11: usize; + let mut _12: bool; scope 1 { debug a => _3; } @@ -32,12 +30,10 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; -- _8 = Len(_3); -- _9 = Lt(copy _7, copy _8); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind continue]; -+ _8 = const N; -+ _9 = Lt(const 0_usize, const N); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue]; +- _8 = Lt(copy _7, const N); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 0_usize, const N); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue]; } bb1: { @@ -51,29 +47,27 @@ StorageDead(_6); StorageDead(_7); StorageDead(_5); + StorageLive(_9); StorageLive(_10); StorageLive(_11); - StorageLive(_12); - _12 = copy _2; -- _13 = Len(_3); -- _14 = Lt(copy _12, copy _13); -- assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind continue]; -+ _13 = const N; -+ _14 = Lt(copy _2, const N); -+ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue]; + _11 = copy _2; +- _12 = Lt(copy _11, const N); +- assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind continue]; ++ _12 = Lt(copy _2, const N); ++ assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue]; } bb3: { -- _11 = copy _3[_12]; -- _10 = opaque::(move _11) -> [return: bb4, unwind continue]; -+ _11 = copy _1; -+ _10 = opaque::(copy _1) -> [return: bb4, unwind continue]; +- _10 = copy _3[_11]; +- _9 = opaque::(move _10) -> [return: bb4, unwind continue]; ++ _10 = copy _1; ++ _9 = opaque::(copy _1) -> [return: bb4, unwind continue]; } bb4: { - StorageDead(_11); - StorageDead(_12); StorageDead(_10); + StorageDead(_11); + StorageDead(_9); _0 = const (); StorageDead(_3); return; diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 10d1ccfdece0..c895a5792595 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -835,6 +835,25 @@ fn array_len(x: &mut [i32; 42]) -> usize { std::intrinsics::ptr_metadata(x) } +// Check that we only load the length once, rather than all 3 times. +fn dedup_multiple_bounds_checks_lengths(x: &[i32]) -> [i32; 3] { + // CHECK-LABEL: fn dedup_multiple_bounds_checks_lengths + // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); + // CHECK: Lt(const 42_usize, copy [[LEN]]); + // CHECK: assert{{.+}}copy [[LEN]] + // CHECK: [[A:_.+]] = copy (*_1)[42 of 43]; + // CHECK-NOT: PtrMetadata + // CHECK: Lt(const 13_usize, copy [[LEN]]); + // CHECK: assert{{.+}}copy [[LEN]] + // CHECK: [[B:_.+]] = copy (*_1)[13 of 14]; + // CHECK-NOT: PtrMetadata + // CHECK: Lt(const 7_usize, copy [[LEN]]); + // CHECK: assert{{.+}}copy [[LEN]] + // CHECK: [[C:_.+]] = copy (*_1)[7 of 8]; + // CHECK: _0 = [move [[A]], move [[B]], move [[C]]] + [x[42], x[13], x[7]] +} + #[custom_mir(dialect = "runtime")] fn generic_cast_metadata(ps: *const [T], pa: *const A, pb: *const B) { // CHECK-LABEL: fn generic_cast_metadata @@ -1109,6 +1128,7 @@ enum Never {} // EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff // EMIT_MIR gvn.manual_slice_mut_len.GVN.diff // EMIT_MIR gvn.array_len.GVN.diff +// EMIT_MIR gvn.dedup_multiple_bounds_checks_lengths.GVN.diff // EMIT_MIR gvn.generic_cast_metadata.GVN.diff // EMIT_MIR gvn.cast_pointer_eq.GVN.diff // EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff index 6b6152c1117e..1b305e746f5e 100644 --- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff @@ -10,62 +10,60 @@ let mut _6: &i32; let _7: &i32; let _8: usize; - let mut _9: usize; - let mut _10: bool; - let mut _12: *const dyn std::marker::Send; - let _13: &dyn std::marker::Send; - let mut _14: &i32; - let _15: &i32; - let _16: usize; - let mut _17: usize; + let mut _9: bool; + let mut _11: *const dyn std::marker::Send; + let _12: &dyn std::marker::Send; + let mut _13: &i32; + let _14: &i32; + let _15: usize; + let mut _16: bool; + let _17: (); let mut _18: bool; - let _19: (); - let mut _20: bool; + let mut _19: *const dyn std::marker::Send; + let mut _20: *const dyn std::marker::Send; let mut _21: *const dyn std::marker::Send; - let mut _22: *const dyn std::marker::Send; - let mut _23: *const dyn std::marker::Send; - let _24: (); - let mut _25: bool; + let _22: (); + let mut _23: bool; + let mut _24: *const dyn std::marker::Send; + let mut _25: *const dyn std::marker::Send; let mut _26: *const dyn std::marker::Send; - let mut _27: *const dyn std::marker::Send; - let mut _28: *const dyn std::marker::Send; - let _29: (); - let mut _30: bool; + let _27: (); + let mut _28: bool; + let mut _29: *const dyn std::marker::Send; + let mut _30: *const dyn std::marker::Send; let mut _31: *const dyn std::marker::Send; - let mut _32: *const dyn std::marker::Send; - let mut _33: *const dyn std::marker::Send; - let _34: (); - let mut _35: bool; + let _32: (); + let mut _33: bool; + let mut _34: *const dyn std::marker::Send; + let mut _35: *const dyn std::marker::Send; let mut _36: *const dyn std::marker::Send; - let mut _37: *const dyn std::marker::Send; - let mut _38: *const dyn std::marker::Send; - let _39: (); - let mut _40: bool; + let _37: (); + let mut _38: bool; + let mut _39: *const dyn std::marker::Send; + let mut _40: *const dyn std::marker::Send; let mut _41: *const dyn std::marker::Send; - let mut _42: *const dyn std::marker::Send; - let mut _43: *const dyn std::marker::Send; - let _44: (); - let mut _45: bool; + let _42: (); + let mut _43: bool; + let mut _44: *const dyn std::marker::Send; + let mut _45: *const dyn std::marker::Send; let mut _46: *const dyn std::marker::Send; - let mut _47: *const dyn std::marker::Send; - let mut _48: *const dyn std::marker::Send; - let mut _49: &[i32; 2]; + let mut _47: &[i32; 2]; scope 1 { debug slice => _1; let _3: *const dyn std::marker::Send; scope 2 { debug a => _3; - let _11: *const dyn std::marker::Send; + let _10: *const dyn std::marker::Send; scope 3 { - debug b => _11; + debug b => _10; } } } bb0: { StorageLive(_1); - _49 = const wide_ptr_same_provenance::promoted[0]; - _1 = &(*_49); + _47 = const wide_ptr_same_provenance::promoted[0]; + _1 = &(*_47); StorageLive(_3); - StorageLive(_4); + nop; @@ -74,11 +72,9 @@ StorageLive(_7); StorageLive(_8); _8 = const 0_usize; -- _9 = Len((*_1)); -- _10 = Lt(copy _8, copy _9); -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind unreachable]; -+ _9 = const 2_usize; -+ _10 = const true; +- _9 = Lt(copy _8, const 2_usize); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind unreachable]; ++ _9 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind unreachable]; } @@ -95,170 +91,168 @@ + nop; StorageDead(_7); StorageDead(_5); - StorageLive(_11); -- StorageLive(_12); + StorageLive(_10); +- StorageLive(_11); + nop; + StorageLive(_12); StorageLive(_13); StorageLive(_14); StorageLive(_15); - StorageLive(_16); - _16 = const 1_usize; -- _17 = Len((*_1)); -- _18 = Lt(copy _16, copy _17); -- assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind unreachable]; -+ _17 = const 2_usize; -+ _18 = const true; + _15 = const 1_usize; +- _16 = Lt(copy _15, const 2_usize); +- assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind unreachable]; ++ _16 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind unreachable]; } bb2: { -- _15 = &(*_1)[_16]; -+ _15 = &(*_1)[1 of 2]; - _14 = &(*_15); - _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); - StorageDead(_14); - _12 = &raw const (*_13); -- _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -- StorageDead(_12); -+ _11 = copy _12; -+ nop; - StorageDead(_15); +- _14 = &(*_1)[_15]; ++ _14 = &(*_1)[1 of 2]; + _13 = &(*_14); + _12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); StorageDead(_13); + _11 = &raw const (*_12); +- _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); +- StorageDead(_11); ++ _10 = copy _11; ++ nop; + StorageDead(_14); + StorageDead(_12); + StorageLive(_17); + StorageLive(_18); StorageLive(_19); +- _19 = copy _3; ++ _19 = copy _4; StorageLive(_20); StorageLive(_21); -- _21 = copy _3; -+ _21 = copy _4; - StorageLive(_22); - StorageLive(_23); -- _23 = copy _11; -- _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _23 = copy _12; -+ _22 = copy _12; - StorageDead(_23); -- _20 = Eq(move _21, move _22); -+ _20 = Eq(copy _4, copy _12); - StorageDead(_22); +- _21 = copy _10; +- _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _21 = copy _11; ++ _20 = copy _11; StorageDead(_21); - _19 = opaque::(move _20) -> [return: bb3, unwind unreachable]; +- _18 = Eq(move _19, move _20); ++ _18 = Eq(copy _4, copy _11); + StorageDead(_20); + StorageDead(_19); + _17 = opaque::(move _18) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_20); - StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + StorageLive(_22); + StorageLive(_23); StorageLive(_24); +- _24 = copy _3; ++ _24 = copy _4; StorageLive(_25); StorageLive(_26); -- _26 = copy _3; -+ _26 = copy _4; - StorageLive(_27); - StorageLive(_28); -- _28 = copy _11; -- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _28 = copy _12; -+ _27 = copy _12; - StorageDead(_28); -- _25 = Ne(move _26, move _27); -+ _25 = Ne(copy _4, copy _12); - StorageDead(_27); +- _26 = copy _10; +- _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _26 = copy _11; ++ _25 = copy _11; StorageDead(_26); - _24 = opaque::(move _25) -> [return: bb4, unwind unreachable]; +- _23 = Ne(move _24, move _25); ++ _23 = Ne(copy _4, copy _11); + StorageDead(_25); + StorageDead(_24); + _22 = opaque::(move _23) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_25); - StorageDead(_24); + StorageDead(_23); + StorageDead(_22); + StorageLive(_27); + StorageLive(_28); StorageLive(_29); +- _29 = copy _3; ++ _29 = copy _4; StorageLive(_30); StorageLive(_31); -- _31 = copy _3; -+ _31 = copy _4; - StorageLive(_32); - StorageLive(_33); -- _33 = copy _11; -- _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _33 = copy _12; -+ _32 = copy _12; - StorageDead(_33); -- _30 = Lt(move _31, move _32); -+ _30 = Lt(copy _4, copy _12); - StorageDead(_32); +- _31 = copy _10; +- _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _31 = copy _11; ++ _30 = copy _11; StorageDead(_31); - _29 = opaque::(move _30) -> [return: bb5, unwind unreachable]; +- _28 = Lt(move _29, move _30); ++ _28 = Lt(copy _4, copy _11); + StorageDead(_30); + StorageDead(_29); + _27 = opaque::(move _28) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_30); - StorageDead(_29); + StorageDead(_28); + StorageDead(_27); + StorageLive(_32); + StorageLive(_33); StorageLive(_34); +- _34 = copy _3; ++ _34 = copy _4; StorageLive(_35); StorageLive(_36); -- _36 = copy _3; -+ _36 = copy _4; - StorageLive(_37); - StorageLive(_38); -- _38 = copy _11; -- _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _38 = copy _12; -+ _37 = copy _12; - StorageDead(_38); -- _35 = Le(move _36, move _37); -+ _35 = Le(copy _4, copy _12); - StorageDead(_37); +- _36 = copy _10; +- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _36 = copy _11; ++ _35 = copy _11; StorageDead(_36); - _34 = opaque::(move _35) -> [return: bb6, unwind unreachable]; +- _33 = Le(move _34, move _35); ++ _33 = Le(copy _4, copy _11); + StorageDead(_35); + StorageDead(_34); + _32 = opaque::(move _33) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_35); - StorageDead(_34); + StorageDead(_33); + StorageDead(_32); + StorageLive(_37); + StorageLive(_38); StorageLive(_39); +- _39 = copy _3; ++ _39 = copy _4; StorageLive(_40); StorageLive(_41); -- _41 = copy _3; -+ _41 = copy _4; - StorageLive(_42); - StorageLive(_43); -- _43 = copy _11; -- _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _43 = copy _12; -+ _42 = copy _12; - StorageDead(_43); -- _40 = Gt(move _41, move _42); -+ _40 = Gt(copy _4, copy _12); - StorageDead(_42); +- _41 = copy _10; +- _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _41 = copy _11; ++ _40 = copy _11; StorageDead(_41); - _39 = opaque::(move _40) -> [return: bb7, unwind unreachable]; +- _38 = Gt(move _39, move _40); ++ _38 = Gt(copy _4, copy _11); + StorageDead(_40); + StorageDead(_39); + _37 = opaque::(move _38) -> [return: bb7, unwind unreachable]; } bb7: { - StorageDead(_40); - StorageDead(_39); + StorageDead(_38); + StorageDead(_37); + StorageLive(_42); + StorageLive(_43); StorageLive(_44); +- _44 = copy _3; ++ _44 = copy _4; StorageLive(_45); StorageLive(_46); -- _46 = copy _3; -+ _46 = copy _4; - StorageLive(_47); - StorageLive(_48); -- _48 = copy _11; -- _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _48 = copy _12; -+ _47 = copy _12; - StorageDead(_48); -- _45 = Ge(move _46, move _47); -+ _45 = Ge(copy _4, copy _12); - StorageDead(_47); +- _46 = copy _10; +- _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _46 = copy _11; ++ _45 = copy _11; StorageDead(_46); - _44 = opaque::(move _45) -> [return: bb8, unwind unreachable]; +- _43 = Ge(move _44, move _45); ++ _43 = Ge(copy _4, copy _11); + StorageDead(_45); + StorageDead(_44); + _42 = opaque::(move _43) -> [return: bb8, unwind unreachable]; } bb8: { - StorageDead(_45); - StorageDead(_44); + StorageDead(_43); + StorageDead(_42); _0 = const (); - StorageDead(_16); - StorageDead(_11); + StorageDead(_15); + StorageDead(_10); StorageDead(_8); StorageDead(_3); StorageDead(_1); diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff index 093c1ec6ce37..e418ecf25bd4 100644 --- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff @@ -10,62 +10,60 @@ let mut _6: &i32; let _7: &i32; let _8: usize; - let mut _9: usize; - let mut _10: bool; - let mut _12: *const dyn std::marker::Send; - let _13: &dyn std::marker::Send; - let mut _14: &i32; - let _15: &i32; - let _16: usize; - let mut _17: usize; + let mut _9: bool; + let mut _11: *const dyn std::marker::Send; + let _12: &dyn std::marker::Send; + let mut _13: &i32; + let _14: &i32; + let _15: usize; + let mut _16: bool; + let _17: (); let mut _18: bool; - let _19: (); - let mut _20: bool; + let mut _19: *const dyn std::marker::Send; + let mut _20: *const dyn std::marker::Send; let mut _21: *const dyn std::marker::Send; - let mut _22: *const dyn std::marker::Send; - let mut _23: *const dyn std::marker::Send; - let _24: (); - let mut _25: bool; + let _22: (); + let mut _23: bool; + let mut _24: *const dyn std::marker::Send; + let mut _25: *const dyn std::marker::Send; let mut _26: *const dyn std::marker::Send; - let mut _27: *const dyn std::marker::Send; - let mut _28: *const dyn std::marker::Send; - let _29: (); - let mut _30: bool; + let _27: (); + let mut _28: bool; + let mut _29: *const dyn std::marker::Send; + let mut _30: *const dyn std::marker::Send; let mut _31: *const dyn std::marker::Send; - let mut _32: *const dyn std::marker::Send; - let mut _33: *const dyn std::marker::Send; - let _34: (); - let mut _35: bool; + let _32: (); + let mut _33: bool; + let mut _34: *const dyn std::marker::Send; + let mut _35: *const dyn std::marker::Send; let mut _36: *const dyn std::marker::Send; - let mut _37: *const dyn std::marker::Send; - let mut _38: *const dyn std::marker::Send; - let _39: (); - let mut _40: bool; + let _37: (); + let mut _38: bool; + let mut _39: *const dyn std::marker::Send; + let mut _40: *const dyn std::marker::Send; let mut _41: *const dyn std::marker::Send; - let mut _42: *const dyn std::marker::Send; - let mut _43: *const dyn std::marker::Send; - let _44: (); - let mut _45: bool; + let _42: (); + let mut _43: bool; + let mut _44: *const dyn std::marker::Send; + let mut _45: *const dyn std::marker::Send; let mut _46: *const dyn std::marker::Send; - let mut _47: *const dyn std::marker::Send; - let mut _48: *const dyn std::marker::Send; - let mut _49: &[i32; 2]; + let mut _47: &[i32; 2]; scope 1 { debug slice => _1; let _3: *const dyn std::marker::Send; scope 2 { debug a => _3; - let _11: *const dyn std::marker::Send; + let _10: *const dyn std::marker::Send; scope 3 { - debug b => _11; + debug b => _10; } } } bb0: { StorageLive(_1); - _49 = const wide_ptr_same_provenance::promoted[0]; - _1 = &(*_49); + _47 = const wide_ptr_same_provenance::promoted[0]; + _1 = &(*_47); StorageLive(_3); - StorageLive(_4); + nop; @@ -74,11 +72,9 @@ StorageLive(_7); StorageLive(_8); _8 = const 0_usize; -- _9 = Len((*_1)); -- _10 = Lt(copy _8, copy _9); -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind continue]; -+ _9 = const 2_usize; -+ _10 = const true; +- _9 = Lt(copy _8, const 2_usize); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind continue]; ++ _9 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind continue]; } @@ -95,170 +91,168 @@ + nop; StorageDead(_7); StorageDead(_5); - StorageLive(_11); -- StorageLive(_12); + StorageLive(_10); +- StorageLive(_11); + nop; + StorageLive(_12); StorageLive(_13); StorageLive(_14); StorageLive(_15); - StorageLive(_16); - _16 = const 1_usize; -- _17 = Len((*_1)); -- _18 = Lt(copy _16, copy _17); -- assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind continue]; -+ _17 = const 2_usize; -+ _18 = const true; + _15 = const 1_usize; +- _16 = Lt(copy _15, const 2_usize); +- assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind continue]; ++ _16 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind continue]; } bb2: { -- _15 = &(*_1)[_16]; -+ _15 = &(*_1)[1 of 2]; - _14 = &(*_15); - _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); - StorageDead(_14); - _12 = &raw const (*_13); -- _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -- StorageDead(_12); -+ _11 = copy _12; -+ nop; - StorageDead(_15); +- _14 = &(*_1)[_15]; ++ _14 = &(*_1)[1 of 2]; + _13 = &(*_14); + _12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); StorageDead(_13); + _11 = &raw const (*_12); +- _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); +- StorageDead(_11); ++ _10 = copy _11; ++ nop; + StorageDead(_14); + StorageDead(_12); + StorageLive(_17); + StorageLive(_18); StorageLive(_19); +- _19 = copy _3; ++ _19 = copy _4; StorageLive(_20); StorageLive(_21); -- _21 = copy _3; -+ _21 = copy _4; - StorageLive(_22); - StorageLive(_23); -- _23 = copy _11; -- _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _23 = copy _12; -+ _22 = copy _12; - StorageDead(_23); -- _20 = Eq(move _21, move _22); -+ _20 = Eq(copy _4, copy _12); - StorageDead(_22); +- _21 = copy _10; +- _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _21 = copy _11; ++ _20 = copy _11; StorageDead(_21); - _19 = opaque::(move _20) -> [return: bb3, unwind continue]; +- _18 = Eq(move _19, move _20); ++ _18 = Eq(copy _4, copy _11); + StorageDead(_20); + StorageDead(_19); + _17 = opaque::(move _18) -> [return: bb3, unwind continue]; } bb3: { - StorageDead(_20); - StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + StorageLive(_22); + StorageLive(_23); StorageLive(_24); +- _24 = copy _3; ++ _24 = copy _4; StorageLive(_25); StorageLive(_26); -- _26 = copy _3; -+ _26 = copy _4; - StorageLive(_27); - StorageLive(_28); -- _28 = copy _11; -- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _28 = copy _12; -+ _27 = copy _12; - StorageDead(_28); -- _25 = Ne(move _26, move _27); -+ _25 = Ne(copy _4, copy _12); - StorageDead(_27); +- _26 = copy _10; +- _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _26 = copy _11; ++ _25 = copy _11; StorageDead(_26); - _24 = opaque::(move _25) -> [return: bb4, unwind continue]; +- _23 = Ne(move _24, move _25); ++ _23 = Ne(copy _4, copy _11); + StorageDead(_25); + StorageDead(_24); + _22 = opaque::(move _23) -> [return: bb4, unwind continue]; } bb4: { - StorageDead(_25); - StorageDead(_24); + StorageDead(_23); + StorageDead(_22); + StorageLive(_27); + StorageLive(_28); StorageLive(_29); +- _29 = copy _3; ++ _29 = copy _4; StorageLive(_30); StorageLive(_31); -- _31 = copy _3; -+ _31 = copy _4; - StorageLive(_32); - StorageLive(_33); -- _33 = copy _11; -- _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _33 = copy _12; -+ _32 = copy _12; - StorageDead(_33); -- _30 = Lt(move _31, move _32); -+ _30 = Lt(copy _4, copy _12); - StorageDead(_32); +- _31 = copy _10; +- _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _31 = copy _11; ++ _30 = copy _11; StorageDead(_31); - _29 = opaque::(move _30) -> [return: bb5, unwind continue]; +- _28 = Lt(move _29, move _30); ++ _28 = Lt(copy _4, copy _11); + StorageDead(_30); + StorageDead(_29); + _27 = opaque::(move _28) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_30); - StorageDead(_29); + StorageDead(_28); + StorageDead(_27); + StorageLive(_32); + StorageLive(_33); StorageLive(_34); +- _34 = copy _3; ++ _34 = copy _4; StorageLive(_35); StorageLive(_36); -- _36 = copy _3; -+ _36 = copy _4; - StorageLive(_37); - StorageLive(_38); -- _38 = copy _11; -- _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _38 = copy _12; -+ _37 = copy _12; - StorageDead(_38); -- _35 = Le(move _36, move _37); -+ _35 = Le(copy _4, copy _12); - StorageDead(_37); +- _36 = copy _10; +- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _36 = copy _11; ++ _35 = copy _11; StorageDead(_36); - _34 = opaque::(move _35) -> [return: bb6, unwind continue]; +- _33 = Le(move _34, move _35); ++ _33 = Le(copy _4, copy _11); + StorageDead(_35); + StorageDead(_34); + _32 = opaque::(move _33) -> [return: bb6, unwind continue]; } bb6: { - StorageDead(_35); - StorageDead(_34); + StorageDead(_33); + StorageDead(_32); + StorageLive(_37); + StorageLive(_38); StorageLive(_39); +- _39 = copy _3; ++ _39 = copy _4; StorageLive(_40); StorageLive(_41); -- _41 = copy _3; -+ _41 = copy _4; - StorageLive(_42); - StorageLive(_43); -- _43 = copy _11; -- _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _43 = copy _12; -+ _42 = copy _12; - StorageDead(_43); -- _40 = Gt(move _41, move _42); -+ _40 = Gt(copy _4, copy _12); - StorageDead(_42); +- _41 = copy _10; +- _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _41 = copy _11; ++ _40 = copy _11; StorageDead(_41); - _39 = opaque::(move _40) -> [return: bb7, unwind continue]; +- _38 = Gt(move _39, move _40); ++ _38 = Gt(copy _4, copy _11); + StorageDead(_40); + StorageDead(_39); + _37 = opaque::(move _38) -> [return: bb7, unwind continue]; } bb7: { - StorageDead(_40); - StorageDead(_39); + StorageDead(_38); + StorageDead(_37); + StorageLive(_42); + StorageLive(_43); StorageLive(_44); +- _44 = copy _3; ++ _44 = copy _4; StorageLive(_45); StorageLive(_46); -- _46 = copy _3; -+ _46 = copy _4; - StorageLive(_47); - StorageLive(_48); -- _48 = copy _11; -- _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _48 = copy _12; -+ _47 = copy _12; - StorageDead(_48); -- _45 = Ge(move _46, move _47); -+ _45 = Ge(copy _4, copy _12); - StorageDead(_47); +- _46 = copy _10; +- _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _46 = copy _11; ++ _45 = copy _11; StorageDead(_46); - _44 = opaque::(move _45) -> [return: bb8, unwind continue]; +- _43 = Ge(move _44, move _45); ++ _43 = Ge(copy _4, copy _11); + StorageDead(_45); + StorageDead(_44); + _42 = opaque::(move _43) -> [return: bb8, unwind continue]; } bb8: { - StorageDead(_45); - StorageDead(_44); + StorageDead(_43); + StorageDead(_42); _0 = const (); - StorageDead(_16); - StorageDead(_11); + StorageDead(_15); + StorageDead(_10); StorageDead(_8); StorageDead(_3); StorageDead(_1); diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff deleted file mode 100644 index f39df7ffca0f..000000000000 --- a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `norm2` before InstSimplify-after-simplifycfg -+ // MIR for `norm2` after InstSimplify-after-simplifycfg - - fn norm2(_1: [f32; 2]) -> f32 { - debug x => _1; - let mut _0: f32; - let _2: f32; - let _3: usize; - let mut _4: usize; - let mut _5: bool; - let _7: usize; - let mut _8: usize; - let mut _9: bool; - let mut _10: f32; - let mut _11: f32; - let mut _12: f32; - let mut _13: f32; - let mut _14: f32; - let mut _15: f32; - scope 1 { - debug a => _2; - let _6: f32; - scope 2 { - debug b => _6; - } - } - - bb0: { - StorageLive(_2); - StorageLive(_3); - _3 = const 0_usize; -- _4 = Len(_1); -+ _4 = const 2_usize; - _5 = Lt(copy _3, copy _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; - } - - bb1: { - _2 = copy _1[_3]; - StorageDead(_3); - StorageLive(_6); - StorageLive(_7); - _7 = const 1_usize; -- _8 = Len(_1); -+ _8 = const 2_usize; - _9 = Lt(copy _7, copy _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable]; - } - - bb2: { - _6 = copy _1[_7]; - StorageDead(_7); - StorageLive(_10); - StorageLive(_11); - _11 = copy _2; - StorageLive(_12); - _12 = copy _2; - _10 = Mul(move _11, move _12); - StorageDead(_12); - StorageDead(_11); - StorageLive(_13); - StorageLive(_14); - _14 = copy _6; - StorageLive(_15); - _15 = copy _6; - _13 = Mul(move _14, move _15); - StorageDead(_15); - StorageDead(_14); - _0 = Add(move _10, move _13); - StorageDead(_13); - StorageDead(_10); - StorageDead(_6); - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff deleted file mode 100644 index 0e7d5653c682..000000000000 --- a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `norm2` before InstSimplify-after-simplifycfg -+ // MIR for `norm2` after InstSimplify-after-simplifycfg - - fn norm2(_1: [f32; 2]) -> f32 { - debug x => _1; - let mut _0: f32; - let _2: f32; - let _3: usize; - let mut _4: usize; - let mut _5: bool; - let _7: usize; - let mut _8: usize; - let mut _9: bool; - let mut _10: f32; - let mut _11: f32; - let mut _12: f32; - let mut _13: f32; - let mut _14: f32; - let mut _15: f32; - scope 1 { - debug a => _2; - let _6: f32; - scope 2 { - debug b => _6; - } - } - - bb0: { - StorageLive(_2); - StorageLive(_3); - _3 = const 0_usize; -- _4 = Len(_1); -+ _4 = const 2_usize; - _5 = Lt(copy _3, copy _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; - } - - bb1: { - _2 = copy _1[_3]; - StorageDead(_3); - StorageLive(_6); - StorageLive(_7); - _7 = const 1_usize; -- _8 = Len(_1); -+ _8 = const 2_usize; - _9 = Lt(copy _7, copy _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue]; - } - - bb2: { - _6 = copy _1[_7]; - StorageDead(_7); - StorageLive(_10); - StorageLive(_11); - _11 = copy _2; - StorageLive(_12); - _12 = copy _2; - _10 = Mul(move _11, move _12); - StorageDead(_12); - StorageDead(_11); - StorageLive(_13); - StorageLive(_14); - _14 = copy _6; - StorageLive(_15); - _15 = copy _6; - _13 = Mul(move _14, move _15); - StorageDead(_15); - StorageDead(_14); - _0 = Add(move _10, move _13); - StorageDead(_13); - StorageDead(_10); - StorageDead(_6); - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/instsimplify/combine_array_len.rs b/tests/mir-opt/instsimplify/combine_array_len.rs deleted file mode 100644 index 91f43f75689d..000000000000 --- a/tests/mir-opt/instsimplify/combine_array_len.rs +++ /dev/null @@ -1,15 +0,0 @@ -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ test-mir-pass: InstSimplify-after-simplifycfg - -// EMIT_MIR combine_array_len.norm2.InstSimplify-after-simplifycfg.diff -fn norm2(x: [f32; 2]) -> f32 { - // CHECK-LABEL: fn norm2( - // CHECK-NOT: Len( - let a = x[0]; - let b = x[1]; - a * a + b * b -} - -fn main() { - assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0); -} diff --git a/tests/mir-opt/issue_72181.foo.built.after.mir b/tests/mir-opt/issue_72181.foo.built.after.mir index 314cf8b367f5..7593b7954325 100644 --- a/tests/mir-opt/issue_72181.foo.built.after.mir +++ b/tests/mir-opt/issue_72181.foo.built.after.mir @@ -4,15 +4,14 @@ fn foo(_1: [(Never, u32); 1]) -> u32 { debug xs => _1; let mut _0: u32; let _2: usize; - let mut _3: usize; - let mut _4: bool; + let mut _3: bool; bb0: { StorageLive(_2); _2 = const 0_usize; - _3 = Len(_1); - _4 = Lt(copy _2, copy _3); - assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind: bb2]; + FakeRead(ForIndex, _1); + _3 = Lt(copy _2, const 1_usize); + assert(move _3, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _2) -> [success: bb1, unwind: bb2]; } bb1: { diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir index aade84a6dd2e..9f3803f5407f 100644 --- a/tests/mir-opt/issue_72181.main.built.after.mir +++ b/tests/mir-opt/issue_72181.main.built.after.mir @@ -7,8 +7,7 @@ fn main() -> () { let mut _4: Foo; let mut _5: u64; let _6: usize; - let mut _7: usize; - let mut _8: bool; + let mut _7: bool; scope 1 { let _2: [Foo; 2]; scope 2 { @@ -38,9 +37,9 @@ fn main() -> () { StorageLive(_5); StorageLive(_6); _6 = const 0_usize; - _7 = Len(_2); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb3, unwind: bb5]; + FakeRead(ForIndex, _2); + _7 = Lt(copy _6, const 2_usize); + assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb3, unwind: bb5]; } bb2: { diff --git a/tests/mir-opt/issue_91633.foo.built.after.mir b/tests/mir-opt/issue_91633.foo.built.after.mir index 50fdf08375a0..53f48350596e 100644 --- a/tests/mir-opt/issue_91633.foo.built.after.mir +++ b/tests/mir-opt/issue_91633.foo.built.after.mir @@ -6,8 +6,9 @@ fn foo(_1: Box<[T]>) -> T { let _2: T; let mut _3: &T; let _4: usize; - let mut _5: usize; - let mut _6: bool; + let mut _5: *const [T]; + let mut _6: usize; + let mut _7: bool; scope 1 { debug f => _2; } @@ -17,9 +18,10 @@ fn foo(_1: Box<[T]>) -> T { StorageLive(_3); StorageLive(_4); _4 = const 0_usize; - _5 = Len((*_1)); - _6 = Lt(copy _4, copy _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb5]; + _5 = &raw const (fake) (*_1); + _6 = PtrMetadata(move _5); + _7 = Lt(copy _4, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb5]; } bb1: { diff --git a/tests/mir-opt/issue_91633.fun.built.after.mir b/tests/mir-opt/issue_91633.fun.built.after.mir index 5b41b376719b..d2fc438d3e81 100644 --- a/tests/mir-opt/issue_91633.fun.built.after.mir +++ b/tests/mir-opt/issue_91633.fun.built.after.mir @@ -15,7 +15,7 @@ fn fun(_1: &[T]) -> &T { StorageLive(_2); StorageLive(_3); _3 = const 0_usize; - _4 = Len((*_1)); + _4 = PtrMetadata(copy _1); _5 = Lt(copy _3, copy _4); assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb2]; } diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff index f052c8f63dca..98c5e868046b 100644 --- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff @@ -11,16 +11,14 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: usize; - let mut _10: bool; + let mut _9: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; -- StorageLive(_5); -+ nop; + StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -40,16 +38,13 @@ } bb2: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Len((*_2)); -- _10 = Lt(copy _8, copy _9); -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable]; -+ _9 = const N; -+ _10 = copy _3; +- _9 = Lt(copy _8, const N); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind unreachable]; ++ _9 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind unreachable]; } @@ -61,8 +56,7 @@ } bb4: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); _0 = const 42_u8; goto -> bb5; diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff index 3299e3004317..72c731378699 100644 --- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff @@ -11,16 +11,14 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: usize; - let mut _10: bool; + let mut _9: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; -- StorageLive(_5); -+ nop; + StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -40,16 +38,13 @@ } bb2: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Len((*_2)); -- _10 = Lt(copy _8, copy _9); -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; -+ _9 = const N; -+ _10 = copy _3; +- _9 = Lt(copy _8, const N); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind continue]; ++ _9 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind continue]; } @@ -61,8 +56,7 @@ } bb4: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); _0 = const 42_u8; goto -> bb5; diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff index 329eb80b3c4f..9ffaf44c02bd 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff @@ -11,19 +11,16 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: usize; - let mut _10: bool; - let _11: usize; - let mut _12: usize; - let mut _13: bool; + let mut _9: bool; + let _10: usize; + let mut _11: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; -- StorageLive(_5); -+ nop; + StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -43,16 +40,13 @@ } bb2: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Len((*_2)); -- _10 = Lt(copy _8, copy _9); -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable]; -+ _9 = const N; -+ _10 = copy _3; +- _9 = Lt(copy _8, const N); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind unreachable]; ++ _9 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind unreachable]; } @@ -64,23 +58,20 @@ } bb4: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); - StorageLive(_11); - _11 = const 0_usize; -- _12 = Len((*_2)); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable]; -+ _12 = const N; -+ _13 = Lt(const 0_usize, const N); -+ assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable]; + StorageLive(_10); + _10 = const 0_usize; +- _11 = Lt(copy _10, const N); +- assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, copy _10) -> [success: bb5, unwind unreachable]; ++ _11 = Lt(const 0_usize, const N); ++ assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable]; } bb5: { -- (*_2)[_11] = const 42_u8; +- (*_2)[_10] = const 42_u8; + (*_2)[0 of 1] = const 42_u8; - StorageDead(_11); + StorageDead(_10); _0 = const 42_u8; goto -> bb6; } diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff index ab007e133ecc..08008e463357 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff @@ -11,19 +11,16 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: usize; - let mut _10: bool; - let _11: usize; - let mut _12: usize; - let mut _13: bool; + let mut _9: bool; + let _10: usize; + let mut _11: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; -- StorageLive(_5); -+ nop; + StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -43,16 +40,13 @@ } bb2: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Len((*_2)); -- _10 = Lt(copy _8, copy _9); -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; -+ _9 = const N; -+ _10 = copy _3; +- _9 = Lt(copy _8, const N); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind continue]; ++ _9 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind continue]; } @@ -64,23 +58,20 @@ } bb4: { -- StorageDead(_5); -+ nop; + StorageDead(_5); StorageDead(_4); - StorageLive(_11); - _11 = const 0_usize; -- _12 = Len((*_2)); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue]; -+ _12 = const N; -+ _13 = Lt(const 0_usize, const N); -+ assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue]; + StorageLive(_10); + _10 = const 0_usize; +- _11 = Lt(copy _10, const N); +- assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, copy _10) -> [success: bb5, unwind continue]; ++ _11 = Lt(const 0_usize, const N); ++ assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue]; } bb5: { -- (*_2)[_11] = const 42_u8; +- (*_2)[_10] = const 42_u8; + (*_2)[0 of 1] = const 42_u8; - StorageDead(_11); + StorageDead(_10); _0 = const 42_u8; goto -> bb6; } diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff index 20001f1248ef..4b39e18d16cf 100644 --- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff +++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff @@ -36,7 +36,7 @@ StorageDead(_4); StorageLive(_7); _7 = copy _1; - _8 = Len((*_2)); + _8 = PtrMetadata(copy _2); _9 = Lt(copy _7, copy _8); assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb3, unwind unreachable]; } diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff index ca8f92df5de0..f0d4afa21ae4 100644 --- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff +++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff @@ -36,7 +36,7 @@ StorageDead(_4); StorageLive(_7); _7 = copy _1; - _8 = Len((*_2)); + _8 = PtrMetadata(copy _2); _9 = Lt(copy _7, copy _8); assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb3, unwind continue]; } diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 7294302609a2..42b388033360 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -27,20 +27,19 @@ fn main() -> () { let mut _0: (); let mut _1: [usize; ValTree(Leaf(0x00000003): usize)]; let _3: usize; - let mut _4: usize; - let mut _5: bool; - let mut _7: bool; - let _8: bool; - let mut _9: usize; - let _10: bool; + let mut _4: bool; + let mut _6: bool; + let _7: bool; + let mut _8: usize; + let _9: bool; scope 1 { debug v => _1; let _2: &'?3 usize; scope 2 { debug p => _2; - let _6: &'?4 usize; + let _5: &'?4 usize; scope 3 { - debug q => _6; + debug q => _5; } } } @@ -52,50 +51,50 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); _3 = const ConstValue(Scalar(0x00000000): usize); - _4 = Len(_1); - _5 = Lt(copy _3, copy _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb7]; + FakeRead(ForIndex, _1); + _4 = Lt(copy _3, const ValTree(Leaf(0x00000003): usize)); + assert(move _4, "index out of bounds: the length is {} but the index is {}", const ValTree(Leaf(0x00000003): usize), copy _3) -> [success: bb1, unwind: bb7]; } bb1: { _2 = &'?2 _1[_3]; FakeRead(ForLet(None), _2); + StorageLive(_5); + _5 = copy _2; + FakeRead(ForLet(None), _5); StorageLive(_6); - _6 = copy _2; - FakeRead(ForLet(None), _6); - StorageLive(_7); - _7 = const ConstValue(Scalar(0x01): bool); - switchInt(move _7) -> [0: bb4, otherwise: bb2]; + _6 = const ConstValue(Scalar(0x01): bool); + switchInt(move _6) -> [0: bb4, otherwise: bb2]; } bb2: { + StorageLive(_7); StorageLive(_8); - StorageLive(_9); - _9 = copy (*_6); - _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; + _8 = copy (*_5); + _7 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _8) -> [return: bb3, unwind: bb7]; } bb3: { - StorageDead(_9); StorageDead(_8); + StorageDead(_7); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb4: { - StorageLive(_10); - _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; + StorageLive(_9); + _9 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; } bb5: { - StorageDead(_10); + StorageDead(_9); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb6: { - StorageDead(_7); StorageDead(_6); + StorageDead(_5); StorageDead(_3); StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 85b89a013c4e..15395fd470e9 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -27,20 +27,19 @@ fn main() -> () { let mut _0: (); let mut _1: [usize; ValTree(Leaf(0x0000000000000003): usize)]; let _3: usize; - let mut _4: usize; - let mut _5: bool; - let mut _7: bool; - let _8: bool; - let mut _9: usize; - let _10: bool; + let mut _4: bool; + let mut _6: bool; + let _7: bool; + let mut _8: usize; + let _9: bool; scope 1 { debug v => _1; let _2: &'?3 usize; scope 2 { debug p => _2; - let _6: &'?4 usize; + let _5: &'?4 usize; scope 3 { - debug q => _6; + debug q => _5; } } } @@ -52,50 +51,50 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); _3 = const ConstValue(Scalar(0x0000000000000000): usize); - _4 = Len(_1); - _5 = Lt(copy _3, copy _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb7]; + FakeRead(ForIndex, _1); + _4 = Lt(copy _3, const ValTree(Leaf(0x0000000000000003): usize)); + assert(move _4, "index out of bounds: the length is {} but the index is {}", const ValTree(Leaf(0x0000000000000003): usize), copy _3) -> [success: bb1, unwind: bb7]; } bb1: { _2 = &'?2 _1[_3]; FakeRead(ForLet(None), _2); + StorageLive(_5); + _5 = copy _2; + FakeRead(ForLet(None), _5); StorageLive(_6); - _6 = copy _2; - FakeRead(ForLet(None), _6); - StorageLive(_7); - _7 = const ConstValue(Scalar(0x01): bool); - switchInt(move _7) -> [0: bb4, otherwise: bb2]; + _6 = const ConstValue(Scalar(0x01): bool); + switchInt(move _6) -> [0: bb4, otherwise: bb2]; } bb2: { + StorageLive(_7); StorageLive(_8); - StorageLive(_9); - _9 = copy (*_6); - _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; + _8 = copy (*_5); + _7 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _8) -> [return: bb3, unwind: bb7]; } bb3: { - StorageDead(_9); StorageDead(_8); + StorageDead(_7); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb4: { - StorageLive(_10); - _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; + StorageLive(_9); + _9 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; } bb5: { - StorageDead(_10); + StorageDead(_9); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb6: { - StorageDead(_7); StorageDead(_6); + StorageDead(_5); StorageDead(_3); StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff index 6575610727b9..5b39e45806e3 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff @@ -7,17 +7,16 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: u32; + let mut _6: bool; + let mut _8: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -38,10 +37,9 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; -- _7 = Lt(copy _5, copy _6); -- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; -+ _7 = const true; +- _6 = Lt(copy _5, const 6_usize); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind unreachable]; } @@ -50,13 +48,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_7); StorageLive(_8); - StorageLive(_9); - _9 = const 42_u32; -- _8 = copy _9; -+ _8 = const 42_u32; - StorageDead(_9); + _8 = const 42_u32; +- _7 = copy _8; ++ _7 = const 42_u32; StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff index 1a4ed5767fec..ea2742a6471a 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff @@ -7,17 +7,16 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: u32; + let mut _6: bool; + let mut _8: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -38,10 +37,9 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; -- _7 = Lt(copy _5, copy _6); -- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; -+ _7 = const true; +- _6 = Lt(copy _5, const 6_usize); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue]; } @@ -50,13 +48,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_7); StorageLive(_8); - StorageLive(_9); - _9 = const 42_u32; -- _8 = copy _9; -+ _8 = const 42_u32; - StorageDead(_9); + _8 = const 42_u32; +- _7 = copy _8; ++ _7 = const 42_u32; StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff index 6575610727b9..5b39e45806e3 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff @@ -7,17 +7,16 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: u32; + let mut _6: bool; + let mut _8: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -38,10 +37,9 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; -- _7 = Lt(copy _5, copy _6); -- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; -+ _7 = const true; +- _6 = Lt(copy _5, const 6_usize); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind unreachable]; } @@ -50,13 +48,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_7); StorageLive(_8); - StorageLive(_9); - _9 = const 42_u32; -- _8 = copy _9; -+ _8 = const 42_u32; - StorageDead(_9); + _8 = const 42_u32; +- _7 = copy _8; ++ _7 = const 42_u32; StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff index 1a4ed5767fec..ea2742a6471a 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff @@ -7,17 +7,16 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: u32; + let mut _6: bool; + let mut _8: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -38,10 +37,9 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; -- _7 = Lt(copy _5, copy _6); -- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; -+ _7 = const true; +- _6 = Lt(copy _5, const 6_usize); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue]; } @@ -50,13 +48,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); + StorageLive(_7); StorageLive(_8); - StorageLive(_9); - _9 = const 42_u32; -- _8 = copy _9; -+ _8 = const 42_u32; - StorageDead(_9); + _8 = const 42_u32; +- _7 = copy _8; ++ _7 = const 42_u32; StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff index e2420a341e0a..f7fe08831b97 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff @@ -7,19 +7,18 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: Point; + let mut _6: bool; + let mut _8: Point; ++ let mut _9: u32; + let mut _10: u32; -+ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -37,31 +36,30 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; - _7 = Lt(copy _5, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; + _6 = Lt(copy _5, const 6_usize); + assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_8); -- StorageLive(_9); -- _9 = Point { x: const 12_u32, y: const 42_u32 }; -- _8 = copy (_9.1: u32); -- StorageDead(_9); + StorageLive(_7); +- StorageLive(_8); +- _8 = Point { x: const 12_u32, y: const 42_u32 }; +- _7 = copy (_8.1: u32); +- StorageDead(_8); ++ StorageLive(_9); + StorageLive(_10); -+ StorageLive(_11); + nop; -+ _10 = const 12_u32; -+ _11 = const 42_u32; ++ _9 = const 12_u32; ++ _10 = const 42_u32; + nop; -+ _8 = copy _11; ++ _7 = copy _10; ++ StorageDead(_9); + StorageDead(_10); -+ StorageDead(_11); + nop; - StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff index a2fb3b979e62..6e36386bea60 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff @@ -7,19 +7,18 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: Point; + let mut _6: bool; + let mut _8: Point; ++ let mut _9: u32; + let mut _10: u32; -+ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -37,31 +36,30 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; - _7 = Lt(copy _5, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; + _6 = Lt(copy _5, const 6_usize); + assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_8); -- StorageLive(_9); -- _9 = Point { x: const 12_u32, y: const 42_u32 }; -- _8 = copy (_9.1: u32); -- StorageDead(_9); + StorageLive(_7); +- StorageLive(_8); +- _8 = Point { x: const 12_u32, y: const 42_u32 }; +- _7 = copy (_8.1: u32); +- StorageDead(_8); ++ StorageLive(_9); + StorageLive(_10); -+ StorageLive(_11); + nop; -+ _10 = const 12_u32; -+ _11 = const 42_u32; ++ _9 = const 12_u32; ++ _10 = const 42_u32; + nop; -+ _8 = copy _11; ++ _7 = copy _10; ++ StorageDead(_9); + StorageDead(_10); -+ StorageDead(_11); + nop; - StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff index e2420a341e0a..f7fe08831b97 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff @@ -7,19 +7,18 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: Point; + let mut _6: bool; + let mut _8: Point; ++ let mut _9: u32; + let mut _10: u32; -+ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -37,31 +36,30 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; - _7 = Lt(copy _5, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; + _6 = Lt(copy _5, const 6_usize); + assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_8); -- StorageLive(_9); -- _9 = Point { x: const 12_u32, y: const 42_u32 }; -- _8 = copy (_9.1: u32); -- StorageDead(_9); + StorageLive(_7); +- StorageLive(_8); +- _8 = Point { x: const 12_u32, y: const 42_u32 }; +- _7 = copy (_8.1: u32); +- StorageDead(_8); ++ StorageLive(_9); + StorageLive(_10); -+ StorageLive(_11); + nop; -+ _10 = const 12_u32; -+ _11 = const 42_u32; ++ _9 = const 12_u32; ++ _10 = const 42_u32; + nop; -+ _8 = copy _11; ++ _7 = copy _10; ++ StorageDead(_9); + StorageDead(_10); -+ StorageDead(_11); + nop; - StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff index a2fb3b979e62..6e36386bea60 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff @@ -7,19 +7,18 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: usize; - let mut _7: bool; - let mut _9: Point; + let mut _6: bool; + let mut _8: Point; ++ let mut _9: u32; + let mut _10: u32; -+ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _8: u32; + let _7: u32; scope 3 { - debug z => _8; + debug z => _7; } } } @@ -37,31 +36,30 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = const 6_usize; - _7 = Lt(copy _5, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; + _6 = Lt(copy _5, const 6_usize); + assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_8); -- StorageLive(_9); -- _9 = Point { x: const 12_u32, y: const 42_u32 }; -- _8 = copy (_9.1: u32); -- StorageDead(_9); + StorageLive(_7); +- StorageLive(_8); +- _8 = Point { x: const 12_u32, y: const 42_u32 }; +- _7 = copy (_8.1: u32); +- StorageDead(_8); ++ StorageLive(_9); + StorageLive(_10); -+ StorageLive(_11); + nop; -+ _10 = const 12_u32; -+ _11 = const 42_u32; ++ _9 = const 12_u32; ++ _10 = const 42_u32; + nop; -+ _8 = copy _11; ++ _7 = copy _10; ++ StorageDead(_9); + StorageDead(_10); -+ StorageDead(_11); + nop; - StorageDead(_8); + StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs index 574062d6c356..5dac535d195a 100644 --- a/tests/mir-opt/pre-codegen/slice_index.rs +++ b/tests/mir-opt/pre-codegen/slice_index.rs @@ -9,7 +9,7 @@ use std::ops::Range; // EMIT_MIR slice_index.slice_index_usize.PreCodegen.after.mir pub fn slice_index_usize(slice: &[u32], index: usize) -> u32 { // CHECK-LABEL: slice_index_usize - // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) + // CHECK: [[LEN:_[0-9]+]] = PtrMetadata(copy _1) // CHECK: Lt(copy _2, copy [[LEN]]) // CHECK-NOT: precondition_check // CHECK: _0 = copy (*_1)[_2]; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir index cc1034229fc3..81e60b8ec2ca 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir @@ -8,7 +8,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 { let mut _4: bool; bb0: { - _3 = Len((*_1)); + _3 = PtrMetadata(copy _1); _4 = Lt(copy _2, copy _3); assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir index 358226fb5294..c0fdc839608d 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir @@ -8,7 +8,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 { let mut _4: bool; bb0: { - _3 = Len((*_1)); + _3 = PtrMetadata(copy _1); _4 = Lt(copy _2, copy _3); assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index ecac03ad0f9d..151783969dd7 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -7,20 +7,19 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _3: usize; let mut _4: usize; let mut _9: std::option::Option; - let mut _11: usize; - let mut _12: bool; - let mut _14: &impl Fn(usize, &T); - let mut _15: (usize, &T); - let _16: (); + let mut _11: bool; + let mut _13: &impl Fn(usize, &T); + let mut _14: (usize, &T); + let _15: (); scope 1 { debug ((iter: std::ops::Range).0: usize) => _4; debug ((iter: std::ops::Range).1: usize) => _3; let _10: usize; scope 2 { debug i => _10; - let _13: &T; + let _12: &T; scope 3 { - debug x => _13; + debug x => _12; } } scope 5 (inlined iter::range::>::next) { @@ -82,23 +81,22 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_6); StorageDead(_7); _10 = copy ((_9 as Some).0: usize); - _11 = Len((*_1)); - _12 = Lt(copy _10, copy _11); - assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind unreachable]; + _11 = Lt(copy _10, copy _3); + assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind unreachable]; } bb6: { - _13 = &(*_1)[_10]; + _12 = &(*_1)[_10]; + StorageLive(_13); + _13 = &_2; StorageLive(_14); - _14 = &_2; - StorageLive(_15); - _15 = (copy _10, copy _13); - _16 = >::call(move _14, move _15) -> [return: bb7, unwind unreachable]; + _14 = (copy _10, copy _12); + _15 = >::call(move _13, move _14) -> [return: bb7, unwind unreachable]; } bb7: { - StorageDead(_15); StorageDead(_14); + StorageDead(_13); StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index 1032473b9b2a..006329dc20dc 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -7,20 +7,19 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _3: usize; let mut _4: usize; let mut _9: std::option::Option; - let mut _11: usize; - let mut _12: bool; - let mut _14: &impl Fn(usize, &T); - let mut _15: (usize, &T); - let _16: (); + let mut _11: bool; + let mut _13: &impl Fn(usize, &T); + let mut _14: (usize, &T); + let _15: (); scope 1 { debug ((iter: std::ops::Range).0: usize) => _4; debug ((iter: std::ops::Range).1: usize) => _3; let _10: usize; scope 2 { debug i => _10; - let _13: &T; + let _12: &T; scope 3 { - debug x => _13; + debug x => _12; } } scope 5 (inlined iter::range::>::next) { @@ -82,23 +81,22 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_6); StorageDead(_7); _10 = copy ((_9 as Some).0: usize); - _11 = Len((*_1)); - _12 = Lt(copy _10, copy _11); - assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind: bb8]; + _11 = Lt(copy _10, copy _3); + assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind: bb8]; } bb6: { - _13 = &(*_1)[_10]; + _12 = &(*_1)[_10]; + StorageLive(_13); + _13 = &_2; StorageLive(_14); - _14 = &_2; - StorageLive(_15); - _15 = (copy _10, copy _13); - _16 = >::call(move _14, move _15) -> [return: bb7, unwind: bb8]; + _14 = (copy _10, copy _12); + _15 = >::call(move _13, move _14) -> [return: bb7, unwind: bb8]; } bb7: { - StorageDead(_15); StorageDead(_14); + StorageDead(_13); StorageDead(_9); goto -> bb1; } diff --git a/tests/run-make/sepcomp-cci-copies/cci_lib.rs b/tests/run-make/sepcomp-cci-copies/cci_lib.rs deleted file mode 100644 index 869d4a6cd3e4..000000000000 --- a/tests/run-make/sepcomp-cci-copies/cci_lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![crate_type = "rlib"] - -#[inline] -pub fn cci_fn() -> usize { - 1234 -} diff --git a/tests/run-make/sepcomp-cci-copies/foo.rs b/tests/run-make/sepcomp-cci-copies/foo.rs deleted file mode 100644 index ba251fcb0ac2..000000000000 --- a/tests/run-make/sepcomp-cci-copies/foo.rs +++ /dev/null @@ -1,25 +0,0 @@ -extern crate cci_lib; -use cci_lib::cci_fn; - -fn call1() -> usize { - cci_fn() -} - -mod a { - use cci_lib::cci_fn; - pub fn call2() -> usize { - cci_fn() - } -} - -mod b { - pub fn call3() -> usize { - 0 - } -} - -fn main() { - call1(); - a::call2(); - b::call3(); -} diff --git a/tests/run-make/sepcomp-cci-copies/rmake.rs b/tests/run-make/sepcomp-cci-copies/rmake.rs deleted file mode 100644 index a66cc2872b43..000000000000 --- a/tests/run-make/sepcomp-cci-copies/rmake.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Check that cross-crate inlined items are inlined in all compilation units -// that refer to them, and not in any other compilation units. -// Note that we have to pass `-C codegen-units=6` because up to two CGUs may be -// created for each source module (see `rustc_const_eval::monomorphize::partitioning`). -// See https://github.com/rust-lang/rust/pull/16367 - -use run_make_support::{count_regex_matches_in_files_with_extension, regex, rustc}; - -fn main() { - rustc().input("cci_lib.rs").run(); - rustc().input("foo.rs").emit("llvm-ir").codegen_units(6).arg("-Zinline-in-all-cgus").run(); - let re = regex::Regex::new(r#"define\ .*cci_fn"#).unwrap(); - assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2); -} diff --git a/tests/run-make/sepcomp-inlining/foo.rs b/tests/run-make/sepcomp-inlining/foo.rs deleted file mode 100644 index 9101ee691a4e..000000000000 --- a/tests/run-make/sepcomp-inlining/foo.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![crate_type = "lib"] - -#[inline] -fn inlined() -> u32 { - 1234 -} - -fn normal() -> u32 { - 2345 -} - -mod a { - pub fn f() -> u32 { - ::inlined() + ::normal() - } -} - -mod b { - pub fn f() -> u32 { - ::inlined() + ::normal() - } -} - -pub fn start(_: isize, _: *const *const u8) -> isize { - a::f(); - b::f(); - - 0 -} diff --git a/tests/run-make/sepcomp-inlining/rmake.rs b/tests/run-make/sepcomp-inlining/rmake.rs deleted file mode 100644 index ea4a4d210cc3..000000000000 --- a/tests/run-make/sepcomp-inlining/rmake.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that #[inline] functions still get inlined across compilation unit -// boundaries. Compilation should produce three IR files, but only the two -// compilation units that have a usage of the #[inline] function should -// contain a definition. Also, the non-#[inline] function should be defined -// in only one compilation unit. -// See https://github.com/rust-lang/rust/pull/16367 - -use run_make_support::{count_regex_matches_in_files_with_extension, regex, rustc}; - -fn main() { - rustc().input("foo.rs").emit("llvm-ir").codegen_units(3).arg("-Zinline-in-all-cgus").run(); - let re = regex::Regex::new(r#"define\ i32\ .*inlined"#).unwrap(); - assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 0); - let re = regex::Regex::new(r#"define\ internal\ .*inlined"#).unwrap(); - assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2); - let re = regex::Regex::new(r#"define\ hidden\ i32\ .*normal"#).unwrap(); - assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 1); - let re = regex::Regex::new(r#"declare\ hidden\ i32\ .*normal"#).unwrap(); - assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2); -} diff --git a/tests/run-make/sepcomp-separate/foo.rs b/tests/run-make/sepcomp-separate/foo.rs deleted file mode 100644 index 169bafa9b3a5..000000000000 --- a/tests/run-make/sepcomp-separate/foo.rs +++ /dev/null @@ -1,21 +0,0 @@ -fn magic_fn() -> usize { - 1234 -} - -mod a { - pub fn magic_fn() -> usize { - 2345 - } -} - -mod b { - pub fn magic_fn() -> usize { - 3456 - } -} - -fn main() { - magic_fn(); - a::magic_fn(); - b::magic_fn(); -} diff --git a/tests/run-make/sepcomp-separate/rmake.rs b/tests/run-make/sepcomp-separate/rmake.rs deleted file mode 100644 index 49958044a612..000000000000 --- a/tests/run-make/sepcomp-separate/rmake.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Test that separate compilation actually puts code into separate compilation -// units. `foo.rs` defines `magic_fn` in three different modules, which should -// wind up in three different compilation units. -// See https://github.com/rust-lang/rust/pull/16367 - -use run_make_support::{count_regex_matches_in_files_with_extension, regex, rustc}; - -fn main() { - rustc().input("foo.rs").emit("llvm-ir").codegen_units(3).run(); - let re = regex::Regex::new(r#"define\ .*magic_fn"#).unwrap(); - assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 3); -} diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.rs b/tests/ui/borrowck/borrowck-describe-lvalue.rs index cdcff69d6e52..f3a4b382fa89 100644 --- a/tests/ui/borrowck/borrowck-describe-lvalue.rs +++ b/tests/ui/borrowck/borrowck-describe-lvalue.rs @@ -231,7 +231,6 @@ fn main() { let x = &mut v; v[0].y; //~^ ERROR cannot use `v[_].y` because it was mutably borrowed - //~| ERROR cannot use `*v` because it was mutably borrowed drop(x); } // Field of constant index diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.stderr b/tests/ui/borrowck/borrowck-describe-lvalue.stderr index 11f2e42d42b7..666a21808d80 100644 --- a/tests/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/tests/ui/borrowck/borrowck-describe-lvalue.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:254:13 + --> $DIR/borrowck-describe-lvalue.rs:253:13 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -9,7 +9,7 @@ LL | *y = 1; | ------ first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:264:20 + --> $DIR/borrowck-describe-lvalue.rs:263:20 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -19,7 +19,7 @@ LL | *y = 1; | ------ first borrow later used here error: captured variable cannot escape `FnMut` closure body - --> $DIR/borrowck-describe-lvalue.rs:262:16 + --> $DIR/borrowck-describe-lvalue.rs:261:16 | LL | let mut x = 0; | ----- variable defined here @@ -300,17 +300,6 @@ LL | S { x: F { y: ref x0, .. }, .. } => LL | drop(x); | - mutable borrow later used here -error[E0503]: cannot use `*v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:232:9 - | -LL | let x = &mut v; - | ------ `v` is borrowed here -LL | v[0].y; - | ^^^^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[_].y` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:232:9 | @@ -318,12 +307,12 @@ LL | let x = &mut v; | ------ `v` is borrowed here LL | v[0].y; | ^^^^^^ use of borrowed `v` -... +LL | LL | drop(x); | - borrow later used here error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:243:24 + --> $DIR/borrowck-describe-lvalue.rs:242:24 | LL | let x = &mut v; | ------ mutable borrow occurs here @@ -357,7 +346,7 @@ LL | drop(x); | - mutable borrow later used here error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:274:22 + --> $DIR/borrowck-describe-lvalue.rs:273:22 | LL | drop(x); | - value moved here @@ -366,7 +355,7 @@ LL | drop(x); | = note: move occurs because `x` has type `Vec`, which does not implement the `Copy` trait -error: aborting due to 32 previous errors +error: aborting due to 31 previous errors Some errors have detailed explanations: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-103095.rs b/tests/ui/borrowck/issue-103095.rs index 3c29bc761553..53587a16abf8 100644 --- a/tests/ui/borrowck/issue-103095.rs +++ b/tests/ui/borrowck/issue-103095.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver trait FnOnceForGenericRef: FnOnce(&T) -> Self::FnOutput { type FnOutput; @@ -16,10 +19,7 @@ struct Data> { impl> Data { fn new(value: T, f: D) -> Self { let output = f(&value); - Self { - value: Some(value), - output: Some(output), - } + Self { value: Some(value), output: Some(output) } } } diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs index 3abc81e191eb..2d22c9a856f6 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs @@ -12,8 +12,7 @@ fn arrays_1() { // c will capture `arr` completely, therefore another index into the // array can't be modified here arr[1] += 10; - //~^ ERROR: cannot use `arr` because it was mutably borrowed - //~| ERROR: cannot use `arr[_]` because it was mutably borrowed + //~^ ERROR: cannot use `arr[_]` because it was mutably borrowed c(); } @@ -55,8 +54,7 @@ fn arrays_4() { // c will capture `arr` completely, therefore we cannot borrow another index // into the array. println!("{}", arr[3]); - //~^ ERROR: cannot use `arr` because it was mutably borrowed - //~| ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable + //~^ ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable c(); } diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr index 9e5200ef34b5..97ecdfab8205 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -1,17 +1,3 @@ -error[E0503]: cannot use `arr` because it was mutably borrowed - --> $DIR/arrays.rs:14:5 - | -LL | let mut c = || { - | -- `arr` is borrowed here -LL | arr[0] += 10; - | --- borrow occurs due to use of `arr` in closure -... -LL | arr[1] += 10; - | ^^^^^^ use of borrowed `arr` -... -LL | c(); - | - borrow later used here - error[E0503]: cannot use `arr[_]` because it was mutably borrowed --> $DIR/arrays.rs:14:5 | @@ -22,12 +8,12 @@ LL | arr[0] += 10; ... LL | arr[1] += 10; | ^^^^^^^^^^^^ use of borrowed `arr` -... +LL | LL | c(); | - borrow later used here error[E0506]: cannot assign to `arr[_]` because it is borrowed - --> $DIR/arrays.rs:29:5 + --> $DIR/arrays.rs:28:5 | LL | let c = || { | -- `arr[_]` is borrowed here @@ -41,7 +27,7 @@ LL | c(); | - borrow later used here error[E0506]: cannot assign to `arr[_]` because it is borrowed - --> $DIR/arrays.rs:43:5 + --> $DIR/arrays.rs:42:5 | LL | let c = || { | -- `arr[_]` is borrowed here @@ -54,22 +40,8 @@ LL | LL | c(); | - borrow later used here -error[E0503]: cannot use `arr` because it was mutably borrowed - --> $DIR/arrays.rs:57:20 - | -LL | let mut c = || { - | -- `arr` is borrowed here -LL | arr[1] += 10; - | --- borrow occurs due to use of `arr` in closure -... -LL | println!("{}", arr[3]); - | ^^^^^^ use of borrowed `arr` -... -LL | c(); - | - borrow later used here - error[E0502]: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable - --> $DIR/arrays.rs:57:20 + --> $DIR/arrays.rs:56:20 | LL | let mut c = || { | -- mutable borrow occurs here @@ -85,7 +57,7 @@ LL | c(); = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable - --> $DIR/arrays.rs:73:24 + --> $DIR/arrays.rs:71:24 | LL | let mut c = || { | -- mutable borrow occurs here @@ -98,7 +70,7 @@ LL | println!("{:#?}", &arr[3..2]); LL | c(); | - mutable borrow later used here -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0502, E0503, E0506. For more information about an error, try `rustc --explain E0502`. diff --git a/tests/ui/closures/supertrait-hint-references-assoc-ty.rs b/tests/ui/closures/supertrait-hint-references-assoc-ty.rs index fa74ffc5bec5..b6a1685cb720 100644 --- a/tests/ui/closures/supertrait-hint-references-assoc-ty.rs +++ b/tests/ui/closures/supertrait-hint-references-assoc-ty.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver pub trait Fn0: Fn(i32) -> Self::Out { type Out; diff --git a/tests/ui/consts/issue-65348.rs b/tests/ui/consts/issue-65348.rs index 1443fcbe1c1c..0d12da3926cd 100644 --- a/tests/ui/consts/issue-65348.rs +++ b/tests/ui/consts/issue-65348.rs @@ -9,15 +9,17 @@ impl Generic { } pub const fn array() -> &'static T { - #[allow(unconditional_panic)] + #[expect(unconditional_panic)] &Generic::::ARRAY[0] } pub const fn newtype_array() -> &'static T { + #[expect(unconditional_panic)] &Generic::::NEWTYPE_ARRAY.0[0] } pub const fn array_field() -> &'static T { + #[expect(unconditional_panic)] &(Generic::::ARRAY_FIELD.0).1[0] } diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs index 34548e2487e0..a44ed9e5ef59 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs @@ -43,9 +43,9 @@ fn main() { } foo(bar, "string", |s| s.len() == 5); - //~^ ERROR implementation of `Parser` is not general enough - //~| ERROR implementation of `Parser` is not general enough + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough foo(baz, "string", |s| s.0.len() == 5); - //~^ ERROR implementation of `Parser` is not general enough - //~| ERROR implementation of `Parser` is not general enough + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough } diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 23fc6e2f7f40..b2bb417a8f01 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -1,39 +1,39 @@ -error: implementation of `Parser` is not general enough +error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 | LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... - = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` -error: implementation of `Parser` is not general enough +error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 | LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... - = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `Parser` is not general enough +error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 | LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... - = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` -error: implementation of `Parser` is not general enough +error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 | LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... - = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` + = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 4 previous errors diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed index 7383ab177dc3..25943d11fc47 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed @@ -9,4 +9,5 @@ fn main() { let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + //[next]~| ERROR expected a `FnMut(& as Iterator>::Item)` closure, found } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index 6104a0893373..696214c0a3cd 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -13,12 +13,26 @@ note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:33 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24 | LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); - | ^^^^^^ expected `&&i32`, found integer + | ^^^^ expected `&&i32`, found integer -error: aborting due to 2 previous errors +error[E0277]: expected a `FnMut(& as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29 + | +LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(& as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnMut(&'a as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` + = note: expected a closure with arguments `(&&&i32,)` + found a closure with arguments `(& as Iterator>::Item,)` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 668a1a7a29c6..9e44489cbf17 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -9,4 +9,5 @@ fn main() { let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + //[next]~| ERROR expected a `FnMut(& as Iterator>::Item)` closure, found } diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed index e2a2f9486b78..8a97a2f09cca 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed +++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed @@ -2,24 +2,24 @@ //@ edition:2018 // Most of items are taken from ./recover-const-async-fn-ptr.rs but this is able to apply rustfix. -pub type T0 = fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T1 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T2 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T3 = fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type T4 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type T5 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type T6 = unsafe extern "C" fn(); +pub type T0 = fn(); //~ ERROR an `fn` pointer type cannot be `const` +pub type T1 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` +pub type T2 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` +pub type T3 = fn(); //~ ERROR an `fn` pointer type cannot be `async` +pub type T4 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` +pub type T5 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` +pub type T6 = unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` -pub type FTT0 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT1 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT2 = for<'a> unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT3 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type FTT4 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type FTT5 = for<'a> unsafe extern "C" fn(); +pub type FTT0 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `const` +pub type FTT1 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` +pub type FTT2 = for<'a> unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` +pub type FTT3 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `async` +pub type FTT4 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` +pub type FTT5 = for<'a> unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `async` -pub type FTT6 = for<'a> unsafe extern "C" fn(); +pub type FTT6 = for<'a> unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr index ddc8bac678cf..b9d2625d9f4b 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr +++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr @@ -9,7 +9,7 @@ LL | pub type T0 = const fn(); help: remove the `const` qualifier | LL - pub type T0 = const fn(); -LL + pub type T0 = fn(); +LL + pub type T0 = fn(); | error: an `fn` pointer type cannot be `const` @@ -23,7 +23,7 @@ LL | pub type T1 = const extern "C" fn(); help: remove the `const` qualifier | LL - pub type T1 = const extern "C" fn(); -LL + pub type T1 = extern "C" fn(); +LL + pub type T1 = extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -37,7 +37,7 @@ LL | pub type T2 = const unsafe extern "C" fn(); help: remove the `const` qualifier | LL - pub type T2 = const unsafe extern "C" fn(); -LL + pub type T2 = unsafe extern "C" fn(); +LL + pub type T2 = unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -51,7 +51,7 @@ LL | pub type T3 = async fn(); help: remove the `async` qualifier | LL - pub type T3 = async fn(); -LL + pub type T3 = fn(); +LL + pub type T3 = fn(); | error: an `fn` pointer type cannot be `async` @@ -65,7 +65,7 @@ LL | pub type T4 = async extern "C" fn(); help: remove the `async` qualifier | LL - pub type T4 = async extern "C" fn(); -LL + pub type T4 = extern "C" fn(); +LL + pub type T4 = extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -79,7 +79,7 @@ LL | pub type T5 = async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - pub type T5 = async unsafe extern "C" fn(); -LL + pub type T5 = unsafe extern "C" fn(); +LL + pub type T5 = unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -93,7 +93,7 @@ LL | pub type T6 = const async unsafe extern "C" fn(); help: remove the `const` qualifier | LL - pub type T6 = const async unsafe extern "C" fn(); -LL + pub type T6 = async unsafe extern "C" fn(); +LL + pub type T6 = async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -107,7 +107,7 @@ LL | pub type T6 = const async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - pub type T6 = const async unsafe extern "C" fn(); -LL + pub type T6 = const unsafe extern "C" fn(); +LL + pub type T6 = const unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -121,7 +121,7 @@ LL | pub type FTT0 = for<'a> const fn(); help: remove the `const` qualifier | LL - pub type FTT0 = for<'a> const fn(); -LL + pub type FTT0 = for<'a> fn(); +LL + pub type FTT0 = for<'a> fn(); | error: an `fn` pointer type cannot be `const` @@ -135,7 +135,7 @@ LL | pub type FTT1 = for<'a> const extern "C" fn(); help: remove the `const` qualifier | LL - pub type FTT1 = for<'a> const extern "C" fn(); -LL + pub type FTT1 = for<'a> extern "C" fn(); +LL + pub type FTT1 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -149,7 +149,7 @@ LL | pub type FTT2 = for<'a> const unsafe extern "C" fn(); help: remove the `const` qualifier | LL - pub type FTT2 = for<'a> const unsafe extern "C" fn(); -LL + pub type FTT2 = for<'a> unsafe extern "C" fn(); +LL + pub type FTT2 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -163,7 +163,7 @@ LL | pub type FTT3 = for<'a> async fn(); help: remove the `async` qualifier | LL - pub type FTT3 = for<'a> async fn(); -LL + pub type FTT3 = for<'a> fn(); +LL + pub type FTT3 = for<'a> fn(); | error: an `fn` pointer type cannot be `async` @@ -177,7 +177,7 @@ LL | pub type FTT4 = for<'a> async extern "C" fn(); help: remove the `async` qualifier | LL - pub type FTT4 = for<'a> async extern "C" fn(); -LL + pub type FTT4 = for<'a> extern "C" fn(); +LL + pub type FTT4 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -191,7 +191,7 @@ LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - pub type FTT5 = for<'a> async unsafe extern "C" fn(); -LL + pub type FTT5 = for<'a> unsafe extern "C" fn(); +LL + pub type FTT5 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -205,7 +205,7 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); help: remove the `const` qualifier | LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); -LL + pub type FTT6 = for<'a> async unsafe extern "C" fn(); +LL + pub type FTT6 = for<'a> async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -219,7 +219,7 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); -LL + pub type FTT6 = for<'a> const unsafe extern "C" fn(); +LL + pub type FTT6 = for<'a> const unsafe extern "C" fn(); | error: aborting due to 16 previous errors diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr index 9112a0e135a5..4e5927914ccb 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr @@ -9,7 +9,7 @@ LL | type T0 = const fn(); help: remove the `const` qualifier | LL - type T0 = const fn(); -LL + type T0 = fn(); +LL + type T0 = fn(); | error: an `fn` pointer type cannot be `const` @@ -23,7 +23,7 @@ LL | type T1 = const extern "C" fn(); help: remove the `const` qualifier | LL - type T1 = const extern "C" fn(); -LL + type T1 = extern "C" fn(); +LL + type T1 = extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -37,7 +37,7 @@ LL | type T2 = const unsafe extern "C" fn(); help: remove the `const` qualifier | LL - type T2 = const unsafe extern "C" fn(); -LL + type T2 = unsafe extern "C" fn(); +LL + type T2 = unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -51,7 +51,7 @@ LL | type T3 = async fn(); help: remove the `async` qualifier | LL - type T3 = async fn(); -LL + type T3 = fn(); +LL + type T3 = fn(); | error: an `fn` pointer type cannot be `async` @@ -65,7 +65,7 @@ LL | type T4 = async extern "C" fn(); help: remove the `async` qualifier | LL - type T4 = async extern "C" fn(); -LL + type T4 = extern "C" fn(); +LL + type T4 = extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -79,7 +79,7 @@ LL | type T5 = async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - type T5 = async unsafe extern "C" fn(); -LL + type T5 = unsafe extern "C" fn(); +LL + type T5 = unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -93,7 +93,7 @@ LL | type T6 = const async unsafe extern "C" fn(); help: remove the `const` qualifier | LL - type T6 = const async unsafe extern "C" fn(); -LL + type T6 = async unsafe extern "C" fn(); +LL + type T6 = async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -107,7 +107,7 @@ LL | type T6 = const async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - type T6 = const async unsafe extern "C" fn(); -LL + type T6 = const unsafe extern "C" fn(); +LL + type T6 = const unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -121,7 +121,7 @@ LL | type FT0 = for<'a> const fn(); help: remove the `const` qualifier | LL - type FT0 = for<'a> const fn(); -LL + type FT0 = for<'a> fn(); +LL + type FT0 = for<'a> fn(); | error: an `fn` pointer type cannot be `const` @@ -135,7 +135,7 @@ LL | type FT1 = for<'a> const extern "C" fn(); help: remove the `const` qualifier | LL - type FT1 = for<'a> const extern "C" fn(); -LL + type FT1 = for<'a> extern "C" fn(); +LL + type FT1 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -149,7 +149,7 @@ LL | type FT2 = for<'a> const unsafe extern "C" fn(); help: remove the `const` qualifier | LL - type FT2 = for<'a> const unsafe extern "C" fn(); -LL + type FT2 = for<'a> unsafe extern "C" fn(); +LL + type FT2 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -163,7 +163,7 @@ LL | type FT3 = for<'a> async fn(); help: remove the `async` qualifier | LL - type FT3 = for<'a> async fn(); -LL + type FT3 = for<'a> fn(); +LL + type FT3 = for<'a> fn(); | error: an `fn` pointer type cannot be `async` @@ -177,7 +177,7 @@ LL | type FT4 = for<'a> async extern "C" fn(); help: remove the `async` qualifier | LL - type FT4 = for<'a> async extern "C" fn(); -LL + type FT4 = for<'a> extern "C" fn(); +LL + type FT4 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -191,7 +191,7 @@ LL | type FT5 = for<'a> async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - type FT5 = for<'a> async unsafe extern "C" fn(); -LL + type FT5 = for<'a> unsafe extern "C" fn(); +LL + type FT5 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` @@ -205,7 +205,7 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn(); help: remove the `const` qualifier | LL - type FT6 = for<'a> const async unsafe extern "C" fn(); -LL + type FT6 = for<'a> async unsafe extern "C" fn(); +LL + type FT6 = for<'a> async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` @@ -219,7 +219,7 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn(); help: remove the `async` qualifier | LL - type FT6 = for<'a> const async unsafe extern "C" fn(); -LL + type FT6 = for<'a> const unsafe extern "C" fn(); +LL + type FT6 = for<'a> const unsafe extern "C" fn(); | error[E0308]: mismatched types diff --git a/tests/ui/self/arbitrary_self_types_recursive_receiver.rs b/tests/ui/self/arbitrary_self_types_recursive_receiver.rs index f3e7f96d7c4d..8b1b6a8a105f 100644 --- a/tests/ui/self/arbitrary_self_types_recursive_receiver.rs +++ b/tests/ui/self/arbitrary_self_types_recursive_receiver.rs @@ -1,6 +1,22 @@ //@ run-pass #![feature(arbitrary_self_types)] +// When probing for methods, we step forward through a chain of types. The first +// few of those steps can be reached by jumping through the chain of Derefs or the +// chain of Receivers. Later steps can only be reached by following the chain of +// Receivers. For instance, supposing A and B implement both Receiver and Deref, +// while C and D implement only Receiver: +// +// Type A>>> +// +// Deref chain: A -> B -> C +// Receiver chain: A -> B -> C -> D -> E +// +// We report bad type errors from the end of the chain. But at the end of which +// chain? We never morph the type as far as E so the correct behavior is to +// report errors from point C, i.e. the end of the Deref chain. This test case +// ensures we do that. + struct MyNonNull(*const T); impl std::ops::Receiver for MyNonNull { @@ -10,7 +26,13 @@ impl std::ops::Receiver for MyNonNull { #[allow(dead_code)] impl MyNonNull { fn foo(&self) -> *const U { - self.cast::().bar() + let mnn = self.cast::(); + // The following method call is the point of this test. + // If probe.rs reported errors from the last type discovered + // in the Receiver chain, it would be sad here because U is just + // a type variable. But this is a valid call so it ensures + // probe.rs doesn't make that mistake. + mnn.bar() } fn cast(&self) -> MyNonNull { MyNonNull(self.0 as *const U) diff --git a/tests/ui/stable-mir-print/operands.stdout b/tests/ui/stable-mir-print/operands.stdout index 3c27878b3cf0..c3b1151ae24a 100644 --- a/tests/ui/stable-mir-print/operands.stdout +++ b/tests/ui/stable-mir-print/operands.stdout @@ -5,187 +5,183 @@ fn operands(_1: u8) -> () { let _2: [u8; 10]; let _3: u8; let _4: usize; - let mut _5: usize; - let mut _6: bool; - let _7: u8; - let _8: usize; - let mut _9: (usize, bool); - let mut _10: usize; - let mut _11: bool; - let mut _12: (&u8, &u8); - let mut _13: &u8; - let mut _14: &u8; - let _15: &u8; - let _16: &u8; - let mut _17: bool; - let mut _18: u8; - let mut _19: u8; - let _20: core::panicking::AssertKind; - let _21: !; - let mut _22: Option>; - let _23: &u8; - let _24: u8; - let mut _25: (&u8, &u8); - let mut _26: &u8; - let mut _27: &u8; - let _28: &u8; - let _29: &u8; - let mut _30: bool; - let mut _31: u8; - let mut _32: u8; - let _33: core::panicking::AssertKind; - let _34: !; - let mut _35: Option>; - let _36: (u8, u8); - let _37: u8; - let _38: u8; - let mut _39: (&u8, &u8); - let mut _40: &u8; - let mut _41: &u8; - let _42: &u8; - let _43: &u8; - let mut _44: bool; - let mut _45: u8; - let mut _46: u8; - let _47: core::panicking::AssertKind; - let _48: !; - let mut _49: Option>; - let _50: usize; - let mut _51: &[u8]; - let mut _52: &[u8; 10]; - let _53: usize; - let _54: &usize; - let mut _55: (&usize, &usize); - let mut _56: &usize; - let mut _57: &usize; - let _58: &usize; - let _59: &usize; - let mut _60: bool; - let mut _61: usize; - let mut _62: usize; - let _63: core::panicking::AssertKind; - let _64: !; - let mut _65: Option>; + let mut _5: bool; + let _6: u8; + let _7: usize; + let mut _8: (usize, bool); + let mut _9: bool; + let mut _10: (&u8, &u8); + let mut _11: &u8; + let mut _12: &u8; + let _13: &u8; + let _14: &u8; + let mut _15: bool; + let mut _16: u8; + let mut _17: u8; + let _18: core::panicking::AssertKind; + let _19: !; + let mut _20: Option>; + let _21: &u8; + let _22: u8; + let mut _23: (&u8, &u8); + let mut _24: &u8; + let mut _25: &u8; + let _26: &u8; + let _27: &u8; + let mut _28: bool; + let mut _29: u8; + let mut _30: u8; + let _31: core::panicking::AssertKind; + let _32: !; + let mut _33: Option>; + let _34: (u8, u8); + let _35: u8; + let _36: u8; + let mut _37: (&u8, &u8); + let mut _38: &u8; + let mut _39: &u8; + let _40: &u8; + let _41: &u8; + let mut _42: bool; + let mut _43: u8; + let mut _44: u8; + let _45: core::panicking::AssertKind; + let _46: !; + let mut _47: Option>; + let _48: usize; + let mut _49: &[u8]; + let mut _50: &[u8; 10]; + let _51: usize; + let _52: &usize; + let mut _53: (&usize, &usize); + let mut _54: &usize; + let mut _55: &usize; + let _56: &usize; + let _57: &usize; + let mut _58: bool; + let mut _59: usize; + let mut _60: usize; + let _61: core::panicking::AssertKind; + let _62: !; + let mut _63: Option>; debug val => _1; debug array => _2; debug first => _3; - debug last => _7; - debug left_val => _15; - debug right_val => _16; - debug kind => _20; - debug reference => _23; - debug dereferenced => _24; - debug left_val => _28; - debug right_val => _29; - debug kind => _33; - debug tuple => _36; - debug first_again => _37; - debug first_again_again => _38; - debug left_val => _42; - debug right_val => _43; - debug kind => _47; - debug length => _50; - debug size_of => _53; - debug left_val => _58; - debug right_val => _59; - debug kind => _63; + debug last => _6; + debug left_val => _13; + debug right_val => _14; + debug kind => _18; + debug reference => _21; + debug dereferenced => _22; + debug left_val => _26; + debug right_val => _27; + debug kind => _31; + debug tuple => _34; + debug first_again => _35; + debug first_again_again => _36; + debug left_val => _40; + debug right_val => _41; + debug kind => _45; + debug length => _48; + debug size_of => _51; + debug left_val => _56; + debug right_val => _57; + debug kind => _61; bb0: { _2 = [_1; 10]; _4 = 0_usize; - _5 = 10_usize; - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; + _5 = Lt(_4, 10_usize); + assert(move _5, "index out of bounds: the length is {} but the index is {}", 10_usize, _4) -> [success: bb1, unwind unreachable]; } bb1: { _3 = _2[_4]; - _9 = CheckedSub(10_usize, 1_usize); - assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; + _8 = CheckedSub(10_usize, 1_usize); + assert(!move (_8.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; } bb2: { - _8 = move (_9.0: usize); - _10 = 10_usize; - _11 = Lt(_8, _10); - assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, _8) -> [success: bb3, unwind unreachable]; + _7 = move (_8.0: usize); + _9 = Lt(_7, 10_usize); + assert(move _9, "index out of bounds: the length is {} but the index is {}", 10_usize, _7) -> [success: bb3, unwind unreachable]; } bb3: { - _7 = _2[_8]; - _13 = &_3; - _14 = &_7; - _12 = (move _13, move _14); - _15 = (_12.0: &u8); - _16 = (_12.1: &u8); - _18 = (*_15); - _19 = (*_16); - _17 = Eq(move _18, move _19); - switchInt(move _17) -> [0: bb5, otherwise: bb4]; + _6 = _2[_7]; + _11 = &_3; + _12 = &_6; + _10 = (move _11, move _12); + _13 = (_10.0: &u8); + _14 = (_10.1: &u8); + _16 = (*_13); + _17 = (*_14); + _15 = Eq(move _16, move _17); + switchInt(move _15) -> [0: bb5, otherwise: bb4]; } bb4: { - _23 = &_3; - _24 = (*_23); - _26 = &_24; - _27 = &_3; - _25 = (move _26, move _27); - _28 = (_25.0: &u8); - _29 = (_25.1: &u8); - _31 = (*_28); - _32 = (*_29); - _30 = Eq(move _31, move _32); - switchInt(move _30) -> [0: bb7, otherwise: bb6]; + _21 = &_3; + _22 = (*_21); + _24 = &_22; + _25 = &_3; + _23 = (move _24, move _25); + _26 = (_23.0: &u8); + _27 = (_23.1: &u8); + _29 = (*_26); + _30 = (*_27); + _28 = Eq(move _29, move _30); + switchInt(move _28) -> [0: bb7, otherwise: bb6]; } bb5: { - _20 = core::panicking::AssertKind::Eq; - _22 = std::option::Option::None; - _21 = core::panicking::assert_failed::(move _20, _15, _16, move _22) -> unwind unreachable; + _18 = core::panicking::AssertKind::Eq; + _20 = std::option::Option::None; + _19 = core::panicking::assert_failed::(move _18, _13, _14, move _20) -> unwind unreachable; } bb6: { - _36 = (_3, _7); - _37 = (_36.0: u8); - _38 = (_36.0: u8); - _40 = &_37; - _41 = &_38; - _39 = (move _40, move _41); - _42 = (_39.0: &u8); - _43 = (_39.1: &u8); - _45 = (*_42); - _46 = (*_43); - _44 = Eq(move _45, move _46); - switchInt(move _44) -> [0: bb9, otherwise: bb8]; + _34 = (_3, _6); + _35 = (_34.0: u8); + _36 = (_34.0: u8); + _38 = &_35; + _39 = &_36; + _37 = (move _38, move _39); + _40 = (_37.0: &u8); + _41 = (_37.1: &u8); + _43 = (*_40); + _44 = (*_41); + _42 = Eq(move _43, move _44); + switchInt(move _42) -> [0: bb9, otherwise: bb8]; } bb7: { - _33 = core::panicking::AssertKind::Eq; - _35 = std::option::Option::None; - _34 = core::panicking::assert_failed::(move _33, _28, _29, move _35) -> unwind unreachable; + _31 = core::panicking::AssertKind::Eq; + _33 = std::option::Option::None; + _32 = core::panicking::assert_failed::(move _31, _26, _27, move _33) -> unwind unreachable; } bb8: { - _52 = &_2; - _51 = move _52 as &[u8]; - _50 = PtrMetadata(move _51); - _54 = &_50; - _53 = std::mem::size_of_val::(_54) -> [return: bb10, unwind unreachable]; + _50 = &_2; + _49 = move _50 as &[u8]; + _48 = PtrMetadata(move _49); + _52 = &_48; + _51 = std::mem::size_of_val::(_52) -> [return: bb10, unwind unreachable]; } bb9: { - _47 = core::panicking::AssertKind::Eq; - _49 = std::option::Option::None; - _48 = core::panicking::assert_failed::(move _47, _42, _43, move _49) -> unwind unreachable; + _45 = core::panicking::AssertKind::Eq; + _47 = std::option::Option::None; + _46 = core::panicking::assert_failed::(move _45, _40, _41, move _47) -> unwind unreachable; } bb10: { - _56 = &_50; - _57 = &_53; - _55 = (move _56, move _57); - _58 = (_55.0: &usize); - _59 = (_55.1: &usize); - _61 = (*_58); - _62 = (*_59); - _60 = Eq(move _61, move _62); - switchInt(move _60) -> [0: bb12, otherwise: bb11]; + _54 = &_48; + _55 = &_51; + _53 = (move _54, move _55); + _56 = (_53.0: &usize); + _57 = (_53.1: &usize); + _59 = (*_56); + _60 = (*_57); + _58 = Eq(move _59, move _60); + switchInt(move _58) -> [0: bb12, otherwise: bb11]; } bb11: { return; } bb12: { - _63 = core::panicking::AssertKind::Eq; - _65 = std::option::Option::None; - _64 = core::panicking::assert_failed::(move _63, _58, _59, move _65) -> unwind unreachable; + _61 = core::panicking::AssertKind::Eq; + _63 = std::option::Option::None; + _62 = core::panicking::assert_failed::(move _61, _56, _57, move _63) -> unwind unreachable; } } fn operands::{constant#0}() -> usize { diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs index 7587042cf276..4aa75a50355b 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.rs +++ b/tests/ui/traits/const-traits/staged-api-user-crate.rs @@ -11,6 +11,7 @@ fn non_const_context() { const fn stable_const_context() { Unstable::func(); //~^ ERROR cannot call conditionally-const associated function `::func` in constant functions + //~| ERROR `staged_api::MyTrait` is not yet stable as a const trait } fn main() {} diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index 400c76fcaf49..8ac83770cf7a 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -9,6 +9,17 @@ LL | Unstable::func(); = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error: `staged_api::MyTrait` is not yet stable as a const trait + --> $DIR/staged-api-user-crate.rs:12:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs index 755a4e456bcf..9a030dafd6bc 100644 --- a/tests/ui/traits/const-traits/staged-api.rs +++ b/tests/ui/traits/const-traits/staged-api.rs @@ -22,7 +22,7 @@ impl const MyTrait for Foo { fn func() {} } -#[rustc_allow_const_fn_unstable(const_trait_impl)] +#[rustc_allow_const_fn_unstable(const_trait_impl, unstable)] const fn conditionally_const() { T::func(); } @@ -37,10 +37,13 @@ fn non_const_context() { const fn const_context() { Unstable::func(); //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` Foo::func(); //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` Unstable2::func(); //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` conditionally_const::(); //~^ ERROR cannot use `#[feature(const_trait_impl)]` } @@ -59,8 +62,23 @@ pub const fn const_context_not_const_stable() { const fn stable_const_context() { Unstable::func(); //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` Foo::func(); //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` + const_context_not_const_stable(); + //~^ ERROR cannot use `#[feature(local_feature)]` + conditionally_const::(); + //~^ ERROR cannot use `#[feature(const_trait_impl)]` +} + +const fn implicitly_stable_const_context() { + Unstable::func(); + //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` + Foo::func(); + //~^ ERROR cannot use `#[feature(const_trait_impl)]` + //~| ERROR cannot use `#[feature(unstable)]` const_context_not_const_stable(); //~^ ERROR cannot use `#[feature(local_feature)]` conditionally_const::(); diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr index acc93f747a8e..a7a7a1ee7215 100644 --- a/tests/ui/traits/const-traits/staged-api.stderr +++ b/tests/ui/traits/const-traits/staged-api.stderr @@ -15,8 +15,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:38:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn const_context() { + | + error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` - --> $DIR/staged-api.rs:40:5 + --> $DIR/staged-api.rs:41:5 | LL | Foo::func(); | ^^^^^^^^^^^ @@ -32,8 +49,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:41:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn const_context() { + | + error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` - --> $DIR/staged-api.rs:42:5 + --> $DIR/staged-api.rs:44:5 | LL | Unstable2::func(); | ^^^^^^^^^^^^^^^^^ @@ -49,9 +83,26 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` --> $DIR/staged-api.rs:44:5 | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:47:5 + | LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -67,7 +118,7 @@ LL | const fn const_context() { | error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` - --> $DIR/staged-api.rs:60:5 + --> $DIR/staged-api.rs:63:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ @@ -83,8 +134,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:63:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn stable_const_context() { + | + error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` - --> $DIR/staged-api.rs:62:5 + --> $DIR/staged-api.rs:66:5 | LL | Foo::func(); | ^^^^^^^^^^^ @@ -100,8 +168,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:66:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn stable_const_context() { + | + error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` - --> $DIR/staged-api.rs:64:5 + --> $DIR/staged-api.rs:69:5 | LL | const_context_not_const_stable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +204,7 @@ LL | const fn stable_const_context() { | error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` - --> $DIR/staged-api.rs:66:5 + --> $DIR/staged-api.rs:71:5 | LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,5 +220,108 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | -error: aborting due to 8 previous errors +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:76:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn implicitly_stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn implicitly_stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:76:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn implicitly_stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn implicitly_stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:79:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn implicitly_stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn implicitly_stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:79:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn implicitly_stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn implicitly_stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:82:5 + | +LL | const_context_not_const_stable(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn implicitly_stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local_feature)] +LL | const fn implicitly_stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:84:5 + | +LL | conditionally_const::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn implicitly_stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn implicitly_stable_const_context() { + | + +error: aborting due to 19 previous errors diff --git a/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs b/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs new file mode 100644 index 000000000000..25649d929032 --- /dev/null +++ b/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs @@ -0,0 +1,52 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +// When type checking a closure expr we look at the list of unsolved goals +// to determine if there are any bounds on the closure type to infer a signature from. +// +// We attempt to discard goals that name the closure type so as to avoid inferring the +// closure type to something like `?x = closure(sig=fn(?x))`. This test checks that when +// such a goal names the closure type inside of an ambiguous alias and there exists another +// potential goal to infer the closure signature from, we do that. + +trait Trait<'a> { + type Assoc; +} + +impl<'a, F> Trait<'a> for F { + type Assoc = u32; +} + +fn closure_typer1(_: F) +where + F: Fn(u32) + for<'a> Fn(>::Assoc), +{ +} + +fn closure_typer2(_: F) +where + F: for<'a> Fn(>::Assoc) + Fn(u32), +{ +} + +fn main() { + // Here we have some closure with a yet to be inferred type of `?c`. There are two goals + // involving `?c` that can be used to determine the closure signature: + // - `?c: for<'a> Fn<(>::Assoc,), Output = ()>` + // - `?c: Fn<(u32,), Output = ()>` + // + // If we were to infer the argument of the closure (`x` below) to `>::Assoc` + // then we would not be able to call `x.into()` as `x` is some unknown type. Instead we must + // use the `?c: Fn(u32)` goal to infer a signature in order for this code to compile. + // + // As the algorithm for picking a goal to infer the signature from is dependent on the ordering + // of pending goals in the type checker, we test both orderings of bounds to ensure we aren't + // testing that we just *happen* to pick `?c: Fn(u32)`. + closure_typer1(move |x| { + let _: u32 = x.into(); + }); + closure_typer2(move |x| { + let _: u32 = x.into(); + }); +}