Letting rustbot assign a reviewer, so that someone can double check
9de86f40d7.

changelog: none
This commit is contained in:
Philipp Krones 2025-08-22 12:36:32 +00:00 committed by GitHub
commit 877967959a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 430 additions and 305 deletions

View file

@ -71,3 +71,7 @@ harness = false
# without increasing total build times.
[profile.dev.package.quine-mc_cluskey]
opt-level = 3
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ['cfg(bootstrap)']

View file

@ -534,6 +534,7 @@ fn get_item_name(item: &Item<'_>) -> Option<String> {
if let Some(of_trait) = im.of_trait {
let mut trait_segs: Vec<String> = of_trait
.trait_ref
.path
.segments
.iter()

View file

@ -130,18 +130,22 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
if bool_value ^ eq_macro {
let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else {
return;
if let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) {
let sugg = if bool_value ^ eq_macro {
!sugg.maybe_paren()
} else if ty::Bool == *non_lit_ty.kind() {
sugg
} else {
!!sugg.maybe_paren()
};
suggestions.push((non_lit_expr.span, (!sugg).to_string()));
}
suggestions.push((non_lit_expr.span, sugg.to_string()));
diag.multipart_suggestion(
format!("replace it with `{non_eq_mac}!(..)`"),
suggestions,
Applicability::MachineApplicable,
);
diag.multipart_suggestion(
format!("replace it with `{non_eq_mac}!(..)`"),
suggestions,
Applicability::MachineApplicable,
);
}
},
);
}

View file

@ -37,12 +37,12 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
impl<'tcx> LateLintPass<'tcx> for CopyIterator {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = item.kind
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& is_copy(cx, ty)
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Iterator, trait_id)
{
span_lint_and_note(

View file

@ -183,14 +183,14 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items: [child],
self_ty,
..
}) = item.kind
&& !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& !item.span.from_expansion()
&& let Some(def_id) = trait_ref.trait_def_id()
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Default, def_id)
&& let impl_item_hir = child.hir_id()
&& let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)

View file

@ -201,10 +201,11 @@ declare_lint_pass!(Derive => [
impl<'tcx> LateLintPass<'tcx> for Derive {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = item.kind
{
let trait_ref = &of_trait.trait_ref;
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());

View file

@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
impl EarlyLintPass for DuplicateMod {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind
if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No { .. }, mod_spans)) = &item.kind
&& let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
&& let Some(local_path) = real.into_local_path()
&& let Ok(absolute_path) = local_path.canonicalize()

View file

@ -36,11 +36,11 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
impl LateLintPass<'_> for EmptyDrop {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items: [child],
..
}) = item.kind
&& trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
&& of_trait.trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
&& let impl_item_hir = child.hir_id()
&& let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
&& let ImplItemKind::Fn(_, b) = &impl_item.kind

View file

@ -442,7 +442,7 @@ impl EmptyLineAfter {
None => span.shrink_to_lo(),
},
mod_items: match kind {
ItemKind::Mod(_, _, ModKind::Loaded(items, _, _, _)) => items
ItemKind::Mod(_, _, ModKind::Loaded(items, _, _)) => items
.iter()
.filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
.map(|i| i.id)

View file

@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
);
},
ItemKind::Impl(imp)
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id())
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
&& error_def_id == trait_def_id
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)

View file

