Merge commit '19e305bb57a7595f2a8d81f521c0dd8bf854e739' into clippy-subtree-update

This commit is contained in:
Philipp Krones
2025-01-09 18:57:00 +01:00
parent 0faf8c7c62
commit d0a74af979
146 changed files with 2002 additions and 434 deletions
+3
View File
@@ -17,6 +17,9 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
# Run
- name: Build
+22 -5
View File
@@ -23,6 +23,8 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
# Run
- name: Check Changelog
@@ -63,6 +65,8 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install i686 dependencies
if: matrix.host == 'i686-unknown-linux-gnu'
@@ -74,7 +78,8 @@ jobs:
- name: Install toolchain
run: |
rustup set default-host ${{ matrix.host }}
rustup show active-toolchain
# Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
rustup show active-toolchain || rustup toolchain install
# Run
- name: Build
@@ -121,9 +126,13 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install toolchain
run: rustup show active-toolchain
run: |
# Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
rustup show active-toolchain || rustup toolchain install
- name: Test metadata collection
run: cargo collect-metadata
@@ -136,9 +145,13 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install toolchain
run: rustup show active-toolchain
run: |
# Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
rustup show active-toolchain || rustup toolchain install
# Run
- name: Build Integration Test
@@ -188,9 +201,13 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install toolchain
run: rustup show active-toolchain
run: |
# Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
rustup show active-toolchain || rustup toolchain install
# Download
- name: Download target dir
@@ -205,7 +222,7 @@ jobs:
# Run
- name: Test ${{ matrix.integration }}
run: |
TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
TOOLCHAIN=$(rustup show active-toolchain | head -n 1 | cut -f1 -d' ')
rustup run $TOOLCHAIN $CARGO_TARGET_DIR/debug/integration --show-output
env:
INTEGRATION: ${{ matrix.integration }}
+6 -1
View File
@@ -25,9 +25,14 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
- name: Install toolchain
run: rustup show active-toolchain
run: |
# Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
rustup show active-toolchain || rustup toolchain install
# Run
- name: Build
+9 -1
View File
@@ -22,19 +22,27 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ env.TARGET_BRANCH }}
path: 'out'
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
# Run
- name: Set tag name
if: startswith(github.ref, 'refs/tags/')
run: |
TAG=$(basename ${{ github.ref }})
TAG=$(basename "${TAGNAME}")
echo "TAG_NAME=$TAG" >> $GITHUB_ENV
env:
# Make sure that the reference gets expanded before injecting it
TAGNAME: ${{ github.ref }}
- name: Set beta to true
if: github.ref == 'refs/heads/beta'
run: echo "BETA=true" >> $GITHUB_ENV
+8
View File
@@ -21,6 +21,8 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 2
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
# HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^`
# being the commit from `master` that is the base of the merge
@@ -73,6 +75,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
- name: Cache lintcheck bin
id: cache-lintcheck-bin
@@ -103,6 +108,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
- name: Restore lintcheck bin
uses: actions/cache/restore@v4
+3
View File
@@ -12,6 +12,9 @@ jobs:
# Setup
- name: Checkout
uses: actions/checkout@v4
with:
# Unsetting this would make so that any malicious package could get our Github Token
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
+45 -2
View File
@@ -6,11 +6,52 @@ document.
## Unreleased / Beta / In Rust Nightly
[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master)
[786fbd6d...master](https://github.com/rust-lang/rust-clippy/compare/786fbd6d...master)
## Rust 1.84
Current stable, released 2025-01-09
[View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster)
### New Lints
* Added [`unnecessary_map_or`] to `style`
[#11796](https://github.com/rust-lang/rust-clippy/pull/11796)
* Added [`arbitrary_source_item_ordering`] to `restriction`
[#13376](https://github.com/rust-lang/rust-clippy/pull/13376)
* Added [`map_with_unused_argument_over_ranges`] to `restriction`
[#13034](https://github.com/rust-lang/rust-clippy/pull/13034)
* Added [`map_all_any_identity`] to `complexity`
[#13499](https://github.com/rust-lang/rust-clippy/pull/13499)
* Added [`needless_as_bytes`] to `complexity`
[#13437](https://github.com/rust-lang/rust-clippy/pull/13437)
* Added [`unnecessary_literal_bound`] to `pedantic`
[#13395](https://github.com/rust-lang/rust-clippy/pull/13395)
* Added [`manual_ignore_case_cmp`] to `perf`
[#13334](https://github.com/rust-lang/rust-clippy/pull/13334)
* Added [`regex_creation_in_loops`] to `perf`
[#13412](https://github.com/rust-lang/rust-clippy/pull/13412)
### Moves and Deprecations
* Moved [`manual_is_power_of_two`] to `pedantic` (From `complexity`, now allow-by-default)
[#13553](https://github.com/rust-lang/rust-clippy/pull/13553)
* Move [`module_name_repetitions`] to `restriction` (from `pedantic`)
[#13541](https://github.com/rust-lang/rust-clippy/pull/13541)
### Enhancements
* [`doc_markdown`]: Added the following identifiers to [`doc-valid-idents`]:
CoAP, MHz, GHz, and THz
[#13633](https://github.com/rust-lang/rust-clippy/pull/13633)
[#13460](https://github.com/rust-lang/rust-clippy/pull/13460)
* [`large_const_arrays`]: Changed the default of [`array-size-threshold`] to `16kb` (from `512kb`)
[#13485](https://github.com/rust-lang/rust-clippy/pull/13485)
## Rust 1.83
Current stable, released 2024-11-28
Released 2024-11-28
[View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster)
@@ -5493,6 +5534,7 @@ Released 2018-09-13
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
[`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
[`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last
[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
@@ -6252,6 +6294,7 @@ Released 2018-09-13
[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold
[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability
[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold
[`lint-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inconsistent-struct-field-initializers
[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else
[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "clippy"
# begin autogenerated version
version = "0.1.85"
version = "0.1.86"
# end autogenerated version
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
@@ -83,7 +83,12 @@ As section headers, we use:
```
### New Lints
* Added [`LINT`] to `GROUP`
### Moves and Deprecations
* Moved [`LINT`] to `GROUP` (From `GROUP`, now LEVEL-by-default)
* Renamed `LINT` to [`LINT`]
### Enhancements
### False Positive Fixes
### Suggestion Fixes/Improvements
+1 -1
View File
@@ -21,7 +21,7 @@ use clippy_utils::is_trait_method;
impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
// Check our expr is calling a method with pattern matching
if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind
if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
// Check if the name of this method is `our_fancy_method`
&& path.ident.name.as_str() == "our_fancy_method"
// We can check the type of the self argument whenever necessary.
+27
View File
@@ -582,6 +582,33 @@ The maximum size of the `Err`-variant in a `Result` returned from a function
* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
## `lint-inconsistent-struct-field-initializers`
Whether to suggest reordering constructor fields when initializers are present.
Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
suggested code would compile, it can change semantics if the initializer expressions have side effects. The
following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
```rust
struct MyStruct {
vector: Vec<u32>,
length: usize
}
fn main() {
let vector = vec![1,2,3];
MyStruct { length: vector.len(), vector};
}
```
[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
**Default Value:** `false`
---
**Affected lints:**
* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor)
## `literal-representation-threshold`
The lower bound for linting decimal literals
+2
View File
@@ -1,5 +1,7 @@
avoid-breaking-exported-api = false
lint-inconsistent-struct-field-initializers = true
[[disallowed-methods]]
path = "rustc_lint::context::LintContext::lint"
reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "clippy_config"
# begin autogenerated version
version = "0.1.85"
version = "0.1.86"
# end autogenerated version
edition = "2021"
publish = false
+20
View File
@@ -532,6 +532,26 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// The maximum size of the `Err`-variant in a `Result` returned from a function
#[lints(result_large_err)]
large_error_threshold: u64 = 128,
/// Whether to suggest reordering constructor fields when initializers are present.
///
/// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
/// suggested code would compile, it can change semantics if the initializer expressions have side effects. The
/// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
///
/// ```rust
/// struct MyStruct {
/// vector: Vec<u32>,
/// length: usize
/// }
/// fn main() {
/// let vector = vec![1,2,3];
/// MyStruct { length: vector.len(), vector};
/// }
/// ```
///
/// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
#[lints(inconsistent_struct_constructor)]
lint_inconsistent_struct_field_initializers: bool = false,
/// The lower bound for linting decimal literals
#[lints(decimal_literal_representation)]
literal_representation_threshold: u64 = 16384,
+3 -3
View File
@@ -179,8 +179,8 @@ enum State {
#[expect(clippy::drain_collect)]
fields.push(ClippyConf {
name,
lints: lints.drain(..).collect(),
attrs: &conf[attrs_start..attrs_end],
lints: lints.drain(..).collect(),
field: conf[field_start..i].trim_end(),
});
attrs_start = i;
@@ -191,8 +191,8 @@ enum State {
#[expect(clippy::drain_collect)]
fields.push(ClippyConf {
name,
lints: lints.drain(..).collect(),
attrs: &conf[attrs_start..attrs_end],
lints: lints.drain(..).collect(),
field: conf[field_start..i].trim_end(),
});
attrs_start = i;
@@ -220,8 +220,8 @@ enum State {
}
fields.push(ClippyConf {
name,
lints,
attrs: &conf[attrs_start..attrs_end],
lints,
field: conf[field_start..].trim_end(),
});
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "clippy_lints"
# begin autogenerated version
version = "0.1.85"
version = "0.1.86"
# end autogenerated version
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
@@ -428,8 +428,8 @@ struct CurItem<'a> {
// Makes a note of the current item for comparison with the next.
cur_t = Some(CurItem {
order: module_level_order,
item,
order: module_level_order,
name: get_item_name(item),
});
}
@@ -464,7 +464,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte
ItemKind::Use(..) => Use,
ItemKind::Static(..) => Static,
ItemKind::Const(..) => Const,
ItemKind::Fn{ .. } => Fn,
ItemKind::Fn { .. } => Fn,
ItemKind::Macro(..) => Macro,
ItemKind::Mod(..) => Mod,
ItemKind::ForeignMod { .. } => ForeignMod,
@@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute])
fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) {
first.span.with_hi(last.span.hi())
} else {
return;
+16 -13
View File
@@ -1,11 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet_with_context;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::{is_lint_allowed, msrvs, std_or_core};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::Adjust;
use rustc_span::BytePos;
use super::BORROW_AS_PTR;
@@ -32,12 +34,21 @@ pub(super) fn check<'tcx>(
return false;
}
let suggestion = if msrv.meets(msrvs::RAW_REF_OP) {
let (suggestion, span) = if msrv.meets(msrvs::RAW_REF_OP) {
let operator_kind = match mutability {
Mutability::Not => "const",
Mutability::Mut => "mut",
};
format!("&raw {operator_kind} {snip}")
// Make sure that the span to be replaced doesn't include parentheses, that could break the
// suggestion.
let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) {
expr.span
.with_lo(expr.span.lo() + BytePos(1))
.with_hi(expr.span.hi() - BytePos(1))
} else {
expr.span
};
(format!("&raw {operator_kind} {snip}"), span)
} else {
let Some(std_or_core) = std_or_core(cx) else {
return false;
@@ -46,18 +57,10 @@ pub(super) fn check<'tcx>(
Mutability::Not => "addr_of",
Mutability::Mut => "addr_of_mut",
};
format!("{std_or_core}::ptr::{macro_name}!({snip})")
(format!("{std_or_core}::ptr::{macro_name}!({snip})"), expr.span)
};
span_lint_and_sugg(
cx,
BORROW_AS_PTR,
expr.span,
"borrow as raw pointer",
"try",
suggestion,
Applicability::MachineApplicable,
);
span_lint_and_sugg(cx, BORROW_AS_PTR, span, "borrow as raw pointer", "try", suggestion, app);
return true;
}
false
+2 -5
View File
@@ -836,11 +836,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
as_underscore::check(cx, expr, cast_to_hir);
as_pointer_underscore::check(cx, cast_to, cast_to_hir);
let was_borrow_as_ptr_emitted = if self.msrv.meets(msrvs::BORROW_AS_PTR) {
borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv)
} else {
false
};
let was_borrow_as_ptr_emitted = self.msrv.meets(msrvs::BORROW_AS_PTR)
&& borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv);
if self.msrv.meets(msrvs::PTR_FROM_REF) && !was_borrow_as_ptr_emitted {
ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
}
+1
View File
@@ -372,6 +372,7 @@
crate::methods::CLONE_ON_REF_PTR_INFO,
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
crate::methods::CONST_IS_EMPTY_INFO,
crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO,
crate::methods::DRAIN_COLLECT_INFO,
crate::methods::ERR_EXPECT_INFO,
crate::methods::EXPECT_FUN_CALL_INFO,
+9 -2
View File
@@ -1,6 +1,6 @@
use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::ty::{implements_trait_with_env, is_type_diagnostic_item};
use clippy_utils::{is_doc_hidden, return_ty};
use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
use rustc_lint::LateContext;
@@ -70,7 +70,14 @@ pub fn check(
&& let typeck = cx.tcx.typeck_body(body_id)
&& let body = cx.tcx.hir().body(body_id)
&& let ret_ty = typeck.expr_ty(body.value)
&& implements_trait(cx, ret_ty, future, &[])
&& implements_trait_with_env(
cx.tcx,
ty::TypingEnv::non_body_analysis(cx.tcx, owner_id.def_id),
ret_ty,
future,
Some(owner_id.def_id.to_def_id()),
&[],
)
&& let ty::Coroutine(_, subs) = ret_ty.kind()
&& is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
{
+1 -1
View File
@@ -797,8 +797,8 @@ fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowSt
parser.into_offset_iter(),
&doc,
Fragments {
fragments: &fragments,
doc: &doc,
fragments: &fragments,
},
))
}
@@ -25,7 +25,7 @@ pub(super) fn check(
// page. So associated items or impl blocks are not part of this list.
ItemKind::Static(..)
| ItemKind::Const(..)
| ItemKind::Fn{ .. }
| ItemKind::Fn { .. }
| ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::TyAlias(..)
+2 -2
View File
@@ -678,12 +678,12 @@ fn find_insert_calls<'tcx>(
map: contains_expr.map,
key: contains_expr.key,
ctxt: expr.span.ctxt(),
edits: Vec::new(),
is_map_used: false,
allow_insert_closure: true,
can_use_entry: true,
in_tail_pos: true,
is_single_insert: true,
is_map_used: false,
edits: Vec::new(),
loops: Vec::new(),
locals: HirIdSet::default(),
};
+1 -1
View File
@@ -182,7 +182,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
// will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
// T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
// So we have a hack like this.
&& generic_args.len() > 0
&& !generic_args.is_empty()
{
return;
}
+2 -2
View File
@@ -243,11 +243,11 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
&& !predicates.is_empty()
{
Some(ImplTraitBound {
span: bound.span(),
predicates,
trait_def_id,
args: path.args.map_or([].as_slice(), |p| p.args),
constraints: path.args.map_or([].as_slice(), |p| p.constraints),
trait_def_id,
span: bound.span(),
})
} else {
None
@@ -1,19 +1,21 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::fulfill_or_allowed;
use clippy_utils::source::snippet;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, ExprKind, StructTailExpr};
use rustc_hir::{self as hir, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
use std::fmt::{self, Write as _};
declare_clippy_lint! {
/// ### What it does
/// Checks for struct constructors where all fields are shorthand and
/// the order of the field init shorthand in the constructor is inconsistent
/// with the order in the struct definition.
/// Checks for struct constructors where the order of the field
/// init in the constructor is inconsistent with the order in the
/// struct definition.
///
/// ### Why is this bad?
/// Since the order of fields in a constructor doesn't affect the
@@ -59,16 +61,37 @@
#[clippy::version = "1.52.0"]
pub INCONSISTENT_STRUCT_CONSTRUCTOR,
pedantic,
"the order of the field init shorthand is inconsistent with the order in the struct definition"
"the order of the field init is inconsistent with the order in the struct definition"
}
declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
pub struct InconsistentStructConstructor {
lint_inconsistent_struct_field_initializers: bool,
}
impl InconsistentStructConstructor {
pub fn new(conf: &'static Conf) -> Self {
Self {
lint_inconsistent_struct_field_initializers: conf.lint_inconsistent_struct_field_initializers,
}
}
}
impl_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if let ExprKind::Struct(qpath, fields, base) = expr.kind
&& fields.iter().all(|f| f.is_shorthand)
&& !expr.span.from_expansion()
let ExprKind::Struct(_, fields, _) = expr.kind else {
return;
};
let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand);
let applicability = if all_fields_are_shorthand {
Applicability::MachineApplicable
} else if self.lint_inconsistent_struct_field_initializers {
Applicability::MaybeIncorrect
} else {
return;
};
if !expr.span.from_expansion()
&& let ty = cx.typeck_results().expr_ty(expr)
&& let Some(adt_def) = ty.ty_adt_def()
&& adt_def.is_struct()
@@ -85,36 +108,24 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
return;
}
let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect();
ordered_fields.sort_unstable_by_key(|id| def_order_map[id]);
let mut fields_snippet = String::new();
let (last_ident, idents) = ordered_fields.split_last().unwrap();
for ident in idents {
let _: fmt::Result = write!(fields_snippet, "{ident}, ");
}
fields_snippet.push_str(&last_ident.to_string());
let base_snippet = if let StructTailExpr::Base(base) = base {
format!(", ..{}", snippet(cx, base.span, ".."))
} else {
String::new()
};
let sugg = format!(
"{} {{ {fields_snippet}{base_snippet} }}",
snippet(cx, qpath.span(), ".."),
);
let span = field_with_attrs_span(cx.tcx, fields.first().unwrap())
.with_hi(field_with_attrs_span(cx.tcx, fields.last().unwrap()).hi());
if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) {
span_lint_and_sugg(
span_lint_and_then(
cx,
INCONSISTENT_STRUCT_CONSTRUCTOR,
expr.span,
span,
"struct constructor field order is inconsistent with struct definition field order",
"try",
sugg,
Applicability::MachineApplicable,
|diag| {
let msg = if all_fields_are_shorthand {
"try"
} else {
"if the field evaluation order doesn't matter, try"
};
let sugg = suggestion(cx, fields, &def_order_map);
diag.span_suggestion(span, msg, sugg, applicability);
},
);
}
}
@@ -135,3 +146,45 @@ fn is_consistent_order<'tcx>(fields: &'tcx [hir::ExprField<'tcx>], def_order_map
true
}
fn suggestion<'tcx>(
cx: &LateContext<'_>,
fields: &'tcx [hir::ExprField<'tcx>],
def_order_map: &FxHashMap<Symbol, usize>,
) -> String {
let ws = fields
.windows(2)
.map(|w| {
let w0_span = field_with_attrs_span(cx.tcx, &w[0]);
let w1_span = field_with_attrs_span(cx.tcx, &w[1]);
let span = w0_span.between(w1_span);
snippet(cx, span, " ")
})
.collect::<Vec<_>>();
let mut fields = fields.to_vec();
fields.sort_unstable_by_key(|field| def_order_map[&field.ident.name]);
let field_snippets = fields
.iter()
.map(|field| snippet(cx, field_with_attrs_span(cx.tcx, field), ".."))
.collect::<Vec<_>>();
assert_eq!(field_snippets.len(), ws.len() + 1);
let mut sugg = String::new();
for i in 0..field_snippets.len() {
sugg += &field_snippets[i];
if i < ws.len() {
sugg += &ws[i];
}
}
sugg
}
fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span {
if let Some(attr) = tcx.hir().attrs(field.hir_id).first() {
field.span.with_lo(attr.span.lo())
} else {
field.span
}
}
+26 -13
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{SpanRangeExt, snippet_with_context};
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
use clippy_utils::ty::implements_trait;
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -626,18 +627,30 @@ fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
})
}
let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
match ty.kind() {
ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
let is_empty = sym!(is_empty);
cx.tcx
.associated_items(principal.def_id())
.filter_by_name_unhygienic(is_empty)
.any(|item| is_is_empty(cx, item))
}),
ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
ty::Array(..) | ty::Slice(..) | ty::Str => true,
_ => false,
fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool {
match ty.kind() {
ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
let is_empty = sym!(is_empty);
cx.tcx
.associated_items(principal.def_id())
.filter_by_name_unhygienic(is_empty)
.any(|item| is_is_empty(cx, item))
}),
ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
ty::Adt(id, _) => {
has_is_empty_impl(cx, id.did())
|| (cx.tcx.recursion_limit().value_within_limit(depth)
&& cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
implements_trait(cx, ty, deref_id, &[])
&& cx
.get_associated_type(ty, deref_id, "Target")
.is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
}))
},
ty::Array(..) | ty::Slice(..) | ty::Str => true,
_ => false,
}
}
ty_has_is_empty(cx, cx.typeck_results().expr_ty(expr).peel_refs(), 0)
}
+5 -1
View File
@@ -649,7 +649,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn));
store.register_late_pass(move |_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub::new(conf)));
store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback));
store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
store.register_late_pass(move |_| {
Box::new(inconsistent_struct_constructor::InconsistentStructConstructor::new(
conf,
))
});
store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(conf)));
+1 -1
View File
@@ -38,8 +38,8 @@ pub(super) fn check<'tcx>(
cx,
label,
inner_labels: label.into_iter().collect(),
is_finite: false,
loop_depth: 0,
is_finite: false,
};
loop_visitor.visit_block(loop_block);
+3 -3
View File
@@ -220,11 +220,11 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &rustc_hir::Body<'tcx>) {
// `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span
let mut vis = BodyVisitor {
macro_unsafe_blocks: Vec::new(),
#[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
expn_depth: if body.value.span.from_expansion() { 1 } else { 0 },
macro_unsafe_blocks: Vec::new(),
lint: self,
cx
cx,
lint: self
};
vis.visit_body(body);
}
+35 -3
View File
@@ -2,14 +2,15 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_ast::{BinOpKind, LitKind};
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self};
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use clippy_config::Conf;
@@ -138,9 +139,40 @@ fn build_suggestion(
applicability: &mut Applicability,
) {
let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par();
let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
&& matches!(
lhs.kind,
ExprKind::Lit(Spanned {
node: LitKind::Int(_, LitIntType::Unsuffixed),
..
}) | ExprKind::Unary(UnOp::Neg, Expr {
kind: ExprKind::Lit(Spanned {
node: LitKind::Int(_, LitIntType::Unsuffixed),
..
}),
..
})
) {
format!("_{}", cx.typeck_results().expr_ty(rhs))
} else {
String::new()
};
let dividend_sugg_str = dividend_sugg.into_string();
// If `dividend_sugg` has enclosing paren like `(-2048)` and we need to add type suffix in the
// suggestion message, we want to make a suggestion string before `div_ceil` like
// `(-2048_{type_suffix})`.
let suggestion_before_div_ceil = if has_enclosing_paren(&dividend_sugg_str) {
format!(
"{}{})",
&dividend_sugg_str[..dividend_sugg_str.len() - 1].to_string(),
type_suffix
)
} else {
format!("{dividend_sugg_str}{type_suffix}")
};
let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})");
let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})");
span_lint_and_sugg(
cx,
+1 -1
View File
@@ -32,7 +32,7 @@
/// a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc")
/// }
/// ```
#[clippy::version = "1.82.0"]
#[clippy::version = "1.84.0"]
pub MANUAL_IGNORE_CASE_CMP,
perf,
"manual case-insensitive ASCII comparison"
+10 -16
View File
@@ -9,7 +9,7 @@
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym};
@@ -114,7 +114,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
{
let arg = peel_ref_operators(cx, arg);
let ty_sugg = get_ty_sugg(cx, arg, start);
let ty_sugg = get_ty_sugg(cx, arg);
let range = check_expr_range(start, end);
check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
}
@@ -123,19 +123,14 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
extract_msrv_attr!(LateContext);
}
fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> {
if let ExprKind::Lit(lit) = bound_expr.kind
&& let local_hid = path_to_local(arg)?
&& let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
let local_hid = path_to_local(arg)?;
if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
// `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
&& ty_span == span
{
let ty_str = match lit.node {
Char(_) => "char",
Byte(_) => "u8",
_ => return None,
};
return Some((*ty_span, ty_str));
let arg_type = cx.typeck_results().expr_ty(arg);
return Some((*ty_span, arg_type));
}
None
}
@@ -145,7 +140,7 @@ fn check_is_ascii(
span: Span,
recv: &Expr<'_>,
range: &CharRange,
ty_sugg: Option<(Span, &'_ str)>,
ty_sugg: Option<(Span, Ty<'_>)>,
) {
let sugg = match range {
CharRange::UpperChar => "is_ascii_uppercase",
@@ -159,8 +154,8 @@ fn check_is_ascii(
let mut app = Applicability::MachineApplicable;
let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))];
if let Some((ty_span, ty_str)) = ty_sugg {
suggestion.push((ty_span, format!("{recv}: {ty_str}")));
if let Some((ty_span, ty)) = ty_sugg {
suggestion.push((ty_span, format!("{recv}: {ty}")));
}
span_lint_and_then(
@@ -206,7 +201,6 @@ fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
}
}
fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange {
if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind
&& let PatExprKind::Lit{ lit: end_lit, negated: false } = &end.kind
-5
View File
@@ -583,11 +583,6 @@
/// are the same on purpose, you can factor them
/// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
///
/// ### Known problems
/// False positive possible with order dependent `match`
/// (see issue
/// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
///
/// ### Example
/// ```rust,ignore
/// match foo {
@@ -1,6 +1,6 @@
use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, walk_span_to_context};
use clippy_utils::source::walk_span_to_context;
use clippy_utils::sugg::{Sugg, make_unop};
use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
@@ -274,7 +274,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
ExprKind::AddrOf(_, _, borrowed) => borrowed,
_ => op,
};
let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
let mut app = Applicability::MachineApplicable;
let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par();
let mut sugg = format!("{receiver_sugg}.{good_method}");
if let Some(guard) = maybe_guard {
// wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
@@ -307,7 +309,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
format!("redundant pattern matching, consider using `{good_method}`"),
"try",
sugg,
Applicability::MachineApplicable,
app,
);
}
}
+1 -1
View File
@@ -345,7 +345,7 @@ fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
PatKind::Guard(..) => {
matches!(self, Self::Wild)
}
},
// Patterns for things which can only contain a single sub-pattern.
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
@@ -0,0 +1,41 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::Instance;
use rustc_span::{Span, sym};
use super::DOUBLE_ENDED_ITERATOR_LAST;
pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) {
let typeck = cx.typeck_results();
// if the "last" method is that of Iterator
if is_trait_method(cx, expr, sym::Iterator)
// if self implements DoubleEndedIterator
&& let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
&& let self_type = cx.typeck_results().expr_ty(self_expr)
&& implements_trait(cx, self_type.peel_refs(), deiter_id, &[])
// resolve the method definition
&& let id = typeck.type_dependent_def_id(expr.hir_id).unwrap()
&& let args = typeck.node_args(expr.hir_id)
&& let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
// find the provided definition of Iterator::last
&& let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last")
// if the resolved method is the same as the provided definition
&& fn_def.def_id() == last_def.def_id
{
span_lint_and_sugg(
cx,
DOUBLE_ENDED_ITERATOR_LAST,
call_span,
"called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator",
"try",
"next_back()".to_string(),
Applicability::MachineApplicable,
);
}
}
+7 -2
View File
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_trait_method, span_contains_comment};
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
@@ -17,10 +17,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
let mut applicability = Applicability::MachineApplicable;
let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
let span = expr.span.with_lo(map_span.lo());
// If the methods are separated with comments, we don't apply suggestion automatically.
if span_contains_comment(cx.tcx.sess.source_map(), span) {
applicability = Applicability::Unspecified;
}
span_lint_and_sugg(
cx,
MAP_FLATTEN,
expr.span.with_lo(map_span.lo()),
span,
format!("called `map(..).flatten()` on `{caller_ty_name}`"),
format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"),
format!("{method_to_use}({closure_snippet})"),
+13 -2
View File
@@ -1,8 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
use clippy_utils::{is_expr_untyped_identity_function, is_trait_method, path_to_local};
use rustc_ast::BindingMode;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{self as hir, Node, PatKind};
use rustc_lint::LateContext;
use rustc_span::{Span, sym};
@@ -24,6 +25,16 @@ pub(super) fn check(
&& is_expr_untyped_identity_function(cx, map_arg)
&& let Some(sugg_span) = expr.span.trim_start(caller.span)
{
// If the result of `.map(identity)` is used as a mutable reference,
// the caller must not be an immutable binding.
if cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr()
&& let Some(hir_id) = path_to_local(caller)
&& let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
&& !matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
{
return;
}
span_lint_and_sugg(
cx,
MAP_IDENTITY,
+29
View File
@@ -14,6 +14,7 @@
mod clone_on_ref_ptr;
mod cloned_instead_of_copied;
mod collapsible_str_replace;
mod double_ended_iterator_last;
mod drain_collect;
mod err_expect;
mod expect_fun_call;
@@ -4284,6 +4285,32 @@
"map of a trivial closure (not dependent on parameter) over a range"
}
declare_clippy_lint! {
/// ### What it does
///
/// Checks for `Iterator::last` being called on a `DoubleEndedIterator`, which can be replaced
/// with `DoubleEndedIterator::next_back`.
///
/// ### Why is this bad?
///
/// `Iterator::last` is implemented by consuming the iterator, which is unnecessary if
/// the iterator is a `DoubleEndedIterator`. Since Rust traits do not allow specialization,
/// `Iterator::last` cannot be optimized for `DoubleEndedIterator`.
///
/// ### Example
/// ```no_run
/// let last_arg = "echo hello world".split(' ').last();
/// ```
/// Use instead:
/// ```no_run
/// let last_arg = "echo hello world".split(' ').next_back();
/// ```
#[clippy::version = "1.85.0"]
pub DOUBLE_ENDED_ITERATOR_LAST,
perf,
"using `Iterator::last` on a `DoubleEndedIterator`"
}
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@@ -4449,6 +4476,7 @@ pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
MAP_ALL_ANY_IDENTITY,
MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
UNNECESSARY_MAP_OR,
DOUBLE_ENDED_ITERATOR_LAST,
]);
/// Extracts a method call name, args, and `Span` of the method name.
@@ -4931,6 +4959,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
false,
);
}
double_ended_iterator_last::check(cx, expr, recv, call_span);
},
("len", []) => {
if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) {
@@ -7,6 +7,7 @@
use super::NEEDLESS_CHARACTER_ITERATION;
use super::utils::get_last_chain_binding_hir_id;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::paths::CHAR_IS_ASCII;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
@@ -77,7 +78,7 @@ fn handle_expr(
if revert != is_all
&& let ExprKind::Path(path) = fn_path.kind
&& let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
&& match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"])
&& match_def_path(cx, fn_def_id, &CHAR_IS_ASCII)
&& path_to_local_id(peels_expr_ref(arg), first_param)
&& let Some(snippet) = before_chars.get_source_text(cx)
{
+5 -5
View File
@@ -470,14 +470,14 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
captured_ids: HirIdSet,
) -> Option<Vec<IterFunction>> {
let mut visitor = IterFunctionVisitor {
uses: Vec::new(),
target: id,
seen_other: false,
cx,
current_mutably_captured_ids: HirIdSet::default(),
illegal_mutable_capture_ids: captured_ids,
current_mutably_captured_ids: HirIdSet::default(),
cx,
uses: Vec::new(),
hir_id_uses_map: FxHashMap::default(),
current_statement_hir_id: None,
seen_other: false,
target: id,
};
visitor.visit_block(block);
if visitor.seen_other {
@@ -1,6 +1,7 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::paths::STDIN;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_local_use_after_expr;
@@ -33,7 +34,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
&& match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"])
&& match_def_path(cx, recv_adt.did(), &STDIN)
&& let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
&& let Res::Local(local_id) = path.res
{
+1 -1
View File
@@ -297,8 +297,8 @@ fn parse_iter_usage<'tcx>(
{
Some(IterUsage {
kind: IterUsageKind::NextTuple,
span: e.span,
unwrap_kind: None,
span: e.span,
})
} else {
None
+4 -4
View File
@@ -124,30 +124,30 @@ pub(super) fn check(
match lit.node {
ast::LitKind::Bool(false) => {
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement {
method_name: "any",
has_args: true,
has_generic_return: false,
method_name: "any",
});
},
ast::LitKind::Bool(true) => {
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement {
method_name: "all",
has_args: true,
has_generic_return: false,
method_name: "all",
});
},
ast::LitKind::Int(Pu128(0), _) => {
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement {
method_name: "sum",
has_args: false,
has_generic_return: needs_turbofish(cx, expr),
method_name: "sum",
});
},
ast::LitKind::Int(Pu128(1), _) => {
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement {
method_name: "product",
has_args: false,
has_generic_return: needs_turbofish(cx, expr),
method_name: "product",
});
},
_ => (),
+19 -5
View File
@@ -7,7 +7,7 @@
use clippy_utils::sugg::{Sugg, make_binop};
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
use clippy_utils::visitors::is_local_used;
use clippy_utils::{is_from_proc_macro, path_to_local_id};
use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id};
use rustc_ast::LitKind::Bool;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
@@ -96,11 +96,25 @@ pub(super) fn check<'a>(
Sugg::hir(cx, non_binding_location, "")
)));
let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding)
.maybe_par()
.into_string();
let mut app = Applicability::MachineApplicable;
let binop = make_binop(
op.node,
&Sugg::hir_with_applicability(cx, recv, "..", &mut app),
&inner_non_binding,
);
(binop, "a standard comparison", Applicability::MaybeIncorrect)
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) {
match parent_expr.kind {
ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_par(),
ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_par(),
_ => binop,
}
} else {
binop
}
.into_string();
(sugg, "a standard comparison", app)
} else if !def_bool
&& msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND)
&& let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite())
@@ -494,7 +494,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
match node {
Node::Stmt(_) => return true,
Node::Block(..) => continue,
Node::Block(..) => {},
Node::Item(item) => {
if let ItemKind::Fn { body: body_id, .. } = &item.kind
&& let output_ty = return_ty(cx, item.owner_id)
+6 -3
View File
@@ -2,7 +2,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method};
use rustc_errors::Applicability;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
@@ -97,6 +97,11 @@ fn check_fn(
span: Span,
def_id: LocalDefId,
) {
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
if is_in_test(cx.tcx, hir_id) {
return;
}
if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
return;
}
@@ -136,8 +141,6 @@ fn check_fn(
return;
}
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
// Const fns are not allowed as methods in a trait.
{
let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
+1 -1
View File
@@ -192,7 +192,7 @@ fn check_crate_post(&mut self, _: &LateContext<'tcx>) {
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
match it.kind {
hir::ItemKind::Fn{ .. } => {
hir::ItemKind::Fn { .. } => {
// ignore main()
if it.ident.name == sym::main {
let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
+1 -1
View File
@@ -96,7 +96,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
return;
}
match it.kind {
hir::ItemKind::Fn{ .. } => {
hir::ItemKind::Fn { .. } => {
let desc = "a function";
let attrs = cx.tcx.hir().attrs(it.hir_id());
check_missing_inline_attrs(cx, attrs, it.span, desc);
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -80,7 +81,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
applicability = Applicability::HasPlaceholders;
"&'_ mut self".to_string()
} else {
format!("&{} mut self", &lifetime.ident.name)
let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
format!("&{lt_name} mut self")
}
},
(Mode::Ref(None), Mutability::Not) => "&self".to_string(),
@@ -89,7 +91,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
applicability = Applicability::HasPlaceholders;
"&'_ self".to_string()
} else {
format!("&{} self", &lifetime.ident.name)
let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
format!("&{lt_name} self")
}
},
(Mode::Value, Mutability::Mut) => "mut self".to_string(),
+117 -26
View File
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{indent_of, snippet, snippet_block};
use rustc_ast::ast;
use rustc_ast::{Block, Label, ast};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
@@ -11,6 +11,7 @@
/// that contain a `continue` statement in either their main blocks or their
/// `else`-blocks, when omitting the `else`-block possibly with some
/// rearrangement of code can make the code easier to understand.
/// The lint also checks if the last statement in the loop is a `continue`
///
/// ### Why is this bad?
/// Having explicit `else` blocks for `if` statements
@@ -75,6 +76,49 @@
/// # break;
/// }
/// ```
///
/// ```rust
/// # use std::io::ErrorKind;
///
/// fn foo() -> ErrorKind { ErrorKind::NotFound }
/// for _ in 0..10 {
/// match foo() {
/// ErrorKind::NotFound => {
/// eprintln!("not found");
/// continue
/// }
/// ErrorKind::TimedOut => {
/// eprintln!("timeout");
/// continue
/// }
/// _ => {
/// eprintln!("other error");
/// continue
/// }
/// }
/// }
/// ```
/// Could be rewritten as
///
///
/// ```rust
/// # use std::io::ErrorKind;
///
/// fn foo() -> ErrorKind { ErrorKind::NotFound }
/// for _ in 0..10 {
/// match foo() {
/// ErrorKind::NotFound => {
/// eprintln!("not found");
/// }
/// ErrorKind::TimedOut => {
/// eprintln!("timeout");
/// }
/// _ => {
/// eprintln!("other error");
/// }
/// }
/// }
/// ```
#[clippy::version = "pre 1.29.0"]
pub NEEDLESS_CONTINUE,
pedantic,
@@ -144,7 +188,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
///
/// - The expression is a `continue` node.
/// - The expression node is a block with the first statement being a `continue`.
fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&Label>) -> bool {
match else_expr.kind {
ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()),
@@ -152,7 +196,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
}
}
fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
fn is_first_block_stmt_continue(block: &Block, label: Option<&Label>) -> bool {
block.stmts.first().is_some_and(|stmt| match stmt.kind {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
if let ast::ExprKind::Continue(ref l) = e.kind {
@@ -166,7 +210,7 @@ fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>)
}
/// If the `continue` has a label, check it matches the label of the loop.
fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::Label>) -> bool {
fn compare_labels(loop_label: Option<&Label>, continue_label: Option<&Label>) -> bool {
match (loop_label, continue_label) {
// `loop { continue; }` or `'a loop { continue; }`
(_, None) => true,
@@ -181,7 +225,7 @@ fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::
/// the AST object representing the loop block of `expr`.
fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
where
F: FnMut(&ast::Block, Option<&ast::Label>),
F: FnMut(&Block, Option<&Label>),
{
if let ast::ExprKind::While(_, loop_block, label)
| ast::ExprKind::ForLoop {
@@ -205,7 +249,7 @@ fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
/// - The `else` expression.
fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
where
F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
F: FnMut(&ast::Expr, &ast::Expr, &Block, &ast::Expr),
{
match stmt.kind {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
@@ -231,14 +275,14 @@ struct LintData<'a> {
/// The condition expression for the above `if`.
if_cond: &'a ast::Expr,
/// The `then` block of the `if` statement.
if_block: &'a ast::Block,
if_block: &'a Block,
/// The `else` block of the `if` statement.
/// Note that we only work with `if` exprs that have an `else` branch.
else_expr: &'a ast::Expr,
/// The 0-based index of the `if` statement in the containing loop block.
stmt_idx: usize,
/// The statements of the loop block.
loop_block: &'a ast::Block,
loop_block: &'a Block,
}
const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant";
@@ -329,33 +373,74 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
)
}
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
if let ast::ExprKind::Loop(loop_block, loop_label, ..) = &expr.kind
&& let Some(last_stmt) = loop_block.stmts.last()
&& let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
&& let ast::ExprKind::Continue(continue_label) = inner_expr.kind
&& compare_labels(loop_label.as_ref(), continue_label.as_ref())
{
span_lint_and_help(
cx,
NEEDLESS_CONTINUE,
last_stmt.span,
MSG_REDUNDANT_CONTINUE_EXPRESSION,
None,
DROP_CONTINUE_EXPRESSION_MSG,
);
fn check_last_stmt_in_expr<F>(inner_expr: &ast::Expr, func: &F)
where
F: Fn(Option<&Label>, Span),
{
match &inner_expr.kind {
ast::ExprKind::Continue(continue_label) => {
func(continue_label.as_ref(), inner_expr.span);
},
ast::ExprKind::If(_, then_block, else_block) => {
check_last_stmt_in_block(then_block, func);
if let Some(else_block) = else_block {
check_last_stmt_in_expr(else_block, func);
}
},
ast::ExprKind::Match(_, arms, _) => {
for arm in arms {
if let Some(expr) = &arm.body {
check_last_stmt_in_expr(expr, func);
}
}
},
ast::ExprKind::Block(b, _) => {
check_last_stmt_in_block(b, func);
},
_ => {},
}
}
fn check_last_stmt_in_block<F>(b: &Block, func: &F)
where
F: Fn(Option<&Label>, Span),
{
if let Some(last_stmt) = b.stmts.last()
&& let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
{
check_last_stmt_in_expr(inner_expr, func);
}
}
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
with_loop_block(expr, |loop_block, label| {
for (i, stmt) in loop_block.stmts.iter().enumerate() {
let p = |continue_label: Option<&Label>, span: Span| {
if compare_labels(label, continue_label) {
span_lint_and_help(
cx,
NEEDLESS_CONTINUE,
span,
MSG_REDUNDANT_CONTINUE_EXPRESSION,
None,
DROP_CONTINUE_EXPRESSION_MSG,
);
}
};
let stmts = &loop_block.stmts;
for (i, stmt) in stmts.iter().enumerate() {
let mut maybe_emitted_in_if = false;
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
let data = &LintData {
stmt_idx: i,
if_expr,
if_cond: cond,
if_block: then_block,
else_expr,
stmt_idx: i,
loop_block,
};
maybe_emitted_in_if = true;
if needless_continue_in_else(else_expr, label) {
emit_warning(
cx,
@@ -365,8 +450,14 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
);
} else if is_first_block_stmt_continue(then_block, label) {
emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
} else {
maybe_emitted_in_if = false;
}
});
if i == stmts.len() - 1 && !maybe_emitted_in_if {
check_last_stmt_in_block(loop_block, &p);
}
}
});
}
@@ -400,7 +491,7 @@ fn erode_from_back(s: &str) -> String {
if ret.is_empty() { s.to_string() } else { ret }
}
fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
fn span_of_first_expr_in_block(block: &Block) -> Option<Span> {
block.stmts.first().map(|stmt| stmt.span)
}
+1 -1
View File
@@ -144,7 +144,7 @@ fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
|diag| {
for parent in cx.tcx.hir().parent_iter(stmt.hir_id) {
if let Node::Item(item) = parent.1
&& let ItemKind::Fn{ .. } = item.kind
&& let ItemKind::Fn { .. } = item.kind
&& let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id)
&& let [.., final_stmt] = block.stmts
&& final_stmt.hir_id == stmt.hir_id
+6 -5
View File
@@ -189,6 +189,8 @@ pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
}
fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
// No branch that we check (yet) should continue if val isn't a ValTree::Branch
let ty::ValTree::Branch(val) = val else { return false };
match *ty.kind() {
// the fact that we have to dig into every structs to search enums
// leads us to the point checking `UnsafeCell` directly is the only option.
@@ -197,12 +199,13 @@ fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, t
// contained value.
ty::Adt(def, ..) if def.is_union() => false,
ty::Array(ty, _) => val
.unwrap_branch()
.iter()
.any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
ty::Adt(def, args) if def.is_enum() => {
let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32());
let Some((&ty::ValTree::Leaf(variant_index), fields)) = val.split_first() else {
return false;
};
let variant_index = VariantIdx::from_u32(variant_index.to_u32());
fields
.iter()
.copied()
@@ -215,12 +218,10 @@ fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, t
.any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty))
},
ty::Adt(def, args) => val
.unwrap_branch()
.iter()
.zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
.any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
ty::Tuple(tys) => val
.unwrap_branch()
.iter()
.zip(tys)
.any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
+1 -1
View File
@@ -270,10 +270,10 @@ fn check_ident(&mut self, ident: Ident) {
return;
}
self.0.names.push(ExistingName {
exemptions: get_exemptions(interned_name).unwrap_or(&[]),
interned: ident.name,
span: ident.span,
len: count,
exemptions: get_exemptions(interned_name).unwrap_or(&[]),
});
}
@@ -47,6 +47,7 @@ pub fn new(conf: &'static Conf) -> Self {
Self {
allowed_binary,
allowed_unary,
const_span: None,
disallowed_int_methods: [
sym::saturating_div,
sym::wrapping_div,
@@ -55,7 +56,6 @@ pub fn new(conf: &'static Conf) -> Self {
]
.into_iter()
.collect(),
const_span: None,
expr_span: None,
}
}
+4 -4
View File
@@ -143,11 +143,11 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
self.searcher = Some(PathbufPushSearcher {
local_id: id,
lhs_is_let: true,
name: name.name,
let_ty_span: local.ty.map(|ty| ty.span),
err_span: local.span,
init_val: *init_expr,
arg: None,
name: name.name,
err_span: local.span,
});
}
}
@@ -165,10 +165,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
local_id: id,
lhs_is_let: false,
let_ty_span: None,
name: name.ident.name,
err_span: expr.span,
init_val: *right,
arg: None,
name: name.ident.name,
err_span: expr.span,
});
}
}
-1
View File
@@ -69,7 +69,6 @@ fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
ExprKind::If(_, next_then, Some(next_els)) => {
then = next_then;
els = next_els;
continue;
},
// else if without else
ExprKind::If(..) => return,
+3 -3
View File
@@ -17,9 +17,9 @@
/// Checks for redundant redefinitions of local bindings.
///
/// ### Why is this bad?
/// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
/// Redundant redefinitions of local bindings do not change behavior other than variable's lifetimes and are likely to be unintended.
///
/// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
/// These rebindings can be intentional to shorten the lifetimes of variables because they affect when the `Drop` implementation is called. Other than that, they do not affect your code's meaning but they _may_ affect `rustc`'s stack allocation.
///
/// ### Example
/// ```no_run
@@ -41,7 +41,7 @@
/// ```
#[clippy::version = "1.73.0"]
pub REDUNDANT_LOCALS,
correctness,
suspicious,
"redundant redefinition of a local binding"
}
declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
+11 -1
View File
@@ -24,6 +24,11 @@
/// ```ignore
/// Regex::new("(")
/// ```
///
/// Use instead:
/// ```ignore
/// Regex::new("\(")
/// ```
#[clippy::version = "pre 1.29.0"]
pub INVALID_REGEX,
correctness,
@@ -49,6 +54,11 @@
/// ```ignore
/// Regex::new("^foobar")
/// ```
///
/// Use instead:
/// ```ignore
/// str::starts_with("foobar")
/// ```
#[clippy::version = "pre 1.29.0"]
pub TRIVIAL_REGEX,
nursery,
@@ -87,7 +97,7 @@
/// }
/// }
/// ```
#[clippy::version = "1.83.0"]
#[clippy::version = "1.84.0"]
pub REGEX_CREATION_IN_LOOPS,
perf,
"regular expression compilation performed in a loop"
@@ -282,9 +282,9 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
}
{
let mut apa = AuxParamsAttr {
first_bind_ident: ident,
first_block_hir_id: self.ap.curr_block_hir_id,
first_block_span: self.ap.curr_block_span,
first_bind_ident: ident,
first_method_span: {
let expr_or_init = expr_or_init(self.cx, expr);
if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind {
@@ -395,8 +395,8 @@ fn default() -> Self {
counter: 0,
has_expensive_expr_after_last_attr: false,
first_block_hir_id: HirId::INVALID,
first_bind_ident: Ident::empty(),
first_block_span: DUMMY_SP,
first_bind_ident: Ident::empty(),
first_method_span: DUMMY_SP,
first_stmt_span: DUMMY_SP,
last_bind_ident: Ident::empty(),
+13 -9
View File
@@ -1,4 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::sugg::Sugg;
use clippy_utils::{
@@ -203,14 +203,18 @@ fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocati
"len",
);
span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
diag.span_suggestion(
vec_alloc.allocation_expr.span.source_callsite(),
"consider replacing this with",
format!("vec![0; {len_expr}]"),
Applicability::Unspecified,
);
});
let span_to_replace = slow_fill
.span
.with_lo(vec_alloc.allocation_expr.span.source_callsite().lo());
span_lint_and_sugg(
cx,
SLOW_VECTOR_INITIALIZATION,
span_to_replace,
msg,
"consider replacing this with",
format!("vec![0; {len_expr}]"),
Applicability::Unspecified,
);
}
}
+2 -2
View File
@@ -384,9 +384,9 @@ fn is_used_other_than_swapping(&mut self, idx_ident: Ident) -> bool {
fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool {
let mut v = IndexBindingVisitor {
found_used: false,
suggest_span: self.suggest_span,
idx: idx_ident,
suggest_span: self.suggest_span,
found_used: false,
};
for stmt in self.block.stmts {
+5 -2
View File
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::has_repr_attr;
use clippy_utils::{has_repr_attr, is_in_test};
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
@@ -37,7 +37,10 @@
impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
if is_struct_with_trailing_zero_sized_array(cx, item)
&& !has_repr_attr(cx, item.hir_id())
&& !is_in_test(cx.tcx, item.hir_id())
{
span_lint_and_help(
cx,
TRAILING_EMPTY_ARRAY,
@@ -30,17 +30,14 @@ pub(super) fn check<'tcx>(
| (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
(ReducedTy::OrderedFields(Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) if reduced_tys.from_fat_ptr => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
// ptr <-> ptr
@@ -50,7 +47,6 @@ pub(super) fn check<'tcx>(
{
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
// fat ptr <-> (*size, *size)
+1 -1
View File
@@ -388,8 +388,8 @@ fn check_fn(
self.check_fn_decl(cx, decl, CheckTyContext {
is_in_trait_impl,
is_exported,
in_body: matches!(fn_kind, FnKind::Closure),
is_exported,
..CheckTyContext::default()
});
}
@@ -47,7 +47,7 @@
/// }
/// }
/// ```
#[clippy::version = "1.83.0"]
#[clippy::version = "1.84.0"]
pub UNNECESSARY_LITERAL_BOUND,
pedantic,
"detects &str that could be &'static str in function return types"
+3 -3
View File
@@ -120,8 +120,8 @@ fn check_fn(
let mut visitor = AsyncFnVisitor {
cx,
found_await: false,
async_depth: 0,
await_in_async_block: None,
async_depth: 0,
};
walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
if !visitor.found_await {
@@ -129,9 +129,9 @@ fn check_fn(
// The actual linting happens in `check_crate_post`, once we've found all
// uses of local async functions that do require asyncness to pass typeck
self.unused_async_fns.push(UnusedAsyncFn {
await_in_async_block: visitor.await_in_async_block,
fn_span: span,
def_id,
fn_span: span,
await_in_async_block: visitor.await_in_async_block,
});
}
}
+2 -2
View File
@@ -245,9 +245,9 @@ fn visit_branch(
let prev_len = self.unwrappables.len();
for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) {
let mut delegate = MutationVisitor {
tcx: self.cx.tcx,
is_mutated: false,
local_id: unwrap_info.local_id,
tcx: self.cx.tcx,
};
let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate);
@@ -397,8 +397,8 @@ fn check_fn(
}
let mut v = UnwrappableVariablesVisitor {
cx,
unwrappables: Vec::new(),
cx,
};
walk_fn(&mut v, kind, decl, body.id(), fn_id);
@@ -73,6 +73,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
SimplifiedType::Slice,
SimplifiedType::Str,
SimplifiedType::Bool,
SimplifiedType::Char,
]
.iter()
.flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
+13 -3
View File
@@ -8,7 +8,7 @@
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method};
use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -132,9 +132,19 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
for (span, lint_opt) in &self.span_to_lint_map {
if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
let help_msg = format!("you can use {} directly", suggest_slice.desc(),);
let help_msg = format!("you can use {} directly", suggest_slice.desc());
span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
diag.span_suggestion(*span, help_msg, snippet, *applicability);
// If the `vec!` macro contains comment, better not make the suggestion machine
// applicable as it would remove them.
let applicability = if *applicability != Applicability::Unspecified
&& let source_map = cx.tcx.sess.source_map()
&& span_contains_comment(source_map, *span)
{
Applicability::Unspecified
} else {
*applicability
};
diag.span_suggestion(*span, help_msg, snippet, applicability);
});
}
}
+2 -2
View File
@@ -166,8 +166,8 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
local_id: id,
init,
lhs_is_let: true,
name: name.name,
let_ty_span: local.ty.map(|ty| ty.span),
name: name.name,
err_span: local.span,
found: 0,
last_push_expr: init_expr.hir_id,
@@ -206,8 +206,8 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
&& name.ident.as_str() == "push"
{
self.searcher = Some(VecPushSearcher {
found: searcher.found + 1,
err_span: searcher.err_span.to(stmt.span),
found: searcher.found + 1,
last_push_expr: expr.hir_id,
..searcher
});
+1 -1
View File
@@ -248,8 +248,8 @@ impl Write {
pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
Self {
format_args,
allow_print_in_tests: conf.allow_print_in_tests,
in_debug_impl: false,
allow_print_in_tests: conf.allow_print_in_tests,
}
}
}
+1 -1
View File
@@ -300,8 +300,8 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus
};
let mut vis = ExitPointFinder {
cx,
state: ExitPointState::WalkUpTo(spawn_expr.hir_id),
cx,
};
if let Break(ExitCallFound) = vis.visit_block(block) {
// Visitor found an unconditional `exit()` call, so don't lint.
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "clippy_utils"
# begin autogenerated version
version = "0.1.85"
version = "0.1.86"
# end autogenerated version
edition = "2021"
description = "Helpful tools for writing lints, provided as they are used in Clippy"
+1 -1
View File
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
<!-- begin autogenerated nightly -->
```
nightly-2024-12-26
nightly-2025-01-09
```
<!-- end autogenerated nightly -->
+1 -1
View File
@@ -196,8 +196,8 @@ pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
if let ExprKind::DropTemps(new_cond) = cond.kind {
return Some(Self {
cond: new_cond,
r#else,
then,
r#else,
});
}
if let ExprKind::Let(..) = cond.kind {
+1 -1
View File
@@ -806,8 +806,8 @@ pub fn new(cx: &'a LateContext<'tcx>) -> Self {
Self {
cx,
maybe_typeck_results: cx.maybe_typeck_results(),
path_check: PathCheck::default(),
s: FxHasher::default(),
path_check: PathCheck::default(),
}
}
+1 -1
View File
@@ -1243,9 +1243,9 @@ fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
let mut v = V {
cx,
allow_closure: true,
loops: Vec::new(),
locals: HirIdSet::default(),
allow_closure: true,
captures: HirIdMap::default(),
};
v.visit_expr(expr);
+1 -1
View File
@@ -32,8 +32,8 @@ fn new(
) -> Self {
Self {
possible_borrower: TransitiveRelation::default(),
cx,
body,
cx,
possible_origin,
}
}
+1 -1
View File
@@ -130,7 +130,7 @@ fn parse_attr(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersio
let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
if let Some(msrv_attr) = msrv_attrs.next() {
if let Some(duplicate) = msrv_attrs.last() {
if let Some(duplicate) = msrv_attrs.next_back() {
sess.dcx()
.struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
.with_span_note(msrv_attr.span(), "first definition found here")
+2
View File
@@ -33,6 +33,8 @@
pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"];
pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"];
pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "<impl char>", "is_ascii"];
pub const STDIN: [&str; 4] = ["std", "io", "stdio", "Stdin"];
// Paths in clippy itself
pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
+1 -1
View File
@@ -94,8 +94,8 @@ pub fn new(mut diag: Diagnostic, base_url: &str, krate: &str) -> Option<Self> {
Some(Self {
name,
diag,
url,
krate: krate.to_string(),
url,
})
}
+1 -1
View File
@@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
channel = "nightly-2024-12-26"
channel = "nightly-2025-01-09"
# end autogenerated nightly
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
profile = "minimal"
+1 -1
View File
@@ -574,12 +574,12 @@ fn new_deprecated(name: &str, reason: &str, version: &'static str) -> Self {
id_location: None,
group: "deprecated",
level: "none",
version,
docs: format!(
"### What it does\n\n\
Nothing. This lint has been deprecated\n\n\
### Deprecation reason\n\n{reason}.\n",
),
version,
applicability: Applicability::Unspecified,
}
}
+1 -1
View File
@@ -59,7 +59,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
missing_files.push(path.to_str().unwrap().to_string());
}
},
_ => continue,
_ => {},
};
}
}
@@ -1,3 +1,4 @@
thread '<unnamed>' panicked at clippy_lints/src/utils/internal_lints/produce_ice.rs:
Would you like some help with that?
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
@@ -0,0 +1 @@
lint-inconsistent-struct-field-initializers = true
@@ -0,0 +1,79 @@
#![warn(clippy::inconsistent_struct_constructor)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::unnecessary_operation)]
#![allow(clippy::no_effect)]
#[derive(Default)]
struct Foo {
x: i32,
y: i32,
z: i32,
}
fn main() {
let x = 1;
let y = 1;
let z = 1;
Foo { x, y, z: z };
Foo {
x,
z: z,
..Default::default()
};
}
// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645
mod field_attributes {
struct HirId;
struct BodyVisitor {
macro_unsafe_blocks: Vec<HirId>,
expn_depth: u32,
}
fn check_body(condition: bool) {
BodyVisitor {
macro_unsafe_blocks: Vec::new(),
#[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
expn_depth: if condition { 1 } else { 0 },
};
}
}
// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
mod cfgs_between_fields {
#[allow(clippy::non_minimal_cfg)]
fn cfg_all() {
struct S {
a: i32,
b: i32,
#[cfg(all())]
c: i32,
d: i32,
}
let s = S {
a: 3,
b: 2,
#[cfg(all())]
c: 1,
d: 0,
};
}
fn cfg_any() {
struct S {
a: i32,
b: i32,
#[cfg(any())]
c: i32,
d: i32,
}
let s = S {
a: 3,
#[cfg(any())]
c: 1,
b: 2,
d: 0,
};
}
}
@@ -0,0 +1,79 @@
#![warn(clippy::inconsistent_struct_constructor)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::unnecessary_operation)]
#![allow(clippy::no_effect)]
#[derive(Default)]
struct Foo {
x: i32,
y: i32,
z: i32,
}
fn main() {
let x = 1;
let y = 1;
let z = 1;
Foo { y, x, z: z };
Foo {
z: z,
x,
..Default::default()
};
}
// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645
mod field_attributes {
struct HirId;
struct BodyVisitor {
macro_unsafe_blocks: Vec<HirId>,
expn_depth: u32,
}
fn check_body(condition: bool) {
BodyVisitor {
#[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
expn_depth: if condition { 1 } else { 0 },
macro_unsafe_blocks: Vec::new(),
};
}
}
// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
mod cfgs_between_fields {
#[allow(clippy::non_minimal_cfg)]
fn cfg_all() {
struct S {
a: i32,
b: i32,
#[cfg(all())]
c: i32,
d: i32,
}
let s = S {
d: 0,
#[cfg(all())]
c: 1,
b: 2,
a: 3,
};
}
fn cfg_any() {
struct S {
a: i32,
b: i32,
#[cfg(any())]
c: i32,
d: i32,
}
let s = S {
d: 0,
#[cfg(any())]
c: 1,
b: 2,
a: 3,
};
}
}
@@ -0,0 +1,77 @@
error: struct constructor field order is inconsistent with struct definition field order
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:18:11
|
LL | Foo { y, x, z: z };
| ^^^^^^^^^^ help: if the field evaluation order doesn't matter, try: `x, y, z: z`
|
= note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]`
error: struct constructor field order is inconsistent with struct definition field order
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:21:9
|
LL | / z: z,
LL | | x,
| |_________^
|
help: if the field evaluation order doesn't matter, try
|
LL ~ x,
LL ~ z: z,
|
error: struct constructor field order is inconsistent with struct definition field order
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:36:13
|
LL | / #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
LL | | expn_depth: if condition { 1 } else { 0 },
LL | | macro_unsafe_blocks: Vec::new(),
| |___________________________________________^
|
help: if the field evaluation order doesn't matter, try
|
LL ~ macro_unsafe_blocks: Vec::new(),
LL + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
LL ~ expn_depth: if condition { 1 } else { 0 },
|
error: struct constructor field order is inconsistent with struct definition field order
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:55:13
|
LL | / d: 0,
LL | | #[cfg(all())]
LL | | c: 1,
LL | | b: 2,
LL | | a: 3,
| |________________^
|
help: if the field evaluation order doesn't matter, try
|
LL ~ a: 3,
LL + b: 2,
LL + #[cfg(all())]
LL + c: 1,
LL ~ d: 0,
|
error: struct constructor field order is inconsistent with struct definition field order
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:72:13
|
LL | / d: 0,
LL | | #[cfg(any())]
LL | | c: 1,
LL | | b: 2,
LL | | a: 3,
| |________________^
|
help: if the field evaluation order doesn't matter, try
|
LL ~ a: 3,
LL + #[cfg(any())]
LL + c: 1,
LL + b: 2,
LL ~ d: 0,
|
error: aborting due to 5 previous errors
@@ -46,6 +46,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
future-size-threshold
ignore-interior-mutability
large-error-threshold
lint-inconsistent-struct-field-initializers
literal-representation-threshold
matches-for-let-else
max-fn-params-bools
@@ -134,6 +135,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
future-size-threshold
ignore-interior-mutability
large-error-threshold
lint-inconsistent-struct-field-initializers
literal-representation-threshold
matches-for-let-else
max-fn-params-bools
@@ -222,6 +224,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
future-size-threshold
ignore-interior-mutability
large-error-threshold
lint-inconsistent-struct-field-initializers
literal-representation-threshold
matches-for-let-else
max-fn-params-bools
+8
View File
@@ -16,4 +16,12 @@ fn main() {
let mut val_mut = 1;
let _p_mut = std::ptr::addr_of_mut!(val_mut);
let mut x: [i32; 2] = [42, 43];
let _raw = std::ptr::addr_of_mut!(x[1]).wrapping_offset(-1);
}
fn issue_13882() {
let mut x: [i32; 2] = [42, 43];
let _raw = (&raw mut x[1]).wrapping_offset(-1);
}
+8
View File
@@ -16,4 +16,12 @@ fn main() {
let mut val_mut = 1;
let _p_mut = &mut val_mut as *mut i32;
let mut x: [i32; 2] = [42, 43];
let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
}
fn issue_13882() {
let mut x: [i32; 2] = [42, 43];
let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
}
+13 -1
View File
@@ -13,5 +13,17 @@ error: borrow as raw pointer
LL | let _p_mut = &mut val_mut as *mut i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
error: aborting due to 2 previous errors
error: borrow as raw pointer
--> tests/ui/borrow_as_ptr.rs:21:16
|
LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])`
error: borrow as raw pointer
--> tests/ui/borrow_as_ptr.rs:26:17
|
LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]`
error: aborting due to 4 previous errors
@@ -47,6 +47,17 @@ fn deref(&self) -> &T {
}
}
// ICE regression test
mod issue12979 {
use std::cell::UnsafeCell;
const ATOMIC_TUPLE: (Vec<UnsafeCell<u8>>, ()) = (Vec::new(), ());
fn main() {
let _x = &ATOMIC_TUPLE.0;
}
}
// use a tuple to make sure referencing a field behind a pointer isn't linted.
const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
@@ -1,5 +1,5 @@
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:54:5
--> tests/ui/borrow_interior_mutable_const/others.rs:65:5
|
LL | ATOMIC.store(1, Ordering::SeqCst);
| ^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:55:16
--> tests/ui/borrow_interior_mutable_const/others.rs:66:16
|
LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
| ^^^^^^
@@ -20,7 +20,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:58:22
--> tests/ui/borrow_interior_mutable_const/others.rs:69:22
|
LL | let _once_ref = &ONCE_INIT;
| ^^^^^^^^^
@@ -28,7 +28,7 @@ LL | let _once_ref = &ONCE_INIT;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:59:25
--> tests/ui/borrow_interior_mutable_const/others.rs:70:25
|
LL | let _once_ref_2 = &&ONCE_INIT;
| ^^^^^^^^^
@@ -36,7 +36,7 @@ LL | let _once_ref_2 = &&ONCE_INIT;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:60:27
--> tests/ui/borrow_interior_mutable_const/others.rs:71:27
|
LL | let _once_ref_4 = &&&&ONCE_INIT;
| ^^^^^^^^^
@@ -44,7 +44,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:61:26
--> tests/ui/borrow_interior_mutable_const/others.rs:72:26
|
LL | let _once_mut = &mut ONCE_INIT;
| ^^^^^^^^^
@@ -52,7 +52,7 @@ LL | let _once_mut = &mut ONCE_INIT;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:72:14
--> tests/ui/borrow_interior_mutable_const/others.rs:83:14
|
LL | let _ = &ATOMIC_TUPLE;
| ^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL | let _ = &ATOMIC_TUPLE;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:73:14
--> tests/ui/borrow_interior_mutable_const/others.rs:84:14
|
LL | let _ = &ATOMIC_TUPLE.0;
| ^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL | let _ = &ATOMIC_TUPLE.0;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:74:19
--> tests/ui/borrow_interior_mutable_const/others.rs:85:19
|
LL | let _ = &(&&&&ATOMIC_TUPLE).0;
| ^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0;
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:75:14
--> tests/ui/borrow_interior_mutable_const/others.rs:86:14
|
LL | let _ = &ATOMIC_TUPLE.0[0];
| ^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0];
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:76:13
--> tests/ui/borrow_interior_mutable_const/others.rs:87:13
|
LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
| ^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:81:13
--> tests/ui/borrow_interior_mutable_const/others.rs:92:13
|
LL | let _ = ATOMIC_TUPLE.0[0];
| ^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL | let _ = ATOMIC_TUPLE.0[0];
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:86:5
--> tests/ui/borrow_interior_mutable_const/others.rs:97:5
|
LL | CELL.set(2);
| ^^^^
@@ -108,7 +108,7 @@ LL | CELL.set(2);
= help: assign this const to a local or static variable, and use the variable here
error: a `const` item with interior mutability should not be borrowed
--> tests/ui/borrow_interior_mutable_const/others.rs:87:16
--> tests/ui/borrow_interior_mutable_const/others.rs:98:16
|
LL | assert_eq!(CELL.get(), 6);
| ^^^^
+9
View File
@@ -0,0 +1,9 @@
// ICE: #10972
// asked to assemble constituent types of unexpected type: Binder(Foo, [])
#![feature(type_alias_impl_trait)]
use std::fmt::Debug;
type Foo = impl Debug;
const FOO2: Foo = 22_u32;
pub fn main() {}

Some files were not shown because too many files have changed in this diff Show More