r? @ghost

changelog: none
This commit is contained in:
Philipp Krones 2025-07-10 18:06:14 +00:00 committed by GitHub
commit cdbbf3afda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 162 additions and 99 deletions

View file

@ -2,7 +2,6 @@
rustc_private,
exit_status_error,
if_let_guard,
let_chains,
os_str_slice,
os_string_truncate,
slice_split_once

View file

@ -74,7 +74,7 @@ impl ApproxConstant {
}
impl LateLintPass<'_> for ApproxConstant {
fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) {
fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: Lit, _negated: bool) {
match lit.node {
LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"),

View file

@ -266,7 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
.tcx
.hir_attrs(item.hir_id())
.iter()
.any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..))))
.any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr { .. })))
{
// Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API.
return;

View file

@ -9,7 +9,7 @@ use clippy_utils::msrvs::{self, Msrv};
use super::REPR_PACKED_WITHOUT_ABI;
pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: Msrv) {
if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs) {
let packed_span = reprs
.iter()
.find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..)))

View file

@ -42,7 +42,7 @@ fn extract_bool_lit(e: &Expr<'_>) -> Option<bool> {
}) = e.kind
&& !e.span.from_expansion()
{
Some(*b)
Some(b)
} else {
None
}

View file

@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
ty::FnDef(..) | ty::FnPtr(..) => {
let mut applicability = Applicability::MaybeIncorrect;
if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() {
if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() {
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
span_lint_and_sugg(
cx,

View file

@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
let mut applicability = Applicability::MaybeIncorrect;
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
if to_nbits < cx.tcx.data_layout.pointer_size().bits() {
span_lint_and_sugg(
cx,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,

View file

@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to:
fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> bool {
match expr.kind {
ExprKind::Call(fun, _) => is_align_of_call(cx, fun, to),
ExprKind::Lit(lit) => is_literal_aligned(cx, lit, to),
ExprKind::Lit(lit) => is_literal_aligned(cx, &lit, to),
_ => false,
}
}

View file

@ -243,7 +243,7 @@ fn lint_unnecessary_cast(
);
}
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<Lit> {
match expr.kind {
ExprKind::Lit(lit) => Some(lit),
ExprKind::Unary(UnOp::Neg, e) => {

View file

@ -5,7 +5,7 @@ use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
/// integral type.
pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> {
match ty.kind() {
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()),
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size().bits()),
ty::Int(i) => i.bit_width(),
ty::Uint(i) => i.bit_width(),
_ => None,

View file

@ -83,7 +83,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
}
/// Check whether a passed literal has potential to cause fallback or not.
fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
fn check_lit(&self, lit: Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
if !lit.span.in_external_macro(self.cx.sess().source_map())
&& matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
&& matches!(
@ -210,7 +210,7 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
ExprKind::Lit(lit) => {
let ty = self.cx.typeck_results().expr_ty(expr);
self.check_lit(lit, ty, expr.hir_id);
self.check_lit(*lit, ty, expr.hir_id);
return;
},

View file

@ -99,5 +99,5 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR
fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
let attrs = cx.tcx.hir_attrs(hir_id);
find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC))
find_attr!(attrs, AttributeKind::Repr { reprs, .. } if reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC))
}

View file

@ -824,7 +824,7 @@ impl TyCoercionStability {
TyKind::Slice(_)
| TyKind::Array(..)
| TyKind::Ptr(_)
| TyKind::BareFn(_)
| TyKind::FnPtr(_)
| TyKind::Pat(..)
| TyKind::Never
| TyKind::Tup(_)

View file

@ -19,7 +19,7 @@ pub fn check(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragm
}
fn warn_if_broken_link(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) {
if let Some(span) = source_span_for_markdown_range(cx.tcx, doc, &bl.span, fragments) {
if let Some((span, _)) = source_span_for_markdown_range(cx.tcx, doc, &bl.span, fragments) {
let mut len = 0;
// grab raw link data

View file

@ -795,8 +795,8 @@ impl Fragments<'_> {
/// get the span for the markdown range. Note that this function is not cheap, use it with
/// caution.
#[must_use]
fn span(&self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments)
fn span(self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments).map(|(sp, _)| sp)
}
}

View file

@ -35,7 +35,7 @@ declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
#[expect(clippy::cast_possible_wrap)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if cx.tcx.data_layout.pointer_size.bits() != 64 {
if cx.tcx.data_layout.pointer_size().bits() != 64 {
return;
}
if let ItemKind::Enum(_, _, def) = &item.kind {

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::indent_of;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -85,7 +85,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
};
if cx.effective_visibilities.is_exported(item.owner_id.def_id)
&& let attrs = cx.tcx.hir_attrs(item.hir_id())
&& !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
&& !find_attr!(attrs, AttributeKind::NonExhaustive(..))
&& fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
{
span_lint_and_then(cx, lint, item.span, msg, |diag| {

View file

@ -57,7 +57,7 @@ impl LateLintPass<'_> for LargeIncludeFile {
if let ExprKind::Lit(lit) = &expr.kind
&& let len = match &lit.node {
// include_bytes
LitKind::ByteStr(bstr, _) => bstr.len(),
LitKind::ByteStr(bstr, _) => bstr.as_byte_str().len(),
// include_str
LitKind::Str(sym, _) => sym.as_str().len(),
_ => return,

View file

@ -13,7 +13,7 @@ use rustc_hir::intravisit::{
walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_unambig_ty, walk_where_predicate,
};
use rustc_hir::{
AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
AmbigArg, BodyId, FnDecl, FnPtrTy, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, Node,
PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
WherePredicateKind, lang_items,
@ -480,7 +480,7 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx Ty<'_, AmbigArg>) {
match ty.kind {
TyKind::BareFn(&BareFnTy { decl, .. }) => {
TyKind::FnPtr(&FnPtrTy { decl, .. }) => {
let mut sub_visitor = RefVisitor::new(self.cx);
sub_visitor.visit_fn_decl(decl);
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());

View file

@ -41,12 +41,12 @@ declare_clippy_lint! {
declare_lint_pass!(ManualIgnoreCaseCmp => [MANUAL_IGNORE_CASE_CMP]);
enum MatchType<'a, 'b> {
enum MatchType<'a> {
ToAscii(bool, Ty<'a>),
Literal(&'b LitKind),
Literal(LitKind),
}
fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> {
fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Option<(Span, MatchType<'a>)> {
if let MethodCall(path, expr, _, _) = kind {
let is_lower = match path.ident.name {
sym::to_ascii_lowercase => true,
@ -63,7 +63,7 @@ fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -
return Some((expr.span, ToAscii(is_lower, ty_raw)));
}
} else if let Lit(expr) = kind {
return Some((expr.span, Literal(&expr.node)));
return Some((expr.span, Literal(expr.node)));
}
None
}

View file

@ -4,15 +4,15 @@ use clippy_utils::is_doc_hidden;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_indent;
use itertools::Itertools;
use rustc_ast::attr;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
use rustc_span::{Span, sym};
declare_clippy_lint! {
/// ### What it does
@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
.then_some((v.def_id, v.span))
});
if let Ok((id, span)) = iter.exactly_one()
&& !attr::contains_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
&& !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..))
{
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
}
@ -113,10 +113,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
item.span,
"this seems like a manual implementation of the non-exhaustive pattern",
|diag| {
if let Some(non_exhaustive) =
attr::find_by_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
if let Some(non_exhaustive_span) =
find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(span) => *span)
{
diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive");
diag.span_note(non_exhaustive_span, "the struct is already non-exhaustive");
} else {
let indent = snippet_indent(cx, item.span).unwrap_or_default();
diag.span_suggestion_verbose(

View file

@ -184,7 +184,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t
..
}) = expr.kind
{
constant_length(cx, pattern).is_some_and(|length| *n == length)
constant_length(cx, pattern).is_some_and(|length| n == length)
} else {
len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg))
}

View file

@ -159,7 +159,7 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
node: LitKind::Bool(b), ..
}) = exp.kind
{
Some(*b)
Some(b)
} else {
None
}

View file

@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExp
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol};
use super::MATCH_SAME_ARMS;
@ -193,7 +193,7 @@ enum NormalizedPat<'a> {
Or(&'a [Self]),
Path(Option<DefId>),
LitStr(Symbol),
LitBytes(&'a [u8]),
LitBytes(ByteSymbol),
LitInt(u128),
LitBool(bool),
Range(PatRange),
@ -332,7 +332,7 @@ impl<'a> NormalizedPat<'a> {
// TODO: Handle negative integers. They're currently treated as a wild match.
PatExprKind::Lit { lit, negated: false } => match lit.node {
LitKind::Str(sym, _) => Self::LitStr(sym),
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
LitKind::ByteStr(byte_sym, _) | LitKind::CStr(byte_sym, _) => Self::LitBytes(byte_sym),
LitKind::Byte(val) => Self::LitInt(val.into()),
LitKind::Char(val) => Self::LitInt(val.into()),
LitKind::Int(val, _) => Self::LitInt(val.get()),

View file

@ -76,7 +76,7 @@ fn get_open_options(
..
} = span
{
Argument::Set(*lit)
Argument::Set(lit)
} else {
// The function is called with a literal which is not a boolean literal.
// This is theoretically possible, but not very likely.

View file

@ -104,7 +104,7 @@ fn len_comparison<'hir>(
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
macro_rules! int_lit_pat {
($id:ident) => {
ExprKind::Lit(&Spanned {
ExprKind::Lit(Spanned {
node: LitKind::Int(Pu128($id), _),
..
})

View file

@ -50,7 +50,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
// function types bring a lot of overhead
TyKind::BareFn(bare) if bare.abi == ExternAbi::Rust => (50 * self.nest, 1),
TyKind::FnPtr(fn_ptr) if fn_ptr.abi == ExternAbi::Rust => (50 * self.nest, 1),
TyKind::TraitObject(param_bounds, _) => {
let has_lifetime_parameters = param_bounds.iter().any(|bound| {

View file

@ -258,7 +258,10 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
cx,
UNNECESSARY_SAFETY_COMMENT,
span,
format!("{} has unnecessary safety comment", item.kind.descr()),
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");
},
@ -276,7 +279,10 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
cx,
UNNECESSARY_SAFETY_COMMENT,
span,
format!("{} has unnecessary safety comment", item.kind.descr()),
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");
},

View file

@ -169,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
let iter = self
.unused_async_fns
.iter()
.filter(|UnusedAsyncFn { def_id, .. }| (!self.async_fns_as_value.contains(def_id)));
.filter(|UnusedAsyncFn { def_id, .. }| !self.async_fns_as_value.contains(def_id));
for fun in iter {
span_lint_hir_and_then(

View file

@ -324,7 +324,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
}
fn lit(&self, lit: &Binding<&Lit>) {
fn lit(&self, lit: &Binding<Lit>) {
let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));

View file

@ -130,7 +130,7 @@ impl LateLintPass<'_> for WildcardImports {
}
if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
&& (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments))
&& let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
&& let Some(used_imports) = cx.tcx.resolutions(()).glob_map.get(&item.owner_id.def_id)
&& !used_imports.is_empty() // Already handled by `unused_imports`
&& !used_imports.contains(&kw::Underscore)
{

View file

@ -65,7 +65,7 @@ pub struct Symbols {
impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]);
impl Symbols {
fn lit_suggestion(&self, lit: &Lit) -> Option<(Span, String)> {
fn lit_suggestion(&self, lit: Lit) -> Option<(Span, String)> {
if let LitKind::Str(name, _) = lit.node {
let sugg = if let Some((prefix, name)) = self.symbol_map.get(&name.as_u32()) {
format!("{prefix}::{name}")

View file

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

View file

@ -838,7 +838,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
(PinnedRef(ll, l), PinnedRef(rl, r)) => {
both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
},
(BareFn(l), BareFn(r)) => {
(FnPtr(l), FnPtr(r)) => {
l.safety == r.safety
&& eq_ext(&l.ext, &r.ext)
&& over(&l.generic_params, &r.generic_params, eq_generic_param)
@ -886,13 +886,13 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
(
Const {
ty: lt,
kw_span: _,
default: ld,
span: _,
},
Const {
ty: rt,
kw_span: _,
default: rd,
span: _,
},
) => eq_ty(lt, rt) && both(ld.as_ref(), rd.as_ref(), eq_anon_const),
_ => false,

View file

@ -1,5 +1,8 @@
use crate::source::SpanRangeExt;
use crate::{sym, tokenize_with_text};
use rustc_ast::attr;
use rustc_ast::attr::AttributeExt;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::Applicability;
use rustc_lexer::TokenKind;
use rustc_lint::LateContext;
@ -8,9 +11,6 @@ use rustc_session::Session;
use rustc_span::{Span, Symbol};
use std::str::FromStr;
use crate::source::SpanRangeExt;
use crate::{sym, tokenize_with_text};
/// Deprecation status of attributes known by Clippy.
pub enum DeprecationStatus {
/// Attribute is deprecated
@ -165,13 +165,14 @@ pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool {
pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
adt.is_variant_list_non_exhaustive()
|| tcx.has_attr(adt.did(), sym::non_exhaustive)
|| find_attr!(tcx.get_all_attrs(adt.did()), AttributeKind::NonExhaustive(..))
|| adt.variants().iter().any(|variant_def| {
variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive)
variant_def.is_field_list_non_exhaustive()
|| find_attr!(tcx.get_all_attrs(variant_def.def_id), AttributeKind::NonExhaustive(..))
})
|| adt
.all_fields()
.any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive))
.any(|field_def| find_attr!(tcx.get_all_attrs(field_def.did), AttributeKind::NonExhaustive(..)))
}
/// Checks if the given span contains a `#[cfg(..)]` attribute

View file

@ -372,17 +372,17 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
TyKind::BareFn(bare_fn) => (
if bare_fn.safety.is_unsafe() {
TyKind::FnPtr(fn_ptr) => (
if fn_ptr.safety.is_unsafe() {
Pat::Str("unsafe")
} else if bare_fn.abi != ExternAbi::Rust {
} else if fn_ptr.abi != ExternAbi::Rust {
Pat::Str("extern")
} else {
Pat::MultiStr(&["fn", "extern"])
},
match bare_fn.decl.output {
match fn_ptr.decl.output {
FnRetTy::DefaultReturn(_) => {
if let [.., ty] = bare_fn.decl.inputs {
if let [.., ty] = fn_ptr.decl.inputs {
ty_search_pat(ty).1
} else {
Pat::Str("(")

View file

@ -4,8 +4,6 @@
//! executable MIR bodies, so we have to do this instead.
#![allow(clippy::float_cmp)]
use std::sync::Arc;
use crate::source::{SpanRangeExt, walk_span_to_context};
use crate::{clip, is_direct_expn_of, sext, unsext};
@ -38,7 +36,7 @@ pub enum Constant<'tcx> {
/// A `String` (e.g., "abc").
Str(String),
/// A binary string (e.g., `b"abc"`).
Binary(Arc<[u8]>),
Binary(Vec<u8>),
/// A single `char` (e.g., `'a'`).
Char(char),
/// An integer's bit representation.
@ -306,7 +304,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)),
LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Arc::clone(s)),
LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(s.as_byte_str().to_vec()),
LitKind::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n.get()),
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
@ -568,7 +566,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
} else {
match &lit.node {
LitKind::Str(is, _) => Some(is.is_empty()),
LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.is_empty()),
LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.as_byte_str().is_empty()),
_ => None,
}
}
@ -916,7 +914,7 @@ fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<boo
// Get the length from the slice, using the same formula as
// [`ConstValue::try_get_slice_bytes_for_diagnostics`].
let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
let ptr_size = tcx.data_layout.pointer_size;
let ptr_size = tcx.data_layout.pointer_size();
if a.size() < offset + 2 * ptr_size {
// (partially) dangling reference
return None;

View file

@ -98,6 +98,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) {
/// 17 | std::mem::forget(seven);
/// | ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
#[track_caller]
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
#[expect(clippy::disallowed_methods)]
cx.span_lint(lint, sp, |diag| {
@ -143,6 +144,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
/// |
/// = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ```
#[track_caller]
pub fn span_lint_and_help<T: LintContext>(
cx: &T,
lint: &'static Lint,
@ -203,6 +205,7 @@ pub fn span_lint_and_help<T: LintContext>(
/// 10 | forget(&SomeStruct);
/// | ^^^^^^^^^^^
/// ```
#[track_caller]
pub fn span_lint_and_note<T: LintContext>(
cx: &T,
lint: &'static Lint,
@ -244,6 +247,7 @@ pub fn span_lint_and_note<T: LintContext>(
/// If you're unsure which function you should use, you can test if the `#[expect]` attribute works
/// where you would expect it to.
/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
#[track_caller]
pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F)
where
C: LintContext,
@ -286,6 +290,7 @@ where
/// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
/// the compiler check lint level attributes at the place of the expression and
/// the `#[allow]` will work.
#[track_caller]
pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) {
#[expect(clippy::disallowed_methods)]
cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
@ -321,6 +326,7 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s
/// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
/// the compiler check lint level attributes at the place of the expression and
/// the `#[allow]` will work.
#[track_caller]
pub fn span_lint_hir_and_then(
cx: &LateContext<'_>,
lint: &'static Lint,
@ -374,6 +380,7 @@ pub fn span_lint_hir_and_then(
/// = note: `-D fold-any` implied by `-D warnings`
/// ```
#[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))]
#[track_caller]
pub fn span_lint_and_sugg<T: LintContext>(
cx: &T,
lint: &'static Lint,

View file

@ -1282,20 +1282,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
TyKind::BareFn(bfn) => {
bfn.safety.hash(&mut self.s);
bfn.abi.hash(&mut self.s);
for arg in bfn.decl.inputs {
TyKind::FnPtr(fn_ptr) => {
fn_ptr.safety.hash(&mut self.s);
fn_ptr.abi.hash(&mut self.s);
for arg in fn_ptr.decl.inputs {
self.hash_ty(arg);
}
std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
match bfn.decl.output {
std::mem::discriminant(&fn_ptr.decl.output).hash(&mut self.s);
match fn_ptr.decl.output {
FnRetTy::DefaultReturn(_) => {},
FnRetTy::Return(ty) => {
self.hash_ty(ty);
},
}
bfn.decl.c_variadic.hash(&mut self.s);
fn_ptr.decl.c_variadic.hash(&mut self.s);
},
TyKind::Tup(ty_list) => {
for ty in *ty_list {

View file

@ -1762,7 +1762,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool {
}
pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr(..))
find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr { .. })
}
pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {

View file

@ -175,10 +175,6 @@ fn check_rvalue<'tcx>(
Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
Err((span, "casting pointers to ints is unstable in const fn".into()))
},
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar, _), _, _) => {
// FIXME(dyn-star)
unimplemented!()
},
Rvalue::Cast(CastKind::Transmute, _, _) => Err((
span,
"transmute can attempt to turn pointers into integers, so is unstable in const fn".into(),
@ -451,7 +447,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
// FIXME(const_trait_impl, fee1-dead) revert to const destruct once it works again
#[expect(unused)]
fn is_ty_const_destruct_unused<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool {
// If this doesn't need drop at all, then don't select `~const Destruct`.
// If this doesn't need drop at all, then don't select `[const] Destruct`.
if !ty.needs_drop(tcx, body.typing_env(tcx)) {
return false;
}

View file

@ -889,7 +889,7 @@ impl AdtVariantInfo {
.enumerate()
.map(|(i, f)| (i, approx_ty_size(cx, f.ty(cx.tcx, subst))))
.collect::<Vec<_>>();
fields_size.sort_by(|(_, a_size), (_, b_size)| (a_size.cmp(b_size)));
fields_size.sort_by(|(_, a_size), (_, b_size)| a_size.cmp(b_size));
Self {
ind: i,
@ -898,7 +898,7 @@ impl AdtVariantInfo {
}
})
.collect::<Vec<_>>();
variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
variants_size.sort_by(|a, b| b.size.cmp(&a.size));
variants_size
}
}

View file

@ -1,3 +1,5 @@
use crate::msrvs::Msrv;
use crate::qualify_min_const_fn::is_stable_const_fn;
use crate::ty::needs_ordered_drop;
use crate::{get_enclosing_block, path_to_local_id};
use core::ops::ControlFlow;
@ -343,13 +345,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
.cx
.qpath_res(p, hir_id)
.opt_def_id()
.is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {},
.is_some_and(|id| is_stable_const_fn(self.cx, id, Msrv::default())) => {},
ExprKind::MethodCall(..)
if self
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
.is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {},
.is_some_and(|id| is_stable_const_fn(self.cx, id, Msrv::default())) => {},
ExprKind::Binary(_, lhs, rhs)
if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
&& self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},

View file

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

View file

@ -240,7 +240,7 @@ LL | unsafe impl TrailingComment for () {} // SAFETY:
|
= help: consider adding a safety comment on the preceding line
error: constant item has unnecessary safety comment
error: constant has unnecessary safety comment
--> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5
|
LL | const BIG_NUMBER: i32 = 1000000;

View file

@ -240,7 +240,7 @@ LL | unsafe impl TrailingComment for () {} // SAFETY:
|
= help: consider adding a safety comment on the preceding line
error: constant item has unnecessary safety comment
error: constant has unnecessary safety comment
--> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5
|
LL | const BIG_NUMBER: i32 = 1000000;

View file

@ -91,7 +91,7 @@ mod issue14871 {
impl<T> const NumberConstants for T
where
T: Number + ~const core::ops::Add,
T: Number + [const] core::ops::Add,
{
fn constant(value: usize) -> Self {
let mut res = Self::ZERO;

View file

@ -91,7 +91,7 @@ mod issue14871 {
impl<T> const NumberConstants for T
where
T: Number + ~const core::ops::Add,
T: Number + [const] core::ops::Add,
{
fn constant(value: usize) -> Self {
let mut res = Self::ZERO;

View file

@ -0,0 +1,23 @@
//@compile-flags: -Z track-diagnostics
//@no-rustfix
// Normalize the emitted location so this doesn't need
// updating everytime someone adds or removes a line.
//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC"
//@normalize-stderr-test: "src/tools/clippy/" -> ""
#![warn(clippy::let_and_return, clippy::unnecessary_cast)]
fn main() {
// Check the provenance of a lint sent through `LintContext::span_lint()`
let a = 3u32;
let b = a as u32;
//~^ unnecessary_cast
// Check the provenance of a lint sent through `TyCtxt::node_span_lint()`
let c = {
let d = 42;
d
//~^ let_and_return
};
}

View file

@ -0,0 +1,29 @@
error: casting to the same type is unnecessary (`u32` -> `u32`)
--> tests/ui/track-diagnostics-clippy.rs:LL:CC
|
LL | let b = a as u32;
| ^^^^^^^^ help: try: `a`
|
= note: -Ztrack-diagnostics: created at clippy_lints/src/casts/unnecessary_cast.rs:LL:CC
= note: `-D clippy::unnecessary-cast` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
error: returning the result of a `let` binding from a block
--> tests/ui/track-diagnostics-clippy.rs:LL:CC
|
LL | let d = 42;
| ----------- unnecessary `let` binding
LL | d
| ^
|
= note: -Ztrack-diagnostics: created at clippy_lints/src/returns.rs:LL:CC
= note: `-D clippy::let-and-return` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
help: return the expression directly
|
LL ~
LL ~ 42
|
error: aborting due to 2 previous errors

View file

@ -8,5 +8,6 @@ struct A;
struct B;
const S: A = B;
//~^ ERROR: mismatched types
//~| NOTE: created at
fn main() {}

View file

@ -3,7 +3,8 @@ error[E0308]: mismatched types
|
LL | const S: A = B;
| ^ expected `A`, found `B`
-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
|
= note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
error: aborting due to 1 previous error

View file

@ -169,9 +169,9 @@ where
// #13476
#[const_trait]
trait ConstTrait {}
const fn const_trait_bounds_good<T: ConstTrait + ~const ConstTrait>() {}
const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
const fn const_trait_bounds_bad<T: ~const ConstTrait>() {}
const fn const_trait_bounds_bad<T: [const] ConstTrait>() {}
//~^ trait_duplication_in_bounds
fn projections<T, U, V>()

View file

@ -169,9 +169,9 @@ where
// #13476
#[const_trait]
trait ConstTrait {}
const fn const_trait_bounds_good<T: ConstTrait + ~const ConstTrait>() {}
const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
const fn const_trait_bounds_bad<T: ~const ConstTrait + ~const ConstTrait>() {}
const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
//~^ trait_duplication_in_bounds
fn projections<T, U, V>()

View file

@ -61,8 +61,8 @@ LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) {
error: these bounds contain repeated elements
--> tests/ui/trait_duplication_in_bounds.rs:174:36
|
LL | const fn const_trait_bounds_bad<T: ~const ConstTrait + ~const ConstTrait>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `~const ConstTrait`
LL | const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait`
error: these where clauses contain repeated elements
--> tests/ui/trait_duplication_in_bounds.rs:181:8

View file

@ -1,4 +1,4 @@
error: constant item has unnecessary safety comment
error: constant has unnecessary safety comment
--> tests/ui/unnecessary_safety_comment.rs:6:5
|
LL | const CONST: u32 = 0;
@ -12,7 +12,7 @@ LL | // SAFETY:
= note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
error: static item has unnecessary safety comment
error: static has unnecessary safety comment
--> tests/ui/unnecessary_safety_comment.rs:10:5
|
LL | static STATIC: u32 = 0;