@ -164,7 +164,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
}
match &item.kind {
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => {
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
self.nest_level += 1;
if !self.check_indent(item.span, item.id) {

View file

@ -254,10 +254,10 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio
if impl_item.ident.name == sym::fmt
&& let ImplItemKind::Fn(_, body_id) = impl_item.kind
&& let Some(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = get_parent_as_impl(cx.tcx, impl_item.hir_id())
&& let Some(did) = trait_ref.trait_def_id()
&& let Some(did) = of_trait.trait_ref.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(did)
&& matches!(name, sym::Debug | sym::Display)
{

View file

@ -67,12 +67,12 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
impl<'tcx> LateLintPass<'tcx> for FromOverInto {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(hir_trait_ref),
of_trait: Some(of_trait),
self_ty,
items: [impl_item_ref],
..
}) = item.kind
&& let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
&& let Some(into_trait_seg) = of_trait.trait_ref.path.segments.last()
// `impl Into<target_ty> for self_ty`
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
&& span_is_local(item.span)

View file

@ -54,8 +54,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
if let ImplItemKind::Fn(_, body_id) = impl_item.kind
&& let hir::Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
&& let hir::ItemKind::Impl(impl_) = item.kind
&& let hir::Impl { of_trait, .. } = *impl_
&& of_trait.is_none()
&& let hir::Impl { of_trait: None, .. } = impl_
&& let body = cx.tcx.hir_body(body_id)
&& cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
&& !is_in_test(cx.tcx, impl_item.hir_id())

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::hir_id::OwnerId;
use rustc_hir::{ImplItem, ImplItemKind, ItemKind, Node, TraitRef};
use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node, TraitRef};
use rustc_lint::LateContext;
use rustc_span::Span;
use rustc_span::symbol::{Ident, kw};
@ -15,10 +15,12 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
&& let ImplItemKind::Fn(_, body_id) = item.kind
&& let parent_node = cx.tcx.parent_hir_node(item.hir_id())
&& let Node::Item(parent_item) = parent_node
&& let ItemKind::Impl(impl_) = &parent_item.kind
&& let Some(trait_ref) = impl_.of_trait
&& let ItemKind::Impl(Impl {
of_trait: Some(of_trait),
..
}) = &parent_item.kind
&& let Some(did) = trait_item_def_id_of_impl(cx, item.owner_id)
&& !is_from_ignored_trait(&trait_ref, ignored_traits)
&& !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits)
{
let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id);
let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied();

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Item, ItemKind, Path, TraitRef};
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::declare_lint_pass;
@ -76,10 +76,10 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes {
/// three of `Hash`, `Borrow<str>` and `Borrow<[u8]>`.
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Impl(imp) = item.kind
&& let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait
&& let Some(of_trait) = imp.of_trait
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash)
&& Res::Def(DefKind::Trait, hash_id) == *res
&& Res::Def(DefKind::Trait, hash_id) == of_trait.trait_ref.path.res
&& let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow)
// since we are in the `Hash` impl, we don't need to check for that.
// we need only to check for `Borrow<str>` and `Borrow<[u8]>`
@ -89,7 +89,7 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes {
span_lint_and_then(
cx,
IMPL_HASH_BORROW_WITH_STR_AND_BYTES,
*span,
of_trait.trait_ref.path.span,
"the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented",
|diag| {
diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T>");

View file

@ -45,8 +45,8 @@ declare_lint_pass!(InfallibleTryFrom => [INFALLIBLE_TRY_FROM]);
impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
let ItemKind::Impl(imp) = item.kind else { return };
let Some(r#trait) = imp.of_trait else { return };
let Some(trait_def_id) = r#trait.trait_def_id() else {
let Some(of_trait) = imp.of_trait else { return };
let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
return;
};
if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) {

View file

@ -8,7 +8,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::MacroKind;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@ -503,8 +502,8 @@ impl LateLintPass<'_> for ItemNameRepetitions {
);
}
let is_macro_rule = matches!(item.kind, ItemKind::Macro(_, _, MacroKind::Bang));
if both_are_public && item_camel.len() > mod_camel.len() && !is_macro_rule {
let is_macro = matches!(item.kind, ItemKind::Macro(_, _, _));
if both_are_public && item_camel.len() > mod_camel.len() && !is_macro {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();

View file

@ -125,8 +125,9 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
if let ItemKind::Impl(imp) = item.kind
&& let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
&& let Some(trait_ref) = imp.of_trait
&& trait_ref
&& let Some(of_trait) = imp.of_trait
&& of_trait
.trait_ref
.trait_def_id()
.is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
&& !item.span.in_external_macro(cx.sess().source_map())

View file

@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
} = item.kind
{
check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv);
} else if let ItemKind::Impl(impl_) = item.kind
} else if let ItemKind::Impl(impl_) = &item.kind
&& !item.span.from_expansion()
{
report_extra_impl_lifetimes(cx, impl_);
@ -712,8 +712,8 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, impl_.generics);
walk_generics(&mut checker, impl_.generics);
if let Some(ref trait_ref) = impl_.of_trait {
walk_trait_ref(&mut checker, trait_ref);
if let Some(of_trait) = impl_.of_trait {
walk_trait_ref(&mut checker, &of_trait.trait_ref);
}
walk_unambig_ty(&mut checker, impl_.self_ty);
for &item in impl_.items {

View file

@ -11,7 +11,7 @@ use rustc_ast::{BinOpKind, LitKind, RangeLimits};
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::unhash::UnindexMap;
use rustc_errors::{Applicability, Diag};
use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
use rustc_hir::{Body, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
@ -135,12 +135,12 @@ fn assert_len_expr<'hir>(
cx: &LateContext<'_>,
expr: &'hir Expr<'hir>,
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
&& let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
let (cmp, asserted_len, slice_len) = if let Some(
higher::IfLetOrMatch::Match(cond, [_, then], _)
) = higher::IfLetOrMatch::parse(cx, expr)
&& let ExprKind::Binary(bin_op, left, right) = &cond.kind
// check if `then` block has a never type expression
&& let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
&& cx.typeck_results().expr_ty(then_expr).is_never()
&& cx.typeck_results().expr_ty(then.body).is_never()
{
len_comparison(bin_op.node, left, right)?
} else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| {

View file

@ -198,8 +198,8 @@ fn check_struct<'tcx>(
impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// is this an `impl Debug for X` block?
if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, .. }) = item.kind
&& let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res
if let ItemKind::Impl(Impl { of_trait: Some(of_trait), self_ty, .. }) = item.kind
&& let Res::Def(DefKind::Trait, trait_def_id) = of_trait.trait_ref.path.res
&& let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind
// make sure that the self type is either a struct, an enum or a union
// this prevents ICEs such as when self is a type parameter or a primitive type

View file

@ -190,5 +190,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
/// and a rustc warning would be triggered, see #15301
fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool {
let attrs = cx.tcx.codegen_fn_attrs(def_id);
attrs.contains_extern_indicator()
attrs.contains_extern_indicator(cx.tcx, def_id)
}

View file

@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
&& span_is_local(item.span)
&& let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
{
let trait_item_ids: DefIdSet = cx
.tcx

View file

@ -778,7 +778,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id())
&& let ItemKind::Impl(impl_block) = parent_item.kind
&& let Some(of_trait) = impl_block.of_trait
&& let Some(trait_id) = of_trait.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
{
// Replace all instances of `<Self as Trait>::AssocType` with the
// unit type and check again. If the result is the same then the

View file

@ -83,10 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
if !item.span.in_external_macro(cx.tcx.sess.source_map())
&& let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
&& let ItemKind::Impl(hir_impl) = &item.kind
&& let Some(trait_ref) = &hir_impl.of_trait
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(of_trait) = &hir_impl.of_trait
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
&& send_trait == trait_id
&& hir_impl.polarity == ImplPolarity::Positive
&& of_trait.polarity == ImplPolarity::Positive
&& let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
&& let self_ty = ty_trait_ref.instantiate_identity().self_ty()
&& let ty::Adt(adt_def, impl_trait_args) = self_ty.kind()

View file

@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::Msrv;
use clippy_utils::qualify_min_const_fn::is_stable_const_fn;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::for_each_expr_without_closures;
@ -21,7 +20,7 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>,
assignee: &'tcx hir::Expr<'_>,
e: &'tcx hir::Expr<'_>,
msrv: Msrv,
_msrv: Msrv,
) {
if let hir::ExprKind::Binary(op, l, r) = &e.kind {
let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
@ -45,10 +44,8 @@ pub(super) fn check<'tcx>(
}
// Skip if the trait is not stable in const contexts
if is_in_const_context(cx)
&& let Some(binop_id) = cx.tcx.associated_item_def_ids(trait_id).first()
&& !is_stable_const_fn(cx, *binop_id, msrv)
{
// FIXME: reintroduce a better check after this is merged back into Clippy
if is_in_const_context(cx) {
return;
}

View file

@ -183,7 +183,7 @@ fn in_impl<'tcx>(
&& let item = cx.tcx.hir_expect_item(impl_def_id.expect_local())
&& let ItemKind::Impl(item) = &item.kind
&& let Some(of_trait) = &item.of_trait
&& let Some(seg) = of_trait.path.segments.last()
&& let Some(seg) = of_trait.trait_ref.path.segments.last()
&& let Res::Def(_, trait_id) = seg.res
&& trait_id == bin_op
&& let Some(generic_args) = seg.args

View file

@ -34,15 +34,15 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]);
impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items: impl_items,
..
}) = item.kind
&& !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& let Some(eq_trait) = cx.tcx.lang_items().eq_trait()
&& trait_ref.path.res.def_id() == eq_trait
&& of_trait.trait_ref.path.res.def_id() == eq_trait
{
for impl_item in *impl_items {
for impl_item in impl_items {
if cx.tcx.item_name(impl_item.owner_id) == sym::ne {
span_lint_hir(
cx,

View file

@ -7,7 +7,6 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::hygiene::MacroKind;
declare_clippy_lint! {
/// ### What it does
@ -89,8 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
// We ignore macro exports. And `ListStem` uses, which aren't interesting.
fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
if let ItemKind::Use(path, kind) = item.kind {
let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(MacroKind::Bang), _)))
|| kind == UseKind::ListStem;
let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) || kind == UseKind::ListStem;
if ignore {
return true;
}

View file

@ -68,9 +68,9 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
let existing_name = map.get_mut(res).unwrap();
match of_trait {
Some(trait_ref) => {
Some(of_trait) => {
let mut methods_in_trait: BTreeSet<Symbol> = if let Node::TraitRef(TraitRef { path, .. }) =
cx.tcx.hir_node(trait_ref.hir_ref_id)
cx.tcx.hir_node(of_trait.trait_ref.hir_ref_id)
&& let Res::Def(DefKind::Trait, did) = path.res
{
// FIXME: if

View file

@ -26,16 +26,16 @@ declare_lint_pass!(SerdeApi => [SERDE_API_MISUSE]);
impl<'tcx> LateLintPass<'tcx> for SerdeApi {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items,
..
}) = item.kind
{
let did = trait_ref.path.res.def_id();
let did = of_trait.trait_ref.path.res.def_id();
if paths::SERDE_DE_VISITOR.matches(cx, did) {
let mut seen_str = None;
let mut seen_string = None;
for item in *items {
for item in items {
match cx.tcx.item_name(item.owner_id) {
sym::visit_str => seen_str = Some(cx.tcx.def_span(item.owner_id)),
sym::visit_string => seen_string = Some(cx.tcx.def_span(item.owner_id)),

View file

@ -1,6 +1,5 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use rustc_ast::node_id::{NodeId, NodeMap};
use rustc_ast::ptr::P;
use rustc_ast::visit::{Visitor, walk_expr};
use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind};
use rustc_errors::Applicability;
@ -124,7 +123,7 @@ impl Visitor<'_> for ImportUsageVisitor {
}
impl SingleComponentPathImports {
fn check_mod(&mut self, items: &[P<Item>]) {
fn check_mod(&mut self, items: &[Box<Item>]) {
// keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example
// below. Removing the `use crypto_hash;` would make this a compile error
// ```

View file

@ -48,10 +48,10 @@ declare_lint_pass!(ToStringTraitImpl => [TO_STRING_TRAIT_IMPL]);
impl<'tcx> LateLintPass<'tcx> for ToStringTraitImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'tcx>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = it.kind
&& let Some(trait_did) = trait_ref.trait_def_id()
&& let Some(trait_did) = of_trait.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::ToString, trait_did)
{
span_lint_and_help(

View file

@ -137,9 +137,9 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt
// We exclude `impl` blocks generated from rustc's proc macros.
&& !cx.tcx.is_automatically_derived(owner_id.to_def_id())
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
&& let Some(of_trait) = impl_.of_trait
{
trait_.trait_def_id()
of_trait.trait_ref.trait_def_id()
} else {
None
}
@ -242,8 +242,8 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local
// We exclude `impl` blocks generated from rustc's proc macros.
&& !cx.tcx.is_automatically_derived(owner_id.to_def_id())
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
&& let Some(trait_def_id) = trait_.trait_def_id()
&& let Some(of_trait) = impl_.of_trait
&& let Some(trait_def_id) = of_trait.trait_ref.trait_def_id()
// The trait is `ToString`.
&& cx.tcx.is_diagnostic_item(sym::ToString, trait_def_id)
{

View file

@ -8,7 +8,7 @@ use clippy_utils::source::walk_span_to_context;
use clippy_utils::visitors::{Descend, for_each_expr};
use hir::HirId;
use rustc_hir as hir;
use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
use rustc_hir::{Block, BlockCheckMode, Impl, ItemKind, Node, UnsafeSource};
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
@ -202,79 +202,41 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
};
let item_has_safety_comment = item_has_safety_comment(cx, item);
match (&item.kind, item_has_safety_comment) {
// lint unsafe impl without safety comment
(ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => {
if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
&& !is_unsafe_from_proc_macro(cx, item.span)
{
let source_map = cx.tcx.sess.source_map();
let span = if source_map.is_multiline(item.span) {
source_map.span_until_char(item.span, '\n')
} else {
item.span
};
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
span_lint_and_then(
cx,
UNDOCUMENTED_UNSAFE_BLOCKS,
span,
"unsafe impl missing a safety comment",
|diag| {
diag.help("consider adding a safety comment on the preceding line");
},
);
}
},
// lint safe impl with unnecessary safety comment
(ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
let (span, help_span) = mk_spans(pos);
span_lint_and_then(
cx,
UNNECESSARY_SAFETY_COMMENT,
span,
"impl has unnecessary safety comment",
|diag| {
diag.span_help(help_span, "consider removing the safety comment");
},
);
}
},
(ItemKind::Impl(_), _) => {},
// const and static items only need a safety comment if their body is an unsafe block, lint otherwise
(&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
let body = cx.tcx.hir_body(body);
if !matches!(
body.value.kind, hir::ExprKind::Block(block, _)
if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
) {
let (span, help_span) = mk_spans(pos);
span_lint_and_then(
cx,
UNNECESSARY_SAFETY_COMMENT,
span,
format!(
"{} has unnecessary safety comment",
cx.tcx.def_descr(item.owner_id.to_def_id()),
),
|diag| {
diag.span_help(help_span, "consider removing the safety comment");
},
);
}
}
},
// Aside from unsafe impls and consts/statics with an unsafe block, items in general
// do not have safety invariants that need to be documented, so lint those.
(_, HasSafetyComment::Yes(pos)) => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
let (span, help_span) = mk_spans(pos);
match item_has_safety_comment {
HasSafetyComment::Yes(pos) => check_has_safety_comment(cx, item, mk_spans(pos)),
HasSafetyComment::No => check_has_no_safety_comment(cx, item),
HasSafetyComment::Maybe => {},
}
}
}
fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span)) {
match &item.kind {
ItemKind::Impl(Impl {
of_trait: Some(of_trait),
..
}) if of_trait.safety.is_safe() => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
span_lint_and_then(
cx,
UNNECESSARY_SAFETY_COMMENT,
span,
"impl has unnecessary safety comment",
|diag| {
diag.span_help(help_span, "consider removing the safety comment");
},
);
}
},
ItemKind::Impl(_) => {},
// const and static items only need a safety comment if their body is an unsafe block, lint otherwise
&ItemKind::Const(.., body) | &ItemKind::Static(.., body) => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
let body = cx.tcx.hir_body(body);
if !matches!(
body.value.kind, hir::ExprKind::Block(block, _)
if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
) {
span_lint_and_then(
cx,
UNNECESSARY_SAFETY_COMMENT,
@ -288,12 +250,56 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
},
);
}
},
_ => (),
}
}
},
// Aside from unsafe impls and consts/statics with an unsafe block, items in general
// do not have safety invariants that need to be documented, so lint those.
_ => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
span_lint_and_then(
cx,
UNNECESSARY_SAFETY_COMMENT,
span,
format!(
"{} has unnecessary safety comment",
cx.tcx.def_descr(item.owner_id.to_def_id()),
),
|diag| {
diag.span_help(help_span, "consider removing the safety comment");
},
);
}
},
}
}
fn check_has_no_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(of_trait),
..
}) = item.kind
&& of_trait.safety.is_unsafe()
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
&& !is_unsafe_from_proc_macro(cx, item.span)
{
let source_map = cx.tcx.sess.source_map();
let span = if source_map.is_multiline(item.span) {
source_map.span_until_char(item.span, '\n')
} else {
item.span
};
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
span_lint_and_then(
cx,
UNDOCUMENTED_UNSAFE_BLOCKS,
span,
"unsafe impl missing a safety comment",
|diag| {
diag.help("consider adding a safety comment on the preceding line");
},
);
}
}
fn expr_has_unnecessary_safety_comment<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'tcx>,

View file

@ -7,13 +7,14 @@ use clippy_utils::msrvs::{self, MsrvStack};
use clippy_utils::over;
use rustc_ast::PatKind::*;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind};
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::DUMMY_SP;
// import needed to shadow `PatKind::Box` glob-imported above
use std::boxed::Box;
use std::cell::Cell;
use std::mem;
use thin_vec::{ThinVec, thin_vec};
@ -97,7 +98,7 @@ fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
return;
}
let mut pat = P(pat.clone());
let mut pat = Box::new(pat.clone());
// Nix all the paren patterns everywhere so that they aren't in our way.
remove_all_parens(&mut pat);
@ -119,7 +120,7 @@ fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
}
/// Remove all `(p)` patterns in `pat`.
fn remove_all_parens(pat: &mut P<Pat>) {
fn remove_all_parens(pat: &mut Box<Pat>) {
#[derive(Default)]
struct Visitor {
/// If is not in the outer most pattern. This is needed to avoid removing the outermost
@ -142,7 +143,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
}
/// Insert parens where necessary according to Rust's precedence rules for patterns.
fn insert_necessary_parens(pat: &mut P<Pat>) {
fn insert_necessary_parens(pat: &mut Box<Pat>) {
struct Visitor;
impl MutVisitor for Visitor {
fn visit_pat(&mut self, pat: &mut Pat) {
@ -154,7 +155,7 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, // `&(mut x)`
_ => return,
};
target.kind = Paren(P(take_pat(target)));
target.kind = Paren(Box::new(take_pat(target)));
}
}
Visitor.visit_pat(pat);
@ -162,7 +163,7 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
/// Unnest or-patterns `p0 | ... | p1` in the pattern `pat`.
/// For example, this would transform `Some(0) | FOO | Some(2)` into `Some(0 | 2) | FOO`.
fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
fn unnest_or_patterns(pat: &mut Box<Pat>) -> bool {
struct Visitor {
changed: bool,
}
@ -222,7 +223,7 @@ macro_rules! always_pat {
/// Focus on `focus_idx` in `alternatives`,
/// attempting to extend it with elements of the same constructor `C`
/// in `alternatives[focus_idx + 1..]`.
fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: usize) -> bool {
fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx: usize) -> bool {
// Extract the kind; we'll need to make some changes in it.
let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, Wild);
// We'll focus on `alternatives[focus_idx]`,
@ -283,14 +284,14 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|k, ps1, idx| matches!(
k,
TupleStruct(qself2, path2, ps2)
if eq_maybe_qself(qself1.as_ref(), qself2.as_ref())
if eq_maybe_qself(qself1.as_deref(), qself2.as_deref())
&& eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
),
|k| always_pat!(k, TupleStruct(_, _, ps) => ps),
),
// Transform a record pattern `S { fp_0, ..., fp_n }`.
Struct(qself1, path1, fps1, rest1) => {
extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives)
extend_with_struct_pat(qself1.as_deref(), path1, fps1, *rest1, start, alternatives)
},
};
@ -303,12 +304,12 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
fn extend_with_struct_pat(
qself1: Option<&P<ast::QSelf>>,
qself1: Option<&ast::QSelf>,
path1: &ast::Path,
fps1: &mut [ast::PatField],
rest1: ast::PatFieldsRest,
start: usize,
alternatives: &mut ThinVec<P<Pat>>,
alternatives: &mut ThinVec<Box<Pat>>,
) -> bool {
(0..fps1.len()).any(|idx| {
let pos_in_2 = Cell::new(None); // The element `k`.
@ -318,7 +319,7 @@ fn extend_with_struct_pat(
|k| {
matches!(k, Struct(qself2, path2, fps2, rest2)
if rest1 == *rest2 // If one struct pattern has `..` so must the other.
&& eq_maybe_qself(qself1, qself2.as_ref())
&& eq_maybe_qself(qself1, qself2.as_deref())
&& eq_path(path1, path2)
&& fps1.len() == fps2.len()
&& fps1.iter().enumerate().all(|(idx_1, fp1)| {
@ -346,11 +347,11 @@ fn extend_with_struct_pat(
/// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post),
/// where `~` denotes semantic equality.
fn extend_with_matching_product(
targets: &mut [P<Pat>],
targets: &mut [Box<Pat>],
start: usize,
alternatives: &mut ThinVec<P<Pat>>,
predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool,
extract: impl Fn(PatKind) -> ThinVec<P<Pat>>,
alternatives: &mut ThinVec<Box<Pat>>,
predicate: impl Fn(&PatKind, &[Box<Pat>], usize) -> bool,
extract: impl Fn(PatKind) -> ThinVec<Box<Pat>>,
) -> bool {
(0..targets.len()).any(|idx| {
let tail_or = drain_matching(
@ -377,14 +378,14 @@ fn take_pat(from: &mut Pat) -> Pat {
/// Extend `target` as an or-pattern with the alternatives
/// in `tail_or` if there are any and return if there were.
fn extend_with_tail_or(target: &mut Pat, tail_or: ThinVec<P<Pat>>) -> bool {
fn extend(target: &mut Pat, mut tail_or: ThinVec<P<Pat>>) {
fn extend_with_tail_or(target: &mut Pat, tail_or: ThinVec<Box<Pat>>) -> bool {
fn extend(target: &mut Pat, mut tail_or: ThinVec<Box<Pat>>) {
match target {
// On an existing or-pattern in the target, append to it.
Pat { kind: Or(ps), .. } => ps.append(&mut tail_or),
// Otherwise convert the target to an or-pattern.
target => {
let mut init_or = thin_vec![P(take_pat(target))];
let mut init_or = thin_vec![Box::new(take_pat(target))];
init_or.append(&mut tail_or);
target.kind = Or(init_or);
},
@ -403,10 +404,10 @@ fn extend_with_tail_or(target: &mut Pat, tail_or: ThinVec<P<Pat>>) -> bool {
// Only elements beginning with `start` are considered for extraction.
fn drain_matching(
start: usize,
alternatives: &mut ThinVec<P<Pat>>,
alternatives: &mut ThinVec<Box<Pat>>,
predicate: impl Fn(&PatKind) -> bool,
extract: impl Fn(PatKind) -> P<Pat>,
) -> ThinVec<P<Pat>> {
extract: impl Fn(PatKind) -> Box<Pat>,
) -> ThinVec<Box<Pat>> {
let mut tail_or = ThinVec::new();
let mut idx = 0;
@ -438,15 +439,15 @@ fn drain_matching(
fn extend_with_matching(
target: &mut Pat,
start: usize,
alternatives: &mut ThinVec<P<Pat>>,
alternatives: &mut ThinVec<Box<Pat>>,
predicate: impl Fn(&PatKind) -> bool,
extract: impl Fn(PatKind) -> P<Pat>,
extract: impl Fn(PatKind) -> Box<Pat>,
) -> bool {
extend_with_tail_or(target, drain_matching(start, alternatives, predicate, extract))
}
/// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`?
fn eq_pre_post(ps1: &[P<Pat>], ps2: &[P<Pat>], idx: usize) -> bool {
fn eq_pre_post(ps1: &[Box<Pat>], ps2: &[Box<Pat>], idx: usize) -> bool {
ps1.len() == ps2.len()
&& ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`.
&& over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r))

View file

@ -347,10 +347,10 @@ impl<'tcx> LateLintPass<'tcx> for Write {
fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = &item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
{
cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
} else {

View file

@ -6,7 +6,8 @@ use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::Res;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{
AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind, find_attr,
AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitImplHeader, TraitRef, Ty,
TyKind, find_attr,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_lint_defs::declare_tool_lint;
@ -56,10 +57,14 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown {
// Is this an `impl` (of a certain form)?
let ItemKind::Impl(Impl {
of_trait:
Some(TraitRef {
path:
Path {
res: Res::Def(_, trait_def_id),
Some(TraitImplHeader {
trait_ref:
TraitRef {
path:
Path {
res: Res::Def(_, trait_def_id),
..
},
..
},
..

View file

@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
<!-- begin autogenerated nightly -->
```
nightly-2025-08-07
nightly-2025-08-22
```
<!-- end autogenerated nightly -->

View file

@ -5,7 +5,6 @@
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
use crate::{both, over};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, *};
use rustc_span::symbol::Ident;
use std::mem;
@ -42,21 +41,23 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
},
(Range(lf, lt, le), Range(rf, rt, re)) => {
eq_expr_opt(lf.as_ref(), rf.as_ref())
&& eq_expr_opt(lt.as_ref(), rt.as_ref())
eq_expr_opt(lf.as_deref(), rf.as_deref())
&& eq_expr_opt(lt.as_deref(), rt.as_deref())
&& eq_range_end(&le.node, &re.node)
},
(Box(l), Box(r))
| (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
(Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
(TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
eq_maybe_qself(lqself.as_deref(), rqself.as_deref())
&& eq_path(lp, rp)
&& over(lfs, rfs, |l, r| eq_pat(l, r))
},
(Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
lr == rr
&& eq_maybe_qself(lqself.as_ref(), rqself.as_ref())
&& eq_maybe_qself(lqself.as_deref(), rqself.as_deref())
&& eq_path(lp, rp)
&& unordered_over(lfs, rfs, eq_field_pat)
},
@ -83,11 +84,11 @@ pub fn eq_field_pat(l: &PatField, r: &PatField) -> bool {
&& over(&l.attrs, &r.attrs, eq_attr)
}
pub fn eq_qself(l: &P<QSelf>, r: &P<QSelf>) -> bool {
pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
l.position == r.position && eq_ty(&l.ty, &r.ty)
}
pub fn eq_maybe_qself(l: Option<&P<QSelf>>, r: Option<&P<QSelf>>) -> bool {
pub fn eq_maybe_qself(l: Option<&QSelf>, r: Option<&QSelf>) -> bool {
match (l, r) {
(Some(l), Some(r)) => eq_qself(l, r),
(None, None) => true,
@ -130,8 +131,8 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
}
}
pub fn eq_expr_opt(l: Option<&P<Expr>>, r: Option<&P<Expr>>) -> bool {
both(l, r, |l, r| eq_expr(l, r))
pub fn eq_expr_opt(l: Option<&Expr>, r: Option<&Expr>) -> bool {
both(l, r, eq_expr)
}
pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
@ -178,7 +179,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
(Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re),
(If(lc, lt, le), If(rc, rt, re)) => {
eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref())
eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref())
},
(While(lc, lt, ll), While(rc, rt, rl)) => {
eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt)
@ -202,9 +203,11 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
(Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
(TryBlock(l), TryBlock(r)) => eq_block(l, r),
(Yield(l), Yield(r)) => eq_expr_opt(l.expr(), r.expr()) && l.same_kind(r),
(Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()),
(Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()),
(Yield(l), Yield(r)) => eq_expr_opt(l.expr().map(Box::as_ref), r.expr().map(Box::as_ref)) && l.same_kind(r),
(Ret(l), Ret(r)) => eq_expr_opt(l.as_deref(), r.as_deref()),
(Break(ll, le), Break(rl, re)) => {
eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_deref(), re.as_deref())
},
(Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
(Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
eq_expr(l1, r1) && eq_expr(l2, r2)
@ -241,13 +244,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
},
(Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk,
(Range(lf, lt, ll), Range(rf, rt, rl)) => {
ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref())
ll == rl && eq_expr_opt(lf.as_deref(), rf.as_deref()) && eq_expr_opt(lt.as_deref(), rt.as_deref())
},
(AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
(Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
(Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
(Struct(lse), Struct(rse)) => {
eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref())
eq_maybe_qself(lse.qself.as_deref(), rse.qself.as_deref())
&& eq_path(&lse.path, &rse.path)
&& eq_struct_rest(&lse.rest, &rse.rest)
&& unordered_over(&lse.fields, &rse.fields, eq_field)
@ -279,8 +282,8 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
l.is_placeholder == r.is_placeholder
&& eq_pat(&l.pat, &r.pat)
&& eq_expr_opt(l.body.as_ref(), r.body.as_ref())
&& eq_expr_opt(l.guard.as_ref(), r.guard.as_ref())
&& eq_expr_opt(l.body.as_deref(), r.body.as_deref())
&& eq_expr_opt(l.guard.as_deref(), r.guard.as_deref())
&& over(&l.attrs, &r.attrs, eq_attr)
}
@ -348,7 +351,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
safety: rs,
define_opaque: _,
}),
) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()),
(
Const(box ConstItem {
defaultness: ld,
@ -371,7 +374,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
&& eq_id(*li, *ri)
&& eq_generics(lg, rg)
&& eq_ty(lt, rt)
&& eq_expr_opt(le.as_ref(), re.as_ref())
&& eq_expr_opt(le.as_deref(), re.as_deref())
},
(
Fn(box ast::Fn {
@ -404,7 +407,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
ls == rs
&& eq_id(*li, *ri)
&& match (lmk, rmk) {
(ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => {
(ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => {
linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
},
(ModKind::Unloaded, ModKind::Unloaded) => true,
@ -474,33 +477,27 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound)
},
(
Impl(box ast::Impl {
safety: lu,
polarity: lp,
defaultness: ld,
constness: lc,
Impl(ast::Impl {
generics: lg,
of_trait: lot,
self_ty: lst,
items: li,
}),
Impl(box ast::Impl {
safety: ru,
polarity: rp,
defaultness: rd,
constness: rc,
Impl(ast::Impl {
generics: rg,
of_trait: rot,
self_ty: rst,
items: ri,
}),
) => {
matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
&& matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
&& eq_defaultness(*ld, *rd)
&& matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
&& eq_generics(lg, rg)
&& both(lot.as_ref(), rot.as_ref(), |l, r| eq_path(&l.path, &r.path))
eq_generics(lg, rg)
&& both(lot.as_deref(), rot.as_deref(), |l, r| {
matches!(l.safety, Safety::Default) == matches!(r.safety, Safety::Default)
&& matches!(l.polarity, ImplPolarity::Positive) == matches!(r.polarity, ImplPolarity::Positive)
&& eq_defaultness(l.defaultness, r.defaultness)
&& matches!(l.constness, ast::Const::No) == matches!(r.constness, ast::Const::No)
&& eq_path(&l.trait_ref.path, &r.trait_ref.path)
})
&& eq_ty(lst, rst)
&& over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
},
@ -532,7 +529,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
safety: rs,
define_opaque: _,
}),
) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs,
) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs,
(
Fn(box ast::Fn {
defaultness: ld,
@ -614,7 +611,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
&& eq_id(*li, *ri)
&& eq_generics(lg, rg)
&& eq_ty(lt, rt)
&& eq_expr_opt(le.as_ref(), re.as_ref())
&& eq_expr_opt(le.as_deref(), re.as_deref())
},
(
Fn(box ast::Fn {
@ -727,10 +724,11 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
}
#[expect(clippy::ref_option, reason = "This is the type how it is stored in the AST")]
pub fn eq_opt_fn_contract(l: &Option<P<FnContract>>, r: &Option<P<FnContract>>) -> bool {
pub fn eq_opt_fn_contract(l: &Option<Box<FnContract>>, r: &Option<Box<FnContract>>) -> bool {
match (l, r) {
(Some(l), Some(r)) => {
eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref())
eq_expr_opt(l.requires.as_deref(), r.requires.as_deref())
&& eq_expr_opt(l.ensures.as_deref(), r.ensures.as_deref())
},
(None, None) => true,
(Some(_), None) | (None, Some(_)) => false,
@ -848,7 +846,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
&& eq_fn_decl(&l.decl, &r.decl)
},
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
(Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
(ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),

View file

@ -20,7 +20,7 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{
Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
};
use rustc_lint::{EarlyContext, LateContext, LintContext};
use rustc_middle::ty::TyCtxt;
@ -254,7 +254,10 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
ItemKind::Trait(_, _, Safety::Unsafe, ..)
| ItemKind::Impl(Impl {
safety: Safety::Unsafe, ..
of_trait: Some(TraitImplHeader {
safety: Safety::Unsafe, ..
}),
..
}) => (Pat::Str("unsafe"), Pat::Str("}")),
ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),

View file

@ -545,8 +545,9 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
&& let ItemKind::Impl(impl_) = &item.kind
&& let Some(of_trait) = impl_.of_trait
{
return impl_.of_trait.as_ref();
return Some(&of_trait.trait_ref);
}
None
}

View file

@ -250,18 +250,13 @@ impl<'a> PanicExpn<'a> {
};
let name = path.segments.last().unwrap().ident.name;
// This has no argument
if name == sym::panic_cold_explicit {
return Some(Self::Empty);
}
let [arg, rest @ ..] = args else {
return None;
};
let result = match name {
sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty,
sym::panic | sym::panic_str => Self::Str(arg),
sym::panic_display | sym::panic_cold_display => {
sym::panic_display => {
let ExprKind::AddrOf(_, _, e) = &arg.kind else {
return None;
};

View file

@ -241,9 +241,6 @@ generate! {
or_insert,
or_insert_with,
outer_expn,
panic_cold_display,
panic_cold_explicit,
panic_display,
panic_str,
parse,
partition,

View file

@ -460,7 +460,8 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
}
fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
if let ItemKind::Impl(i) = &self.cx.tcx.hir_item(id).kind
&& i.safety.is_unsafe()
&& let Some(of_trait) = i.of_trait
&& of_trait.safety.is_unsafe()
{
ControlFlow::Break(())
} else {

View file

@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
channel = "nightly-2025-08-07"
channel = "nightly-2025-08-22"
# end autogenerated nightly
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
profile = "minimal"

View file

@ -1,6 +1,6 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)]
#![feature(path_file_prefix)]
#![cfg_attr(bootstrap, feature(path_file_prefix))]
use std::cmp::Ordering;
use std::ffi::OsStr;

View file

@ -1,7 +1,7 @@
#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
#![warn(clippy::bool_assert_comparison)]
use std::ops::Not;
use std::ops::{Add, Not};
macro_rules! a {
() => {
@ -62,6 +62,14 @@ impl Not for ImplNotTraitWithBool {
}
}
impl Add for ImplNotTraitWithBool {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
self
}
}
#[derive(Debug)]
struct NonCopy;
@ -94,7 +102,7 @@ fn main() {
assert_eq!(a!(), "".is_empty());
assert_eq!("".is_empty(), b!());
assert_eq!(a, true);
assert!(b);
assert!(!!b);
//~^ bool_assert_comparison
assert_ne!("a".len(), 1);
@ -122,7 +130,7 @@ fn main() {
debug_assert_eq!(a!(), "".is_empty());
debug_assert_eq!("".is_empty(), b!());
debug_assert_eq!(a, true);
debug_assert!(b);
debug_assert!(!!b);
//~^ bool_assert_comparison
debug_assert_ne!("a".len(), 1);
@ -167,7 +175,7 @@ fn main() {
use debug_assert_eq as renamed;
renamed!(a, true);
debug_assert!(b);
debug_assert!(!!b);
//~^ bool_assert_comparison
let non_copy = NonCopy;
@ -199,4 +207,12 @@ fn main() {
//~^ bool_assert_comparison
debug_assert!(!"requires negation".is_empty());
//~^ bool_assert_comparison
assert!(!b);
//~^ bool_assert_comparison
assert!(!(!b));
//~^ bool_assert_comparison
assert!(!!(b + b));
//~^ bool_assert_comparison
assert!(!(b + b));
//~^ bool_assert_comparison
}

View file

@ -1,7 +1,7 @@
#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
#![warn(clippy::bool_assert_comparison)]
use std::ops::Not;
use std::ops::{Add, Not};
macro_rules! a {
() => {
@ -62,6 +62,14 @@ impl Not for ImplNotTraitWithBool {
}
}
impl Add for ImplNotTraitWithBool {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
self
}
}
#[derive(Debug)]
struct NonCopy;
@ -199,4 +207,12 @@ fn main() {
//~^ bool_assert_comparison
debug_assert_eq!("requires negation".is_empty(), false);
//~^ bool_assert_comparison
assert_eq!(!b, true);
//~^ bool_assert_comparison
assert_eq!(!b, false);
//~^ bool_assert_comparison
assert_eq!(b + b, true);
//~^ bool_assert_comparison
assert_eq!(b + b, false);
//~^ bool_assert_comparison
}

View file

@ -1,5 +1,5 @@
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:87:5
--> tests/ui/bool_assert_comparison.rs:95:5
|
LL | assert_eq!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -13,7 +13,7 @@ LL + assert!(!"a".is_empty());
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:89:5
--> tests/ui/bool_assert_comparison.rs:97:5
|
LL | assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -25,7 +25,7 @@ LL + assert!("".is_empty());
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:91:5
--> tests/ui/bool_assert_comparison.rs:99:5
|
LL | assert_eq!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -37,7 +37,7 @@ LL + assert!("".is_empty());
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:97:5
--> tests/ui/bool_assert_comparison.rs:105:5
|
LL | assert_eq!(b, true);
| ^^^^^^^^^^^^^^^^^^^
@ -45,11 +45,11 @@ LL | assert_eq!(b, true);
help: replace it with `assert!(..)`
|
LL - assert_eq!(b, true);
LL + assert!(b);
LL + assert!(!!b);
|
error: used `assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:101:5
--> tests/ui/bool_assert_comparison.rs:109:5
|
LL | assert_ne!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -61,7 +61,7 @@ LL + assert!("a".is_empty());
|
error: used `assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:103:5
--> tests/ui/bool_assert_comparison.rs:111:5
|
LL | assert_ne!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -73,7 +73,7 @@ LL + assert!(!"".is_empty());
|
error: used `assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:105:5
--> tests/ui/bool_assert_comparison.rs:113:5
|
LL | assert_ne!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -85,7 +85,7 @@ LL + assert!(!"".is_empty());
|
error: used `assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:111:5
--> tests/ui/bool_assert_comparison.rs:119:5
|
LL | assert_ne!(b, true);
| ^^^^^^^^^^^^^^^^^^^
@ -97,7 +97,7 @@ LL + assert!(!b);
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:115:5
--> tests/ui/bool_assert_comparison.rs:123:5
|
LL | debug_assert_eq!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -109,7 +109,7 @@ LL + debug_assert!(!"a".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:117:5
--> tests/ui/bool_assert_comparison.rs:125:5
|
LL | debug_assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -121,7 +121,7 @@ LL + debug_assert!("".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:119:5
--> tests/ui/bool_assert_comparison.rs:127:5
|
LL | debug_assert_eq!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -133,7 +133,7 @@ LL + debug_assert!("".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:125:5
--> tests/ui/bool_assert_comparison.rs:133:5
|
LL | debug_assert_eq!(b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -141,11 +141,11 @@ LL | debug_assert_eq!(b, true);
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!(b, true);
LL + debug_assert!(b);
LL + debug_assert!(!!b);
|
error: used `debug_assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:129:5
--> tests/ui/bool_assert_comparison.rs:137:5
|
LL | debug_assert_ne!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -157,7 +157,7 @@ LL + debug_assert!("a".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:131:5
--> tests/ui/bool_assert_comparison.rs:139:5
|
LL | debug_assert_ne!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -169,7 +169,7 @@ LL + debug_assert!(!"".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:133:5
--> tests/ui/bool_assert_comparison.rs:141:5
|
LL | debug_assert_ne!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -181,7 +181,7 @@ LL + debug_assert!(!"".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:139:5
--> tests/ui/bool_assert_comparison.rs:147:5
|
LL | debug_assert_ne!(b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -193,7 +193,7 @@ LL + debug_assert!(!b);
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:145:5
--> tests/ui/bool_assert_comparison.rs:153:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -205,7 +205,7 @@ LL + assert!(!"a".is_empty(), "tadam {}", 1);
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:147:5
--> tests/ui/bool_assert_comparison.rs:155:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -217,7 +217,7 @@ LL + assert!(!"a".is_empty(), "tadam {}", true);
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:149:5
--> tests/ui/bool_assert_comparison.rs:157:5
|
LL | assert_eq!(false, "a".is_empty(), "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -229,7 +229,7 @@ LL + assert!(!"a".is_empty(), "tadam {}", true);
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:155:5
--> tests/ui/bool_assert_comparison.rs:163:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -241,7 +241,7 @@ LL + debug_assert!(!"a".is_empty(), "tadam {}", 1);
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:157:5
--> tests/ui/bool_assert_comparison.rs:165:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -253,7 +253,7 @@ LL + debug_assert!(!"a".is_empty(), "tadam {}", true);
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:159:5
--> tests/ui/bool_assert_comparison.rs:167:5
|
LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -265,31 +265,35 @@ LL + debug_assert!(!"a".is_empty(), "tadam {}", true);
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:163:5
--> tests/ui/bool_assert_comparison.rs:171:5
|
LL | assert_eq!(a!(), true);
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(a!(), true);
LL + assert!(a!());
LL | true
...
LL |
LL ~ assert!(a!());
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:165:5
--> tests/ui/bool_assert_comparison.rs:173:5
|
LL | assert_eq!(true, b!());
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(true, b!());
LL + assert!(b!());
LL | true
...
LL |
LL ~ assert!(b!());
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:170:5
--> tests/ui/bool_assert_comparison.rs:178:5
|
LL | renamed!(b, true);
| ^^^^^^^^^^^^^^^^^
@ -297,11 +301,11 @@ LL | renamed!(b, true);
help: replace it with `debug_assert!(..)`
|
LL - renamed!(b, true);
LL + debug_assert!(b);
LL + debug_assert!(!!b);
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:185:5
--> tests/ui/bool_assert_comparison.rs:193:5
|
LL | assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -313,7 +317,7 @@ LL + assert!("".is_empty());
|
error: used `assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:187:5
--> tests/ui/bool_assert_comparison.rs:195:5
|
LL | assert_ne!("".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -325,7 +329,7 @@ LL + assert!("".is_empty());
|
error: used `assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:189:5
--> tests/ui/bool_assert_comparison.rs:197:5
|
LL | assert_ne!("requires negation".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -337,7 +341,7 @@ LL + assert!(!"requires negation".is_empty());
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:191:5
--> tests/ui/bool_assert_comparison.rs:199:5
|
LL | assert_eq!("requires negation".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -349,7 +353,7 @@ LL + assert!(!"requires negation".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:194:5
--> tests/ui/bool_assert_comparison.rs:202:5
|
LL | debug_assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -361,7 +365,7 @@ LL + debug_assert!("".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:196:5
--> tests/ui/bool_assert_comparison.rs:204:5
|
LL | debug_assert_ne!("".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -373,7 +377,7 @@ LL + debug_assert!("".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:198:5
--> tests/ui/bool_assert_comparison.rs:206:5
|
LL | debug_assert_ne!("requires negation".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -385,7 +389,7 @@ LL + debug_assert!(!"requires negation".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:200:5
--> tests/ui/bool_assert_comparison.rs:208:5
|
LL | debug_assert_eq!("requires negation".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -396,5 +400,53 @@ LL - debug_assert_eq!("requires negation".is_empty(), false);
LL + debug_assert!(!"requires negation".is_empty());
|
error: aborting due to 33 previous errors
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:210:5
|
LL | assert_eq!(!b, true);
| ^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(!b, true);
LL + assert!(!b);
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:212:5
|
LL | assert_eq!(!b, false);
| ^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(!b, false);
LL + assert!(!(!b));
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:214:5
|
LL | assert_eq!(b + b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(b + b, true);
LL + assert!(!!(b + b));
|
error: used `assert_eq!` with a literal bool
--> tests/ui/bool_assert_comparison.rs:216:5
|
LL | assert_eq!(b + b, false);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(b + b, false);
LL + assert!(!(b + b));
|
error: aborting due to 37 previous errors

View file

@ -330,7 +330,7 @@ LL | if X.is_some() {
|
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
= note: `#[deny(static_mut_refs)]` on by default
= note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
error: aborting due to 36 previous errors

View file

@ -196,6 +196,7 @@ fn issue_13106() {
const {
assert!(EMPTY_STR.is_empty());
//~^ const_is_empty
}
const {

View file

@ -158,10 +158,16 @@ LL | let _ = val.is_empty();
| ^^^^^^^^^^^^^^
error: this expression always evaluates to true
--> tests/ui/const_is_empty.rs:202:9
--> tests/ui/const_is_empty.rs:198:17
|
LL | assert!(EMPTY_STR.is_empty());
| ^^^^^^^^^^^^^^^^^^^^
error: this expression always evaluates to true
--> tests/ui/const_is_empty.rs:203:9
|
LL | EMPTY_STR.is_empty();
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 27 previous errors
error: aborting due to 28 previous errors

View file

@ -9,7 +9,7 @@ macro_rules! define_other_core {
}
fn main() {
core::panic!();
core::panic!(); //~ ERROR: `core` is ambiguous
}
define_other_core!();

View file

@ -9,5 +9,25 @@ LL | define_other_core!();
|
= note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
error[E0659]: `core` is ambiguous
--> tests/ui/crashes/ice-6255.rs:12:5
|
LL | core::panic!();
| ^^^^ ambiguous name
|
= note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `core` could refer to a built-in crate
note: `core` could also refer to the crate imported here
--> tests/ui/crashes/ice-6255.rs:6:9
|
LL | extern crate std as core;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | define_other_core!();
| -------------------- in this macro invocation
= help: use `crate::core` to refer to this crate unambiguously
= note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0659`.

View file

@ -3,6 +3,8 @@ error: malformed `path` attribute input
|
LL | #[path = foo!()]
| ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
|
= note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
error: aborting due to 1 previous error

View file

@ -1,6 +1,6 @@
#![warn(clippy::incompatible_msrv)]
#![feature(custom_inner_attributes)]
#![allow(stable_features)]
#![allow(stable_features, clippy::diverging_sub_expression)]
#![feature(strict_provenance)] // For use in test
#![clippy::msrv = "1.3.0"]