From 6e0c456ec4a05ebacf23039af797dbcfff49086c Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Fri, 15 Sep 2023 21:56:10 -0600 Subject: [PATCH 001/107] triagebot no-merges: exclude "Rustup"s, add labels --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 6856bb0ab375..419b3c30deb0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -11,6 +11,8 @@ allow-unauthenticated = [ # Have rustbot inform users about the *No Merge Policy* [no-merges] +exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust +labels = ["has-merge-commits", "S-waiting-on-author"] [autolabel."S-waiting-on-review"] new_pr = true From 77c121e8172377ca5a978a2f107735847dea33ed Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 20 Sep 2023 19:05:51 +0900 Subject: [PATCH 002/107] Warn missing_enforced_import_renames by default --- clippy_lints/src/missing_enforced_import_rename.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 96d83e114a41..fc088710e429 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -17,6 +17,9 @@ declare_clippy_lint! { /// Checks for imports that do not rename the item as specified /// in the `enforce-import-renames` config option. /// + /// Note: Even though this lint is warn-by-default, it will only trigger if + /// import renames are defined in the clippy.toml file. + /// /// ### Why is this bad? /// Consistency is important, if a project has defined import /// renames they should be followed. More practically, some item names are too @@ -38,7 +41,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.55.0"] pub MISSING_ENFORCED_IMPORT_RENAMES, - restriction, + style, "enforce import renames" } From faacd55741785b17d6bdbe3f3319ee6e3079ccab Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Thu, 5 Oct 2023 00:03:04 +0900 Subject: [PATCH 003/107] Fix typo in attrs.rs documenation -> documentation --- clippy_lints/src/attrs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 0546807bac4f..db01ddbde04e 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -183,7 +183,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for empty lines after documenation comments. + /// Checks for empty lines after documentation comments. /// /// ### Why is this bad? /// The documentation comment was most likely meant to be an inner attribute or regular comment. @@ -795,7 +795,7 @@ impl EarlyLintPass for EarlyAttributes { /// Check for empty lines after outer attributes. /// -/// Attributes and documenation comments are both considered outer attributes +/// Attributes and documentation comments are both considered outer attributes /// by the AST. However, the average user likely considers them to be different. /// Checking for empty lines after each of these attributes is split into two different /// lints but can share the same logic. From 31fd282732e15811e916d216d5badd0a56361dd3 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:07:54 +0200 Subject: [PATCH 004/107] [`get_first`]: lint on non-primitive types --- clippy_lints/src/methods/get_first.rs | 2 -- tests/ui/get_first.fixed | 13 ++++++++++--- tests/ui/get_first.rs | 13 ++++++++++--- tests/ui/get_first.stderr | 18 ++++++++++++------ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index ee063adac64a..e7b4564c651e 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_slice_of_primitives; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::LitKind; @@ -20,7 +19,6 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); if cx.tcx.type_of(impl_id).instantiate_identity().is_slice(); - if let Some(_) = is_slice_of_primitives(cx, recv); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { let mut app = Applicability::MachineApplicable; diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index b1a597fc4dd5..a7cdd2a93bac 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -14,17 +14,20 @@ impl Bar { fn main() { let x = vec![2, 3, 5]; - let _ = x.first(); // Use x.first() + let _ = x.first(); + //~^ ERROR: accessing first element with `x.get(0)` let _ = x.get(1); let _ = x[0]; let y = [2, 3, 5]; - let _ = y.first(); // Use y.first() + let _ = y.first(); + //~^ ERROR: accessing first element with `y.get(0)` let _ = y.get(1); let _ = y[0]; let z = &[2, 3, 5]; - let _ = z.first(); // Use z.first() + let _ = z.first(); + //~^ ERROR: accessing first element with `z.get(0)` let _ = z.get(1); let _ = z[0]; @@ -37,4 +40,8 @@ fn main() { let bar = Bar { arr: [0, 1, 2] }; let _ = bar.get(0); // Do not lint, because Bar is struct. + + let non_primitives = [vec![1, 2], vec![3, 4]]; + let _ = non_primitives.first(); + //~^ ERROR: accessing first element with `non_primitives.get(0)` } diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index e27ee4be8c08..cca743c4bf5e 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -14,17 +14,20 @@ impl Bar { fn main() { let x = vec![2, 3, 5]; - let _ = x.get(0); // Use x.first() + let _ = x.get(0); + //~^ ERROR: accessing first element with `x.get(0)` let _ = x.get(1); let _ = x[0]; let y = [2, 3, 5]; - let _ = y.get(0); // Use y.first() + let _ = y.get(0); + //~^ ERROR: accessing first element with `y.get(0)` let _ = y.get(1); let _ = y[0]; let z = &[2, 3, 5]; - let _ = z.get(0); // Use z.first() + let _ = z.get(0); + //~^ ERROR: accessing first element with `z.get(0)` let _ = z.get(1); let _ = z[0]; @@ -37,4 +40,8 @@ fn main() { let bar = Bar { arr: [0, 1, 2] }; let _ = bar.get(0); // Do not lint, because Bar is struct. + + let non_primitives = [vec![1, 2], vec![3, 4]]; + let _ = non_primitives.get(0); + //~^ ERROR: accessing first element with `non_primitives.get(0)` } diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr index 56b4c29a3135..8ee66e33cc81 100644 --- a/tests/ui/get_first.stderr +++ b/tests/ui/get_first.stderr @@ -1,23 +1,29 @@ error: accessing first element with `x.get(0)` --> $DIR/get_first.rs:17:13 | -LL | let _ = x.get(0); // Use x.first() +LL | let _ = x.get(0); | ^^^^^^^^ help: try: `x.first()` | = note: `-D clippy::get-first` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::get_first)]` error: accessing first element with `y.get(0)` - --> $DIR/get_first.rs:22:13 + --> $DIR/get_first.rs:23:13 | -LL | let _ = y.get(0); // Use y.first() +LL | let _ = y.get(0); | ^^^^^^^^ help: try: `y.first()` error: accessing first element with `z.get(0)` - --> $DIR/get_first.rs:27:13 + --> $DIR/get_first.rs:29:13 | -LL | let _ = z.get(0); // Use z.first() +LL | let _ = z.get(0); | ^^^^^^^^ help: try: `z.first()` -error: aborting due to 3 previous errors +error: accessing first element with `non_primitives.get(0)` + --> $DIR/get_first.rs:45:13 + | +LL | let _ = non_primitives.get(0); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()` + +error: aborting due to 4 previous errors From e6f29f1900002d980dd06778a29e73637539d928 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:08:30 +0200 Subject: [PATCH 005/107] dogfood --- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/manual_bits.rs | 4 ++-- clippy_lints/src/methods/search_is_some.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/needless_continue.rs | 4 ++-- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/uninit_vec.rs | 2 +- clippy_lints/src/unnecessary_map_on_constructor.rs | 4 ++-- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/higher.rs | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index f7b3b2358a0b..5fffb27cda2f 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -185,7 +185,7 @@ fn get_vec_push<'tcx>( if let StmtKind::Semi(semi_stmt) = &stmt.kind; if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; // Figure out the parameters for the method call - if let Some(pushed_item) = args.get(0); + if let Some(pushed_item) = args.first(); // Check that the method being called is push() on a Vec if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 6c7c57ba1d6b..552c57d5e025 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let QPath::Resolved(_, count_func_path) = count_func_qpath; - if let Some(segment_zero) = count_func_path.segments.get(0); + if let Some(segment_zero) = count_func_path.segments.first(); if let Some(args) = segment_zero.args; - if let Some(GenericArg::Type(real_ty)) = args.args.get(0); + if let Some(GenericArg::Type(real_ty)) = args.args.first(); if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id); diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index afdb8ce94ac4..04ddaaa2f461 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( if search_method == "find"; if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind; let closure_body = cx.tcx.hir().body(body); - if let Some(closure_arg) = closure_body.params.get(0); + if let Some(closure_arg) = closure_body.params.first(); then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index f2773cad400c..0629dee4f722 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -67,7 +67,7 @@ impl MissingDoc { if_chain! { if let Some(meta) = meta; if let MetaItemKind::List(list) = meta.kind; - if let Some(meta) = list.get(0); + if let Some(meta) = list.first(); if let Some(name) = meta.ident(); then { name.name == sym::include diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 38a75034cd31..377cbef7b99e 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -189,7 +189,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 { - block.stmts.get(0).map_or(false, |stmt| match stmt.kind { + block.stmts.first().map_or(false, |stmt| match stmt.kind { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { if let ast::ExprKind::Continue(ref l) = e.kind { compare_labels(label, l.as_ref()) @@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String { } fn span_of_first_expr_in_block(block: &ast::Block) -> Option { - block.stmts.get(0).map(|stmt| stmt.span) + block.stmts.first().map(|stmt| stmt.span) } #[cfg(test)] diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 9db18c2976c2..2278e41be375 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { - if let Some(s) = block.stmts.get(0) { + if let Some(s) = block.stmts.first() { self.visit_stmt(s); } diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 6756df8e716c..72569e10f058 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt let expr = peel_hir_expr_while(expr, |e| { if let ExprKind::Block(block, _) = e.kind { // Extract the first statement/expression - match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) { + match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) { (None, Some(expr)) => Some(expr), (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr), _ => None, diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 5aa057580e9d..894de0d85c1e 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind && let hir::ExprKind::Path(constructor_path) = constructor.kind - && let Some(arg) = constructor_args.get(0) + && let Some(arg) = constructor_args.first() { if constructor.span.from_expansion() || arg.span.from_expansion() { return; @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { _ => return, } - if let Some(map_arg) = args.get(0) + if let Some(map_arg) = args.first() && let hir::ExprKind::Path(fun) = map_arg.kind { if map_arg.span.from_expansion() { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 0bae7056c4fb..79c04c7c7f4a 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -504,7 +504,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { }, (Some(Constant::Vec(vec)), _) => { if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) { - match vec.get(0) { + match vec.first() { Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), _ => None, diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 802adbd4d2d5..7c1be625bd3a 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -449,7 +449,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - } else if name.ident.name == symbol::kw::Default { return Some(VecInitKind::Default); } else if name.ident.name.as_str() == "with_capacity" { - let arg = args.get(0)?; + let arg = args.first()?; return match constant_simple(cx, cx.typeck_results(), arg) { Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)), _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)), From 010a9b1e6056970ad9b50618f485568f49cf962b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Oct 2023 16:08:07 +1100 Subject: [PATCH 006/107] Rename `Features::active_features`. The word "active" is currently used in two different and confusing ways: - `ACTIVE_FEATURES` actually means "available unstable features" - `Features::active_features` actually means "features declared in the crate's code", which can include feature within `ACTIVE_FEATURES` but also others. (This is also distinct from "enabled" features which includes declared features but also some edition-specific features automatically enabled depending on the edition in use.) This commit changes the `Features::active_features` to `Features::declared_features` which actually matches its meaning. Likewise, `Features::active` becomes `Features::declared`. --- clippy_lints/src/manual_float_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 88db7ae6aece..15c8417e7028 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { if !in_external_macro(cx.sess(), expr.span) && ( matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) - || cx.tcx.features().active(sym!(const_float_classify)) + || cx.tcx.features().declared(sym!(const_float_classify)) ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind From 9de3e6c9281e284f81515345330fb74b0c4ad312 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 26 Sep 2023 23:56:38 -0400 Subject: [PATCH 007/107] Add more diagnostic items for clippy --- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/box_default.rs | 14 +-- clippy_lints/src/casts/cast_ptr_alignment.rs | 19 ++-- .../src/casts/cast_slice_from_raw_parts.rs | 12 +-- clippy_lints/src/create_dir.rs | 4 +- clippy_lints/src/default.rs | 10 +- .../src/default_constructed_unit_structs.rs | 5 +- .../src/default_instead_of_iter_empty.rs | 6 +- clippy_lints/src/exit.rs | 5 +- clippy_lints/src/explicit_write.rs | 28 +++--- clippy_lints/src/from_raw_with_void_ptr.rs | 4 +- clippy_lints/src/instant_subtraction.rs | 6 +- clippy_lints/src/lines_filter_map_ok.rs | 4 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/methods/bytecount.rs | 8 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 19 ++-- .../methods/from_iter_instead_of_collect.rs | 4 +- .../src/methods/inefficient_to_string.rs | 3 +- .../src/methods/iter_out_of_bounds.rs | 10 +- clippy_lints/src/methods/open_options.rs | 8 +- .../src/methods/option_as_ref_deref.rs | 5 +- clippy_lints/src/methods/seek_from_current.rs | 5 +- .../seek_to_start_instead_of_rewind.rs | 6 +- .../methods/suspicious_command_arg_space.rs | 7 +- clippy_lints/src/missing_fields_in_debug.rs | 12 ++- clippy_lints/src/needless_pass_by_value.rs | 4 +- clippy_lints/src/non_canonical_impls.rs | 7 +- .../src/non_octal_unix_permissions.rs | 10 +- .../src/non_send_fields_in_send_ty.rs | 4 +- clippy_lints/src/operators/cmp_owned.rs | 4 +- .../src/permissions_set_readonly_false.rs | 6 +- clippy_lints/src/ptr.rs | 92 ++++++++----------- clippy_lints/src/rc_clone_in_vec_init.rs | 9 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/size_of_in_element_count.rs | 22 ++--- clippy_lints/src/swap_ptr_to_ref.rs | 6 +- clippy_lints/src/unnamed_address.rs | 4 +- clippy_lints/src/unused_peekable.rs | 10 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/paths.rs | 48 ---------- clippy_utils/src/ty.rs | 6 +- .../unnecessary_def_path_hardcoded_path.rs | 4 +- ...unnecessary_def_path_hardcoded_path.stderr | 4 +- 45 files changed, 190 insertions(+), 270 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 7dd808a7b3b7..accff9b0a34c 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -287,5 +287,5 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { } fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool { - match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT) + matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RefCellRef | sym::RefCellRefMut)) } diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index fa9c525fc08d..3f1ff66b8cf6 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::ty::expr_sig; -use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths}; +use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind}; +use rustc_hir::{def::Res, Block, Expr, ExprKind, Local, Node, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -55,7 +55,7 @@ impl LateLintPass<'_> for BoxDefault { expr.span, "`Box::new(_)` of default value", "try", - if is_plain_default(arg_path) || given_type(cx, expr) { + if is_plain_default(cx, arg_path) || given_type(cx, expr) { "Box::default()".into() } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) @@ -68,11 +68,13 @@ impl LateLintPass<'_> for BoxDefault { } } -fn is_plain_default(arg_path: &Expr<'_>) -> bool { +fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { // we need to match the actual path so we don't match e.g. "u8::default" - if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind { + if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind + && let Res::Def(_, def_id) = path.res + { // avoid generic parameters - match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none()) + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) && path.segments.iter().all(|seg| seg.args.is_none()) } else { false } diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 1de69122101c..9e8ef2825374 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_c_void; -use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, match_any_def_paths, paths}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant}; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; @@ -75,16 +75,17 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } }, ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => { - static PATHS: &[&[&str]] = &[ - paths::PTR_READ_UNALIGNED.as_slice(), - paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(), - paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(), - ]; - if let ExprKind::Path(path) = &func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && (match_any_def_paths(cx, def_id, PATHS).is_some() - || cx.tcx.is_diagnostic_item(sym::ptr_write_unaligned, def_id)) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some( + sym::ptr_write_unaligned + | sym::ptr_read_unaligned + | sym::intrinsics_unaligned_volatile_load + | sym::intrinsics_unaligned_volatile_store + ) + ) { true } else { diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 5e0123842b04..eb0f75b2f605 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; use super::CAST_SLICE_FROM_RAW_PARTS; @@ -17,12 +17,10 @@ enum RawPartsKind { } fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { - if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) { - Some(RawPartsKind::Immutable) - } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) { - Some(RawPartsKind::Mutable) - } else { - None + match cx.tcx.get_diagnostic_name(did)? { + sym::slice_from_raw_parts => Some(RawPartsKind::Immutable), + sym::slice_from_raw_parts_mut => Some(RawPartsKind::Mutable), + _ => None, } } diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 878248a6bdc8..2bca695c43b1 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ impl LateLintPass<'_> for CreateDir { if let ExprKind::Call(func, [arg, ..]) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); + if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 763ad0264ad9..5787f19cc6cb 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,9 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{ - any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, -}; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -14,7 +12,7 @@ use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -91,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); if !is_update_syntax_base(cx, expr); // Detect and ignore ::default() because these calls do explicitly name the type. if let QPath::Resolved(None, _path) = qpath; @@ -268,7 +266,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); then { // right hand side of assignment is `Default::default` - match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD) + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) } else { false } diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index a294c6937877..0676777e7968 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_ty_alias, match_def_path, paths}; +use clippy_utils::is_ty_alias; use hir::def::Res; use hir::ExprKind; use rustc_errors::Applicability; @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -63,7 +64,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { // `::Assoc` cannot be used as a constructor if !is_alias(*base); if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); // make sure we have a struct with no fields (unit struct) if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); if def.is_struct(); diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 572990aaba10..3d6d257e386b 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::{last_path_segment, match_def_path, paths}; +use clippy_utils::last_path_segment; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::SyntaxContext; +use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && let TyKind::Path(ty_path) = &ty.kind && let QPath::Resolved(None, path) = ty_path && let def::Res::Def(_, def_id) = &path.res - && match_def_path(cx, *def_id, &paths::ITER_EMPTY) + && cx.tcx.is_diagnostic_item(sym::IterEmpty, *def_id) && let ctxt = expr.span.ctxt() && ty.span.ctxt() == ctxt { diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 8ba6a9e48763..5de79133c7dc 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_entrypoint_fn, match_def_path, paths}; +use clippy_utils::{is_entrypoint_fn}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit { if let ExprKind::Call(path_expr, _args) = e.kind; if let ExprKind::Path(ref path) = path_expr.kind; if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::EXIT); + if cx.tcx.is_diagnostic_item(sym::process_exit, def_id); let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id; if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent); // If the next item up is a function we check if it is an entry point diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index b612cc00bf97..6f6177340f48 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_expn_of, match_function_call, paths}; +use clippy_utils::{is_expn_of, path_def_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -47,18 +47,19 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt - && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind) + && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind) + && let ExprKind::Call(write_recv_path, _) = write_recv.kind && write_fun.ident.name == sym!(write_fmt) - // match calls to std::io::stdout() / std::io::stderr () - && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { - Some("stdout") - } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { - Some("stderr") - } else { - None - } - && let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) + && let Some(def_id) = path_def_id(cx, write_recv_path) { + // match calls to std::io::stdout() / std::io::stderr () + let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::io_stdout) => ("stdout", ""), + Some(sym::io_stderr) => ("stderr", "e"), + _ => return, + }; + let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { return; }; + // ordering is important here, since `writeln!` uses `write!` internally let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { Some("writeln") @@ -67,11 +68,6 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { } else { None }; - let prefix = if dest_name == "stderr" { - "e" - } else { - "" - }; // We need to remove the last trailing newline from the string because the // underlying `fmt::write` function doesn't know whether `println!` or `print!` was diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 5e859d97c624..d82ea6d2fc80 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_c_void; -use clippy_utils::{match_def_path, path_def_id, paths}; +use clippy_utils::path_def_id; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -68,7 +68,7 @@ fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static s } } - if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) { + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RcWeak | sym::ArcWeak)) { Some("Weak") } else { None diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 8df7dfb8b9e5..a1a115f6d79f 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -130,11 +130,7 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); - - match expr_ty.kind() { - rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT), - _ => false, - } + ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant) } fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 49425ff0a8e0..ac949b672609 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; @@ -62,7 +62,7 @@ impl LateLintPass<'_> for LinesFilterMapOk { if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && is_trait_method(cx, expr, sym::Iterator) && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && - match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) { let lint = match &fm_arg.kind { // Detect `Result::ok` diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 1a69a48c582b..f923413f4348 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -135,7 +135,7 @@ fn check_to_owned( if msrv.meets(msrvs::STRING_RETAIN) && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) - && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) + && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id) && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs index f490a7175540..35370355f834 100644 --- a/clippy_lints/src/methods/bytecount.rs +++ b/clippy_lints/src/methods/bytecount.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; +use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; @@ -25,9 +25,9 @@ pub(super) fn check<'tcx>( if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; if let ExprKind::Binary(ref op, l, r) = body.value.kind; if op.node == BinOpKind::Eq; - if match_type(cx, + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), - &paths::SLICE_ITER); + sym::SliceIter); let operand_is_arg = |expr| { let expr = peel_ref_operators(cx, peel_blocks(expr)); path_to_local_id(expr, arg_id) diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index ddf3c9f27df2..926bd06bacbd 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,7 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -22,15 +20,14 @@ pub(super) fn check( } let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if let ty::Adt(_, subst) = obj_ty.kind() { - let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { - "Rc" - } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) { - "Arc" - } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) { - "Weak" - } else { - return; + if let ty::Adt(adt, subst) = obj_ty.kind() + && let Some(name) = cx.tcx.get_diagnostic_name(adt.did()) + { + let caller_type = match name { + sym::Rc => "Rc", + sym::Arc => "Arc", + sym::RcWeak | sym::ArcWeak => "Weak", + _ => return, }; // Sometimes unnecessary ::<_> after Rc/Arc/Weak diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 66dfce3682b5..4040d3a5fe13 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_path_def_path, paths, sugg}; +use clippy_utils::{is_path_diagnostic_item, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -13,7 +13,7 @@ use super::FROM_ITER_INSTEAD_OF_COLLECT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { if_chain! { - if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD); + if is_path_diagnostic_item(cx, func, sym::from_iter_fn); let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 631741d9290c..6686d42c95f8 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -22,7 +21,7 @@ pub fn check( if_chain! { if args.is_empty() && method_name == sym::to_string; if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); + if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did); if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id); let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver); let self_ty = args.type_at(0); diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs index 79c6d63254b2..99ea7f03df4e 100644 --- a/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::higher::VecArgs; -use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths}; +use clippy_utils::{expr_or_init, is_trait_method}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -26,14 +26,14 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> }; let did = adt.did(); - if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) { + if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) { // For array::IntoIter, the length is the second generic // parameter. substs .const_at(1) .try_eval_target_usize(cx.tcx, cx.param_env) .map(u128::from) - } else if match_def_path(cx, did, &paths::SLICE_ITER) + } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did) && let ExprKind::MethodCall(_, recv, ..) = iter.kind { if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { @@ -47,9 +47,9 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> } else { None } - } else if match_def_path(cx, did, &paths::ITER_EMPTY) { + } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) { Some(0) - } else if match_def_path(cx, did, &paths::ITER_ONCE) { + } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) { Some(1) } else { None diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index 1c664e76d74f..c0f5a2799451 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::source_map::{Span, Spanned}; +use rustc_span::sym; use super::NONSENSICAL_OPEN_OPTIONS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions) { let mut options = Vec::new(); get_open_options(cx, recv, &mut options); @@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() { + if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() { let argument_option = match arguments[0].kind { ExprKind::Lit(span) => { if let Spanned { diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 3e33f9193374..d0c27f9631f7 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -32,8 +32,7 @@ pub(super) fn check( return; } - let deref_aliases: [&[&str]; 8] = [ - &paths::DEREF_MUT_TRAIT_METHOD, + let deref_aliases: [&[&str]; 7] = [ &paths::CSTRING_AS_C_STR, &paths::OS_STRING_AS_OS_STR, &paths::PATH_BUF_AS_PATH, @@ -49,6 +48,7 @@ pub(super) fn check( .opt_def_id() .map_or(false, |fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) + || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) || deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) }) }, @@ -70,6 +70,7 @@ pub(super) fn check( then { let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) + || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) } else { false diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index f3d6a15ede01..4ea87027a9e6 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -2,18 +2,19 @@ use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use clippy_utils::{match_def_path, paths}; use super::SEEK_FROM_CURRENT; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) { + if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) { if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) { let mut applicability = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability); diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 787e9e0ebd24..50d4de7a6800 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths}; +use clippy_utils::{is_expr_used_or_unified, match_def_path, paths}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::SEEK_TO_START_INSTEAD_OF_REWIND; @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( return; } - if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && + if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) && implements_trait(cx, ty, seek_trait_id, &[]) && let ExprKind::Call(func, args1) = arg.kind && let ExprKind::Path(ref path) = func.kind && diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs index bc8f01767641..8959e2c1d75f 100644 --- a/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::{Applicability, Diagnostic}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Span}; use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; @@ -11,7 +10,7 @@ use super::SUSPICIOUS_COMMAND_ARG_SPACE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if match_type(cx, ty, &paths::STD_PROCESS_COMMAND) + if is_type_diagnostic_item(cx, ty, sym::Command) && let hir::ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(s, _) = &lit.node && let Some((arg1, arg2)) = s.as_str().split_once(' ') diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 2f63b9b9f0b8..f0b865be8042 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{for_each_expr, Visitable}; -use clippy_utils::{is_path_lang_item, paths}; +use clippy_utils::is_path_lang_item; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -114,9 +114,11 @@ fn should_lint<'tcx>( if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); - if path.ident.name == sym::debug_struct && match_type(cx, recv_ty, &paths::FORMATTER) { + if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) { has_debug_struct = true; - } else if path.ident.name == sym!(finish_non_exhaustive) && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) { + } else if path.ident.name == sym!(finish_non_exhaustive) + && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) + { has_finish_non_exhaustive = true; } } @@ -137,7 +139,7 @@ fn as_field_call<'tcx>( ) -> Option { if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind && let recv_ty = typeck_results.expr_ty(recv).peel_refs() - && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) + && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) && path.ident.name == sym::field && let ExprKind::Lit(lit) = &debug_field.kind && let LitKind::Str(sym, ..) = lit.node diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5ee26966fa71..6d7df2eac629 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -4,7 +4,7 @@ use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; -use clippy_utils::{get_trait_def_id, is_self, paths}; +use clippy_utils::is_self; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diagnostic}; @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { need!(cx.tcx.lang_items().fn_trait()), need!(cx.tcx.lang_items().fn_once_trait()), need!(cx.tcx.lang_items().fn_mut_trait()), - need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)), + need!(cx.tcx.get_diagnostic_item(sym::RangeBounds)), ]; let sized_trait = need!(cx.tcx.lang_items().sized_trait()); diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 20b4b4f03ed4..4be140647fcc 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::paths::ORD_CMP; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core}; +use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; @@ -261,7 +260,7 @@ fn self_cmp_call<'tcx>( match cmp_expr.kind { ExprKind::Call(path, [_self, _other]) => path_res(cx, path) .opt_def_id() - .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)), + .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)), ExprKind::MethodCall(_, _, [_other], ..) => { // We can set this to true here no matter what as if it's a `MethodCall` and goes to the // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp` @@ -273,7 +272,7 @@ fn self_cmp_call<'tcx>( cx.tcx .typeck(def_id) .type_dependent_def_id(cmp_expr.hir_id) - .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)) + .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)) }, _ => false, } diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index e1de494eb41c..d47728f190ab 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -45,13 +44,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { - let obj_ty = cx.typeck_results().expr_ty(func).peel_refs(); - if_chain! { + if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def(); if (path.ident.name == sym!(mode) - && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS) - || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder))) - || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS)); + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder))) + || (path.ident.name == sym!(set_mode) + && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); if let ExprKind::Lit(_) = param.kind; if param.span.ctxt() == expr.span.ctxt(); diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index c5e777c20702..d388dfc08f3b 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; +use clippy_utils::is_lint_allowed; use rustc_ast::ImplPolarity; use rustc_hir::def_id::DefId; use rustc_hir::{FieldDef, Item, ItemKind, Node}; @@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b return true; }, ty::Adt(adt_def, _) => { - if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) { + if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) { return true; } }, diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index d3de9699fe9d..136642d69dca 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{match_def_path, path_def_id, paths}; +use clippy_utils::path_def_id; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -50,7 +50,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) }, ExprKind::Call(path, [arg]) if path_def_id(cx, path).map_or(false, |did| { - if match_def_path(cx, did, &paths::FROM_STR_METHOD) { + if cx.tcx.is_diagnostic_item(sym::from_str_method, did) { true } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) { !is_copy(cx, typeck.expr_ty(expr)) diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index 664d44d6504d..f3089d716ff1 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -31,7 +31,7 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind - && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) && path.ident.name == sym!(set_readonly) && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 7dabdcd58ec2..310051efc508 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -4,9 +4,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths}; +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; use hir::LifetimeName; -use if_chain::if_chain; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdMap; @@ -271,60 +270,43 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B. - const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 13] = [ - (&paths::SLICE_FROM_RAW_PARTS, &[0]), - (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]), - (&paths::PTR_COPY, &[0, 1]), - (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]), - (&paths::PTR_READ, &[0]), - (&paths::PTR_READ_UNALIGNED, &[0]), - (&paths::PTR_READ_VOLATILE, &[0]), - (&paths::PTR_REPLACE, &[0]), - (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]), - (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]), - (&paths::PTR_SWAP, &[0, 1]), - (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]), - (&paths::PTR_WRITE_BYTES, &[0]), - ]; - let invalid_null_ptr_usage_table_diag_items: [(Option, &[usize]); 3] = [ - (cx.tcx.get_diagnostic_item(sym::ptr_write), &[0]), - (cx.tcx.get_diagnostic_item(sym::ptr_write_unaligned), &[0]), - (cx.tcx.get_diagnostic_item(sym::ptr_write_volatile), &[0]), - ]; + if let ExprKind::Call(fun, args) = expr.kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) + { + // `arg` positions where null would cause U.B. + let arg_indices: &[_] = match name { + sym::ptr_read + | sym::ptr_read_unaligned + | sym::ptr_read_volatile + | sym::ptr_replace + | sym::ptr_slice_from_raw_parts + | sym::ptr_slice_from_raw_parts_mut + | sym::ptr_write + | sym::ptr_write_bytes + | sym::ptr_write_unaligned + | sym::ptr_write_volatile + | sym::slice_from_raw_parts + | sym::slice_from_raw_parts_mut => &[0], + sym::ptr_copy + | sym::ptr_copy_nonoverlapping + | sym::ptr_swap + | sym::ptr_swap_nonoverlapping => &[0, 1], + _ => return, + }; - if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::>(); - if let Some(arg_indices) = INVALID_NULL_PTR_USAGE_TABLE - .iter() - .find_map(|&(fn_path, indices)| if fn_path == fun_def_path { Some(indices) } else { None }) - .or_else(|| { - invalid_null_ptr_usage_table_diag_items - .iter() - .find_map(|&(def_id, indices)| { - if def_id == Some(fun_def_id) { - Some(indices) - } else { - None - } - }) - }); - then { - for &arg_idx in arg_indices { - if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) { - span_lint_and_sugg( - cx, - INVALID_NULL_PTR_USAGE, - arg.span, - "pointer must be non-null", - "change this to", - "core::ptr::NonNull::dangling().as_ptr()".to_string(), - Applicability::MachineApplicable, - ); - } + for &arg_idx in arg_indices { + if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) { + span_lint_and_sugg( + cx, + INVALID_NULL_PTR_USAGE, + arg.span, + "pointer must be non-null", + "change this to", + "core::ptr::NonNull::dangling().as_ptr()".to_string(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 8e85c55e7563..1a127c2bcf68 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -2,11 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{indent_of, snippet}; -use clippy_utils::ty::match_type; -use clippy_utils::{last_path_segment, paths}; +use clippy_utils::last_path_segment; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span, Symbol}; @@ -133,8 +133,9 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { return Some((symbol, func.span)); } - let ty_path = cx.typeck_results().expr_ty(expr); - if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) { + if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) + { return Some((Symbol::intern("Weak"), func.span)); } } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index e36adef555e6..2c0086b09813 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -99,8 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind)); let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) - || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) - || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) + || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) + || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id) && is_type_lang_item(cx, arg_ty, LangItem::String)); let from_deref = !from_borrow diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index bd783b4e0054..b940cac6047b 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -2,7 +2,6 @@ //! expecting a count of T use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -67,16 +66,6 @@ fn get_pointee_ty_and_count_expr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { - const FUNCTIONS: [&[&str]; 8] = [ - &paths::PTR_COPY_NONOVERLAPPING, - &paths::PTR_COPY, - &paths::PTR_WRITE_BYTES, - &paths::PTR_SWAP_NONOVERLAPPING, - &paths::PTR_SLICE_FROM_RAW_PARTS, - &paths::PTR_SLICE_FROM_RAW_PARTS_MUT, - &paths::SLICE_FROM_RAW_PARTS, - &paths::SLICE_FROM_RAW_PARTS_MUT, - ]; const METHODS: [&str; 11] = [ "write_bytes", "copy_to", @@ -97,7 +86,16 @@ fn get_pointee_ty_and_count_expr<'tcx>( if let ExprKind::Call(func, [.., count]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some( + sym::ptr_copy + | sym::ptr_copy_nonoverlapping + | sym::ptr_slice_from_raw_parts + | sym::ptr_slice_from_raw_parts_mut + | sym::ptr_swap_nonoverlapping + | sym::ptr_write_bytes + | sym::slice_from_raw_parts + | sym::slice_from_raw_parts_mut + )); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next(); diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index d085dda3582b..3685432a2539 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_context; -use clippy_utils::{match_def_path, path_def_id, paths}; +use clippy_utils::path_def_id; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{Span, SyntaxContext}; +use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -42,7 +42,7 @@ impl LateLintPass<'_> for SwapPtrToRef { fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind && let Some(fn_id) = path_def_id(cx, fn_expr) - && match_def_path(cx, fn_id, &paths::MEM_SWAP) + && cx.tcx.is_diagnostic_item(sym::mem_swap, fn_id) && let ctxt = e.span.ctxt() && let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt) && let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt) diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index dea8a1e35bbb..996e7edf5573 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -96,7 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress { if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_EQ); + if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id); let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0); if ty_param.is_trait(); then { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 4ee16d9a5e4a..db91beec0efa 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators}; +use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; +use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { // Don't lint `Peekable`s returned from a block if let Some(expr) = block.expr && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr)) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { return; } @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { && !init.span.from_expansion() && let Some(ty) = cx.typeck_results().expr_ty_opt(init) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { let mut vis = PeekableVisitor::new(cx, binding); @@ -222,7 +222,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool { if let Some(ty) = cx.typeck_results().expr_ty_opt(arg) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { true } else { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index f32e7edad6cb..3cc91838c000 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths}; +use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::DefKind; @@ -331,7 +331,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); if_chain! { - if match_def_path(cx, def_id, &paths::TRY_FROM); + if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id); if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, args) = a.kind(); if let Some(a_type) = args.types().next(); diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 802adbd4d2d5..741f9f54883d 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -457,7 +457,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - }; }, ExprKind::Path(QPath::Resolved(_, path)) - if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) + if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => { return Some(VecInitKind::Default); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 13da79fba7e8..64ca2ff78736 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2076,7 +2076,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool match expr.kind { ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), - _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), + _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)), } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 2fb24b5c7ed9..1f2bb16f459f 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -25,17 +25,12 @@ pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", " pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; -pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; -pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; #[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; #[cfg(feature = "internal")] pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; -pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; -pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; -pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates @@ -48,8 +43,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; #[cfg(feature = "internal")] pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; -pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; -pub const ITER_ONCE: [&str; 5] = ["core", "iter", "sources", "once", "Once"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; @@ -59,10 +52,8 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; -pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; #[cfg(feature = "internal")] pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; -pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; @@ -71,28 +62,9 @@ pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "Rw pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; -pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"]; -pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; -pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; -pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; -pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; -pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"]; -pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"]; -pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"]; -pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"]; -pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"]; -pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"]; -pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"]; -pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"]; -pub const PTR_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"]; -pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"]; -pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; -pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; -pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"]; -pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"]; pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"]; pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"]; @@ -101,21 +73,11 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; -pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_GET: [&str; 4] = ["core", "slice", "", "get"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_INTO: [&str; 4] = ["core", "slice", "", "iter"]; -pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; -pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; -pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; -pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; -pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; -pub const STD_IO_LINES: [&str; 3] = ["std", "io", "Lines"]; -pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; -pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; @@ -136,13 +98,11 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; #[cfg(feature = "internal")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; -pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"]; -pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"]; @@ -150,18 +110,10 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; -pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; -pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; -pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; -pub const INSTANT: [&str; 3] = ["std", "time", "Instant"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; -pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"]; -pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"]; -pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"]; #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; -pub const ARRAY_INTO_ITER: [&str; 4] = ["core", "array", "iter", "IntoIter"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 604dc76912e6..2d305a63eca1 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -31,7 +31,7 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; use std::iter; -use crate::{match_def_path, path_res, paths}; +use crate::{match_def_path, path_res}; mod type_certainty; pub use type_certainty::expr_type_is_certain; @@ -461,10 +461,8 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { else if is_type_lang_item(cx, ty, LangItem::OwnedBox) || matches!( get_type_diagnostic_name(cx, ty), - Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type) + Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type | sym::RcWeak | sym::ArcWeak) ) - || match_type(cx, ty, &paths::WEAK_RC) - || match_type(cx, ty, &paths::WEAK_ARC) { // Check all of the generic arguments. if let ty::Adt(_, subs) = ty.kind() { diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs index b5ff3a542056..60be29788134 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs @@ -11,6 +11,6 @@ fn main() { const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - // Don't lint, not yet a diagnostic or language item - const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; + // Don't lint, not a diagnostic or language item + const OPS_MOD: [&str; 5] = ["core", "ops"]; } diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index 58b1fd92b5dc..076786329cd9 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"] error: hardcoded path to a diagnostic item --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 | -LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const OPS_MOD: [&str; 5] = ["core", "ops"]; + | ^^^^^^^^^^^^^^^ | = help: convert all references to use `sym::deref_method` From ddd1564e5d723c7c380ab0656c91857d99391a5f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 11:18:34 +0200 Subject: [PATCH 008/107] Add regression test for #11610 about mutable usage of argument in async function for the `needless_pass_by_ref_mut` lint --- tests/ui/needless_pass_by_ref_mut.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index 39d76f999002..93f94b384af2 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -270,6 +270,12 @@ pub async fn closure4(n: &mut usize) { })(); } +// Should not warn. +async fn _f(v: &mut Vec<()>) { + let x = || v.pop(); + _ = || || x; +} + fn main() { let mut u = 0; let mut v = vec![0]; From 8ebed4cc1a2e21844c58f3b0bfbad1a069bb09b6 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 6 Oct 2023 17:35:45 +0200 Subject: [PATCH 009/107] Merge commit 'b105fb4c39bc1a010807a6c076193cef8d93c109' into clippyup --- CHANGELOG.md | 97 ++++++- Cargo.toml | 4 +- book/src/development/adding_lints.md | 2 +- book/src/lint_configuration.md | 1 + clippy_dev/src/new_lint.rs | 63 ++++- clippy_lints/Cargo.toml | 5 +- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/enum_clike.rs | 4 +- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/ignored_unit_patterns.rs | 4 + clippy_lints/src/implicit_hasher.rs | 5 +- clippy_lints/src/items_after_test_module.rs | 108 +++++--- clippy_lints/src/iter_without_into_iter.rs | 249 ++++++++++++++++++ clippy_lints/src/lib.rs | 4 + clippy_lints/src/manual_float_methods.rs | 4 +- clippy_lints/src/manual_hash_one.rs | 133 ++++++++++ clippy_lints/src/manual_let_else.rs | 4 +- clippy_lints/src/manual_non_exhaustive.rs | 22 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 6 +- clippy_lints/src/methods/mod.rs | 13 +- .../src/methods/unnecessary_literal_unwrap.rs | 11 +- clippy_lints/src/missing_assert_message.rs | 4 + .../src/mixed_read_write_in_expression.rs | 7 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 4 +- clippy_lints/src/non_canonical_impls.rs | 2 +- clippy_lints/src/operators/mod.rs | 4 +- clippy_lints/src/raw_strings.rs | 30 +-- clippy_lints/src/redundant_locals.rs | 36 +-- clippy_lints/src/std_instead_of_core.rs | 6 +- clippy_lints/src/utils/conf.rs | 43 ++- clippy_lints/src/wildcard_imports.rs | 1 + clippy_lints/src/write.rs | 142 +++++++--- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/consts.rs | 69 +++-- clippy_utils/src/lib.rs | 31 ++- clippy_utils/src/msrvs.rs | 2 +- clippy_utils/src/visitors.rs | 44 ++++ declare_clippy_lint/Cargo.toml | 2 +- rust-toolchain | 2 +- src/driver.rs | 55 ++-- src/main.rs | 63 +++-- tests/ui/auxiliary/proc_macro_derive.rs | 28 ++ tests/ui/ignored_unit_patterns.fixed | 15 ++ tests/ui/ignored_unit_patterns.rs | 15 ++ tests/ui/ignored_unit_patterns.stderr | 24 +- tests/ui/infinite_loop.rs | 2 - tests/ui/infinite_loop.stderr | 33 +-- tests/ui/into_iter_without_iter.rs | 124 +++++++++ tests/ui/into_iter_without_iter.stderr | 114 ++++++++ .../after_proc_macros.rs | 11 + .../auxiliary/submodule.rs | 4 + .../block_module.stderr | 2 - .../items_after_test_module/in_submodule.rs | 8 + .../in_submodule.stderr | 14 + .../multiple_modules.rs | 11 + .../{block_module.rs => root_module.fixed} | 15 +- .../ui/items_after_test_module/root_module.rs | 22 ++ .../root_module.stderr | 20 ++ tests/ui/iter_without_into_iter.rs | 120 +++++++++ tests/ui/iter_without_into_iter.stderr | 150 +++++++++++ tests/ui/let_underscore_future.rs | 2 - tests/ui/let_underscore_future.stderr | 17 +- tests/ui/manual_hash_one.fixed | 89 +++++++ tests/ui/manual_hash_one.rs | 89 +++++++ tests/ui/manual_hash_one.stderr | 56 ++++ tests/ui/manual_let_else_match.fixed | 4 + tests/ui/manual_let_else_match.rs | 8 + tests/ui/manual_let_else_match.stderr | 12 +- tests/ui/manual_non_exhaustive_enum.rs | 3 +- tests/ui/manual_non_exhaustive_enum.stderr | 20 +- tests/ui/mut_key.rs | 2 - tests/ui/mut_key.stderr | 41 ++- tests/ui/mut_reference.rs | 2 - tests/ui/mut_reference.stderr | 17 +- tests/ui/needless_pass_by_ref_mut.rs | 1 + tests/ui/needless_pass_by_ref_mut.stderr | 42 +-- tests/ui/needless_raw_string.fixed | 4 + tests/ui/needless_raw_string.rs | 4 + tests/ui/needless_raw_string.stderr | 46 +++- tests/ui/needless_raw_string_hashes.stderr | 30 +-- tests/ui/print_literal.fixed | 18 +- tests/ui/print_literal.rs | 18 +- tests/ui/print_literal.stderr | 156 +++++++---- tests/ui/redundant_locals.rs | 37 +++ tests/ui/redundant_locals.stderr | 139 ++++++---- tests/ui/should_impl_trait/method_list_2.rs | 2 - .../ui/should_impl_trait/method_list_2.stderr | 36 +-- tests/ui/slow_vector_initialization.rs | 2 - tests/ui/slow_vector_initialization.stderr | 11 +- tests/ui/std_instead_of_core.fixed | 11 + tests/ui/std_instead_of_core.rs | 11 + tests/ui/std_instead_of_core.stderr | 22 +- tests/ui/wildcard_imports.fixed | 28 ++ tests/ui/wildcard_imports.rs | 28 ++ tests/ui/wildcard_imports.stderr | 38 +-- .../wildcard_imports_2021.edition2018.fixed | 28 ++ .../wildcard_imports_2021.edition2018.stderr | 38 +-- .../wildcard_imports_2021.edition2021.fixed | 28 ++ .../wildcard_imports_2021.edition2021.stderr | 38 +-- tests/ui/wildcard_imports_2021.rs | 28 ++ tests/ui/write_literal.fixed | 14 +- tests/ui/write_literal.rs | 14 +- tests/ui/write_literal.stderr | 106 ++++---- tests/ui/write_literal_2.rs | 16 +- tests/ui/write_literal_2.stderr | 82 ++---- 108 files changed, 2669 insertions(+), 800 deletions(-) create mode 100644 clippy_lints/src/iter_without_into_iter.rs create mode 100644 clippy_lints/src/manual_hash_one.rs create mode 100644 tests/ui/into_iter_without_iter.rs create mode 100644 tests/ui/into_iter_without_iter.stderr create mode 100644 tests/ui/items_after_test_module/after_proc_macros.rs create mode 100644 tests/ui/items_after_test_module/auxiliary/submodule.rs delete mode 100644 tests/ui/items_after_test_module/block_module.stderr create mode 100644 tests/ui/items_after_test_module/in_submodule.rs create mode 100644 tests/ui/items_after_test_module/in_submodule.stderr create mode 100644 tests/ui/items_after_test_module/multiple_modules.rs rename tests/ui/items_after_test_module/{block_module.rs => root_module.fixed} (86%) create mode 100644 tests/ui/items_after_test_module/root_module.rs create mode 100644 tests/ui/items_after_test_module/root_module.stderr create mode 100644 tests/ui/iter_without_into_iter.rs create mode 100644 tests/ui/iter_without_into_iter.stderr create mode 100644 tests/ui/manual_hash_one.fixed create mode 100644 tests/ui/manual_hash_one.rs create mode 100644 tests/ui/manual_hash_one.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9ab1e2402c..fef25ad8635a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,101 @@ document. ## Unreleased / Beta / In Rust Nightly -[37f4c172...master](https://github.com/rust-lang/rust-clippy/compare/37f4c172...master) +[1e8fdf49...master](https://github.com/rust-lang/rust-clippy/compare/1e8fdf49...master) + +## Rust 1.73 + +Current stable, released 2023-10-05 + +[View all 103 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-07-02T12%3A24%3A40Z..2023-08-11T11%3A09%3A56Z+base%3Amaster) + +### New Lints + +* [`impossible_comparisons`] + [#10843](https://github.com/rust-lang/rust-clippy/pull/10843) +* [`redundant_comparisons`] + [#10843](https://github.com/rust-lang/rust-clippy/pull/10843) +* [`ignored_unit_patterns`] + [#11242](https://github.com/rust-lang/rust-clippy/pull/11242) +* [`readonly_write_lock`] + [#11210](https://github.com/rust-lang/rust-clippy/pull/11210) +* [`filter_map_bool_then`] + [#11115](https://github.com/rust-lang/rust-clippy/pull/11115) +* [`needless_return_with_question_mark`] + [#11031](https://github.com/rust-lang/rust-clippy/pull/11031) +* [`redundant_guards`] + [#10955](https://github.com/rust-lang/rust-clippy/pull/10955) +* [`redundant_locals`] + [#10885](https://github.com/rust-lang/rust-clippy/pull/10885) +* [`absolute_paths`] + [#11003](https://github.com/rust-lang/rust-clippy/pull/11003) +* [`error_impl_error`] + [#11107](https://github.com/rust-lang/rust-clippy/pull/11107) +* [`iter_skip_zero`] + [#11046](https://github.com/rust-lang/rust-clippy/pull/11046) +* [`string_lit_chars_any`] + [#11052](https://github.com/rust-lang/rust-clippy/pull/11052) +* [`four_forward_slashes`] + [#11140](https://github.com/rust-lang/rust-clippy/pull/11140) +* [`format_collect`] + [#11116](https://github.com/rust-lang/rust-clippy/pull/11116) +* [`needless_pass_by_ref_mut`] + [#10900](https://github.com/rust-lang/rust-clippy/pull/10900) +* [`manual_is_infinite`] + [#11049](https://github.com/rust-lang/rust-clippy/pull/11049) +* [`manual_is_finite`] + [#11049](https://github.com/rust-lang/rust-clippy/pull/11049) +* [`incorrect_partial_ord_impl_on_ord_type`] + [#10788](https://github.com/rust-lang/rust-clippy/pull/10788) +* [`read_line_without_trim`] + [#10970](https://github.com/rust-lang/rust-clippy/pull/10970) +* [`type_id_on_box`] + [#10987](https://github.com/rust-lang/rust-clippy/pull/10987) + +### Moves and Deprecations + +* Renamed `unwrap_or_else_default` to [`unwrap_or_default`] + [#10120](https://github.com/rust-lang/rust-clippy/pull/10120) +* Moved [`tuple_array_conversions`] to `pedantic` (Now allow-by-default) + [#11146](https://github.com/rust-lang/rust-clippy/pull/11146) +* Moved [`arc_with_non_send_sync`] to `suspicious` (Now warn-by-default) + [#11104](https://github.com/rust-lang/rust-clippy/pull/11104) +* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default) + [#11415](https://github.com/rust-lang/rust-clippy/pull/11415) + +### Enhancements + +* [`unwrap_used`]: No longer lints on the never-type or never-like enums + [#11252](https://github.com/rust-lang/rust-clippy/pull/11252) +* [`expect_used`]: No longer lints on the never-type or never-like enums + [#11252](https://github.com/rust-lang/rust-clippy/pull/11252) + +### False Positive Fixes + +* [`panic_in_result_fn`]: No longer triggers on `todo!`, `unimplemented!`, `unreachable!` + [#11123](https://github.com/rust-lang/rust-clippy/pull/11123) + +### Suggestion Fixes/Improvements + +* [`semicolon_if_nothing_returned`]: The suggestion is now machine-applicable with rustfix + [#11083](https://github.com/rust-lang/rust-clippy/pull/11083) + +### ICE Fixes + +* [`filter_map_bool_then`]: No longer crashes on late-bound regions + [#11318](https://github.com/rust-lang/rust-clippy/pull/11318) +* [`unwrap_or_default`]: No longer crashes on alias types for local items + [#11258](https://github.com/rust-lang/rust-clippy/pull/11258) +* [`unnecessary_literal_unwrap`]: No longer crashes on `None.unwrap_or_default()` + [#11106](https://github.com/rust-lang/rust-clippy/pull/11106) +* Fixed MIR-related ICE + [#11130](https://github.com/rust-lang/rust-clippy/pull/11130) +* [`missing_fields_in_debug`]: No longer crashes on non-ADT self types + [#11069](https://github.com/rust-lang/rust-clippy/pull/11069) ## Rust 1.72 -Current stable, released 2023-08-24 +Released 2023-08-24 [View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster) @@ -5011,6 +5101,7 @@ Released 2018-09-13 [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division [`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref +[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter [`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering [`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage [`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref @@ -5036,6 +5127,7 @@ Released 2018-09-13 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain +[`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays @@ -5072,6 +5164,7 @@ Released 2018-09-13 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten +[`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite diff --git a/Cargo.toml b/Cargo.toml index 66786004f6e7..cbcb42dad79b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.74" +version = "0.1.75" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -25,6 +25,8 @@ clippy_lints = { path = "clippy_lints" } rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" +color-print = "0.3.4" # Sync version with Cargo +anstream = "0.5.0" [dev-dependencies] ui_test = "0.20" diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index f6f0c95c7293..e001197842bd 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -261,7 +261,7 @@ impl EarlyLintPass for FooFunctions {} [declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 [example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints -[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 +[category_level_mapping]: ../index.html ## Lint registration diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index b980083f1f52..2c958ccbbc24 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -151,6 +151,7 @@ The minimum rust version that the project supports * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) +* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) ## `cognitive-complexity-threshold` diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index e64cf2c87496..be2386bb1d24 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -58,7 +58,7 @@ pub fn create( }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; - create_test(&lint).context("Unable to create a test for the new lint")?; + create_test(&lint, msrv).context("Unable to create a test for the new lint")?; if lint.ty.is_none() { add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; @@ -88,15 +88,21 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { } } -fn create_test(lint: &LintData<'_>) -> io::Result<()> { - fn create_project_layout>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> { +fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { + fn create_project_layout>( + lint_name: &str, + location: P, + case: &str, + hint: &str, + msrv: bool, + ) -> io::Result<()> { let mut path = location.into().join(case); fs::create_dir(&path)?; write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?; path.push("src"); fs::create_dir(&path)?; - write_file(path.join("main.rs"), get_test_file_contents(lint_name))?; + write_file(path.join("main.rs"), get_test_file_contents(lint_name, msrv))?; Ok(()) } @@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { let test_dir = lint.project_root.join(&relative_test_dir); fs::create_dir(&test_dir)?; - create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; - create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?; + create_project_layout( + lint.name, + &test_dir, + "fail", + "Content that triggers the lint goes here", + msrv, + )?; + create_project_layout( + lint.name, + &test_dir, + "pass", + "This file should not trigger the lint", + false, + )?; println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); } else { let test_path = format!("tests/ui/{}.rs", lint.name); - let test_contents = get_test_file_contents(lint.name); + let test_contents = get_test_file_contents(lint.name, msrv); write_file(lint.project_root.join(&test_path), test_contents)?; println!("Generated test file: `{test_path}`"); @@ -194,8 +212,8 @@ pub(crate) fn get_stabilization_version() -> String { parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") } -fn get_test_file_contents(lint_name: &str) -> String { - formatdoc!( +fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { + let mut test = formatdoc!( r#" #![warn(clippy::{lint_name})] @@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String { // test code goes here }} "# - ) + ); + + if msrv { + let _ = writedoc!( + test, + r#" + + // TODO: set xx to the version one below the MSRV used by the lint, and yy to + // the version used by the lint + #[clippy::msrv = "1.xx"] + fn msrv_1_xx() {{ + // a simple example that would trigger the lint if the MSRV were met + }} + + #[clippy::msrv = "1.yy"] + fn msrv_1_yy() {{ + // the same example as above + }} + "# + ); + } + + test } fn get_manifest_contents(lint_name: &str, hint: &str) -> String { @@ -258,7 +298,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ) }); - let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category)); + let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category)); result.push_str(&if enable_msrv { formatdoc!( @@ -281,7 +321,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. - // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` "# ) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index dcd9a4adcbd4..4d5b3bf8a948 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.74" +version = "0.1.75" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -28,6 +28,9 @@ semver = "1.0" rustc-semver = "1.1" url = "2.2" +[dev-dependencies] +walkdir = "2.3" + [features] deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index e1ef514edfd1..e3f4cf79d315 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { + /// ### What it does /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// @@ -19,7 +20,6 @@ declare_clippy_lint! { /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// /// ### Why is this bad? - /// /// `#[expect]` attributes suppress the lint emission, but emit a warning, if /// the expectation is unfulfilled. This can be useful to be notified when the /// lint is no longer triggered. diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4d1281ec1e7c..481c44031cf7 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -229,6 +229,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, + crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO, + crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO, crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, crate::large_futures::LARGE_FUTURES_INFO, @@ -280,6 +282,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_INFO, crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, + crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 3f60e5a7c4d6..646767868e2c 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,7 +1,7 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use clippy_utils::consts::{miri_to_const, Constant}; +use clippy_utils::consts::{mir_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .const_eval_poly(def_id.to_def_id()) .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) { + if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { ty = adt.repr().discr_type().to_ty(cx.tcx); diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index f24577c73822..6d429fbd0353 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// impl std::error::Error for Error { ... } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ERROR_IMPL_ERROR, restriction, "exported types named `Error` that implement `Error`" diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 419c77343441..0ec52f89e716 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FOUR_FORWARD_SLASHES, suspicious, "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)" diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index d8ead1c9d9f6..ef2a66d4a209 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -37,6 +37,10 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]); impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) { + if pat.span.from_expansion() { + return; + } + match cx.tcx.hir().get_parent(pat.hir_id) { Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => { // Ignore function parameters diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 64a4a3fa741b..2b2ea156cd4d 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -6,9 +6,8 @@ use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { vis.visit_ty(ty); for target in &vis.found { - if in_external_macro(cx.sess(), generics.span) { + if generics.span.from_expansion() { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 55a43e915628..41477242bcc0 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,10 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_from_proc_macro, is_in_cfg_test}; -use rustc_hir::{HirId, ItemId, ItemKind, Mod}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_hir::{HirId, Item, ItemKind, Mod}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{sym, Span}; +use rustc_span::hygiene::AstPass; +use rustc_span::{sym, ExpnKind}; declare_clippy_lint! { /// ### What it does @@ -41,46 +43,72 @@ declare_clippy_lint! { declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]); +fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { + if let ItemKind::Mod(test_mod) = item.kind + && item.span.hi() == test_mod.spans.inner_span.hi() + && is_cfg_test(cx.tcx, item.hir_id()) + && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) + { + true + } else { + false + } +} + impl LateLintPass<'_> for ItemsAfterTestModule { - fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { - let mut was_test_mod_visited = false; - let mut test_mod_span: Option = None; + fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) { + let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id)); - let hir = cx.tcx.hir(); - let items = hir.items().collect::>(); + let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else { + return; + }; - for (i, itid) in items.iter().enumerate() { - let item = hir.item(*itid); + let after: Vec<_> = items + .filter(|item| { + // Ignore the generated test main function + !(item.ident.name == sym::main + && item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness)) + }) + .collect(); - if_chain! { - if was_test_mod_visited; - if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */); - if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash - == cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail - if !matches!(item.kind, ItemKind::Mod(_)); - if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself - if !in_external_macro(cx.sess(), item.span); - if !is_from_proc_macro(cx, item); + if let Some(last) = after.last() + && after.iter().all(|&item| { + !matches!(item.kind, ItemKind::Mod(_)) + && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) + }) + && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id())) + { + let def_spans: Vec<_> = std::iter::once(test_mod.owner_id) + .chain(after.iter().map(|item| item.owner_id)) + .map(|id| cx.tcx.def_span(id)) + .collect(); - then { - span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); - }}; - - if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() { - // Check that it works the same way, the only I way I've found for #10713 - for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { - if_chain! { - if attr.has_name(sym::cfg); - if let Some(mitems) = attr.meta_item_list(); - if let [mitem] = &*mitems; - if mitem.has_name(sym::test); - then { - was_test_mod_visited = true; - test_mod_span = Some(item.span); - } + span_lint_hir_and_then( + cx, + ITEMS_AFTER_TEST_MODULE, + test_mod.hir_id(), + def_spans, + "items after a test module", + |diag| { + if let Some(prev) = mod_pos.checked_sub(1) + && let prev = cx.tcx.hir().item(module.item_ids[prev]) + && let items_span = last.span.with_lo(test_mod.span.hi()) + && let Some(items) = snippet_opt(cx, items_span) + { + diag.multipart_suggestion_with_style( + "move the items to before the test module was defined", + vec![ + (prev.span.shrink_to_hi(), items), + (items_span, String::new()) + ], + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); } - } - } + }, + ); } } } diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs new file mode 100644 index 000000000000..43e1b92c9b9a --- /dev/null +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -0,0 +1,249 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::get_parent_as_impl; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, make_normalized_projection}; +use rustc_ast::Mutability; +use rustc_errors::Applicability; +use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation. + /// + /// ### Why is this bad? + /// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly + /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`. + /// + /// ### Example + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.0.iter() + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.0.iter() + /// } + /// } + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.iter() + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub ITER_WITHOUT_INTO_ITER, + pedantic, + "implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl" +} + +declare_clippy_lint! { + /// ### What it does + /// This is the opposite of the `iter_without_into_iter` lint. + /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method. + /// + /// ### Why is this bad? + /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains + /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax + /// in case of ambiguity with another `Intoiterator` impl. + /// + /// ### Example + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.0.iter() + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.into_iter() + /// } + /// } + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.0.iter() + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub INTO_ITER_WITHOUT_ITER, + pedantic, + "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method" +} + +declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]); + +/// Checks if a given type is nameable in a trait (impl). +/// RPIT is stable, but impl Trait in traits is not (yet), so when we have +/// a function such as `fn iter(&self) -> impl IntoIterator`, we can't +/// suggest `type IntoIter = impl IntoIterator`. +fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool { + !matches!(ty.kind, TyKind::OpaqueDef(..)) +} + +fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { + if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { + cx.tcx.inherent_impls(ty_did).iter().any(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .is_some_and(|item| item.kind == ty::AssocKind::Fn) + }) + } else { + false + } +} + +impl LateLintPass<'_> for IterWithoutIntoIter { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + if let ItemKind::Impl(imp) = item.kind + && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind + && let Some(trait_ref) = imp.of_trait + && trait_ref.trait_def_id().is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() + && let expected_method_name = match mtbl { + Mutability::Mut => sym::iter_mut, + Mutability::Not => sym::iter, + } + && !type_has_inherent_method(cx, ty, expected_method_name) + && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { + if item.ident.name == sym!(IntoIter) { + Some(cx.tcx.hir().impl_item(item.id).expect_type().span) + } else { + None + } + }) + { + span_lint_and_then( + cx, + INTO_ITER_WITHOUT_ITER, + item.span, + &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), + |diag| { + // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS + // to avoid name ambiguities, as there might be an inherent into_iter method + // that we don't want to call. + let sugg = format!( +" +impl {self_ty_without_ref} {{ + fn {expected_method_name}({ref_self}self) -> {iter_ty} {{ + <{ref_self}Self as IntoIterator>::into_iter(self) + }} +}} +", + self_ty_without_ref = snippet(cx, self_ty_without_ref.ty.span, ".."), + ref_self = mtbl.ref_prefix_str(), + iter_ty = snippet(cx, iter_assoc_span, ".."), + ); + + diag.span_suggestion_verbose( + item.span.shrink_to_lo(), + format!("consider implementing `{expected_method_name}`"), + sugg, + // Just like iter_without_into_iter, this suggestion is on a best effort basis + // and requires potentially adding lifetimes or moving them around. + Applicability::Unspecified + ); + } + ); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { + let item_did = item.owner_id.to_def_id(); + let (borrow_prefix, expected_implicit_self) = match item.ident.name { + sym::iter => ("&", ImplicitSelfKind::ImmRef), + sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef), + _ => return, + }; + + if let ImplItemKind::Fn(sig, _) = item.kind + && let FnRetTy::Return(ret) = sig.decl.output + && is_nameable_in_impl_trait(ret) + && cx.tcx.generics_of(item_did).params.is_empty() + && sig.decl.implicit_self == expected_implicit_self + && sig.decl.inputs.len() == 1 + && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) + && imp.of_trait.is_none() + && let sig = cx.tcx.liberate_late_bound_regions( + item_did, + cx.tcx.fn_sig(item_did).instantiate_identity() + ) + && let ref_ty = sig.inputs()[0] + && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let Some(iterator_did) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let ret_ty = sig.output() + // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator` + // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs) + && implements_trait(cx, ret_ty, iterator_did, &[]) + && let Some(iter_ty) = make_normalized_projection( + cx.tcx, + cx.param_env, + iterator_did, + sym!(Item), + [ret_ty], + ) + // Only lint if the `IntoIterator` impl doesn't actually exist + && !implements_trait(cx, ref_ty, into_iter_did, &[]) + { + let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, "..")); + + span_lint_and_then( + cx, + ITER_WITHOUT_INTO_ITER, + item.span, + &format!("`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident), + |diag| { + // Get the lower span of the `impl` block, and insert the suggestion right before it: + // impl X { + // ^ fn iter(&self) -> impl IntoIterator { ... } + // } + let span_behind_impl = cx.tcx + .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id) + .shrink_to_lo(); + + let sugg = format!( +" +impl IntoIterator for {self_ty_snippet} {{ + type IntoIter = {ret_ty}; + type Iter = {iter_ty}; + fn into_iter() -> Self::IntoIter {{ + self.iter() + }} +}} +" + ); + diag.span_suggestion_verbose( + span_behind_impl, + format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"), + sugg, + // Suggestion is on a best effort basis, might need some adjustments by the user + // such as adding some lifetimes in the associated types, or importing types. + Applicability::Unspecified, + ); + }); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1271be2fd936..0f35ec276657 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -169,6 +169,7 @@ mod invalid_upcast_comparisons; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; +mod iter_without_into_iter; mod large_const_arrays; mod large_enum_variant; mod large_futures; @@ -190,6 +191,7 @@ mod manual_async_fn; mod manual_bits; mod manual_clamp; mod manual_float_methods; +mod manual_hash_one; mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; @@ -1119,6 +1121,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv(), )) }); + store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); + store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 88db7ae6aece..ed9189a18049 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// # let x = 1.0f32; /// if x.is_infinite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_INFINITE, style, "use dedicated method to check if a float is infinite" @@ -51,7 +51,7 @@ declare_clippy_lint! { /// if x.is_finite() {} /// if x.is_finite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_FINITE, style, "use dedicated method to check if a float is finite" diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs new file mode 100644 index 000000000000..ea9113354504 --- /dev/null +++ b/clippy_lints/src/manual_hash_one.rs @@ -0,0 +1,133 @@ +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_opt; +use clippy_utils::visitors::{is_local_used, local_used_once}; +use clippy_utils::{is_trait_method, path_to_local_id}; +use rustc_errors::Applicability; +use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for cases where [`BuildHasher::hash_one`] can be used. + /// + /// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one + /// + /// ### Why is this bad? + /// It is more concise to use the `hash_one` method. + /// + /// ### Example + /// ```rust + /// use std::hash::{BuildHasher, Hash, Hasher}; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let mut hasher = s.build_hasher(); + /// value.hash(&mut hasher); + /// let hash = hasher.finish(); + /// ``` + /// Use instead: + /// ```rust + /// use std::hash::BuildHasher; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let hash = s.hash_one(&value); + /// ``` + #[clippy::version = "1.74.0"] + pub MANUAL_HASH_ONE, + complexity, + "manual implementations of `BuildHasher::hash_one`" +} + +pub struct ManualHashOne { + msrv: Msrv, +} + +impl ManualHashOne { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]); + +impl LateLintPass<'_> for ManualHashOne { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + // `let mut hasher = seg.build_hasher();` + if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind + && let Some(init) = local.init + && !init.span.from_expansion() + && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind + && seg.ident.name == sym!(build_hasher) + + && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id) + && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id) + + && let mut stmts = block.stmts.iter() + .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id) + .skip(1) + .filter(|&stmt| is_local_used(cx, stmt, hasher)) + + // `hashed_value.hash(&mut hasher);` + && let Some(hash_stmt) = stmts.next() + && let StmtKind::Semi(hash_expr) = hash_stmt.kind + && !hash_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind + && seg.ident.name == sym::hash + && is_trait_method(cx, hash_expr, sym::Hash) + && path_to_local_id(ref_to_hasher.peel_borrows(), hasher) + + && let maybe_finish_stmt = stmts.next() + // There should be no more statements referencing `hasher` + && stmts.next().is_none() + + // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block + && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher) + && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id) + && !finish_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind + && seg.ident.name == sym!(finish) + + && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE) + { + span_lint_hir_and_then( + cx, + MANUAL_HASH_ONE, + finish_expr.hir_id, + finish_expr.span, + "manual implementation of `BuildHasher::hash_one`", + |diag| { + if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) + && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + { + diag.multipart_suggestion( + "try", + vec![ + (local_stmt.span, String::new()), + (hash_stmt.span, String::new()), + ( + finish_expr.span, + // `needless_borrows_for_generic_args` will take care of + // removing the `&` when it isn't needed + format!("{build_hasher}.hash_one(&{hashed_value})") + ) + ], + Applicability::MachineApplicable, + ); + + } + }, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index c531137b785e..2117308cd400 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -136,9 +136,9 @@ fn emit_manual_let_else( // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app); - let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); + let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); - let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) { + let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call { sn_else.into_owned() } else { format!("{{ {sn_else} }}") diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 0e22485db2c5..c12727c4a28c 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -3,6 +3,7 @@ use clippy_utils::is_doc_hidden; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{self, VisibilityKind}; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -158,7 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { let mut iter = def.variants.iter().filter_map(|v| { (matches!(v.data, hir::VariantData::Unit(_, _)) && v.ident.as_str().starts_with('_') - && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) + && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) .then_some((v.def_id, v.span)) }); if let Some((id, span)) = iter.next() @@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive() - && let header_span = cx.sess().source_map().span_until_char(enum_span, '{') - && let Some(snippet) = snippet_opt(cx, header_span) - { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); + let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); + if let Some(snippet) = snippet_opt(cx, header_span) { + diag.span_suggestion( + header_span, + "add the attribute", + format!("#[non_exhaustive] {snippet}"), + Applicability::Unspecified, + ); } diag.span_help(variant_span, "remove this variant"); }, diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 930386a60aa0..a23000e5fe15 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -961,7 +961,7 @@ declare_clippy_lint! { /// _ => todo!(), /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_GUARDS, complexity, "checks for unnecessary guards in match expressions" diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 7c0485914b83..8f0083f812cc 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; +use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt}; use clippy_utils::diagnostics::span_lint_and_note; use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e7fcef9e9de2..a935aea5075d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2970,7 +2970,7 @@ declare_clippy_lint! { /// assert_eq!((*any_box).type_id(), TypeId::of::()); /// // ^ dereference first, to call `type_id` on `dyn Any` /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub TYPE_ID_ON_BOX, suspicious, "calling `.type_id()` on `Box`" @@ -3368,6 +3368,7 @@ declare_clippy_lint! { } declare_clippy_lint! { + /// ### What it does /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input /// into a string, then later attempting to parse this string into a type without first trimming it, which will /// always fail because the string has a trailing newline in it. @@ -3390,7 +3391,7 @@ declare_clippy_lint! { /// // ^^^^^^^^^^^ remove the trailing newline /// assert_eq!(num, 42); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub READ_LINE_WITHOUT_TRIM, correctness, "calling `Stdin::read_line`, then trying to parse it without first trimming" @@ -3418,7 +3419,7 @@ declare_clippy_lint! { /// # let c = 'c'; /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub STRING_LIT_CHARS_ANY, restriction, "checks for `.chars().any(|i| i == c)`" @@ -3453,7 +3454,7 @@ declare_clippy_lint! { /// }) /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FORMAT_COLLECT, perf, "`format!`ing every element in a collection, then collecting the strings into a new `String`" @@ -3474,7 +3475,7 @@ declare_clippy_lint! { /// let y = v.iter().collect::>(); /// assert_eq!(x, y); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ITER_SKIP_ZERO, correctness, "disallows `.skip(0)`" @@ -3505,7 +3506,7 @@ declare_clippy_lint! { /// # let v = vec![]; /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FILTER_MAP_BOOL_THEN, style, "checks for usage of `bool::then` in `Iterator::filter_map`" diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 24c0ea3f60a9..3e19d72ec912 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -24,7 +24,6 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) - } } -#[expect(clippy::too_many_lines)] pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -101,11 +100,11 @@ pub(super) fn check( (expr.span.with_lo(args[0].span.hi()), String::new()), ]), ("None", "unwrap_or_else", _) => match args[0].kind { - hir::ExprKind::Closure(hir::Closure { - body, - .. - }) => Some(vec![ - (expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), String::new()), + hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ + ( + expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), + String::new(), + ), (expr.span.with_lo(args[0].span.hi()), String::new()), ]), _ => None, diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index c17f00c42751..136947a2c8cd 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -15,6 +15,10 @@ declare_clippy_lint! { /// A good custom message should be more about why the failure of the assertion is problematic /// and not what is failed because the assertion already conveys that. /// + /// Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy. + /// Also, in most cases understanding the test failure would be easier + /// compared to understanding a complex invariant distributed around the codebase. + /// /// ### Known problems /// This lint cannot check the quality of the custom panic messages. /// Hence, you can suppress this lint simply by adding placeholder messages diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index ea6a9bc5657d..e87aea263d48 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -135,10 +135,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool { - match stmt.kind { - StmtKind::Item(..) => false, - _ => true, - } + !matches!(stmt.kind, StmtKind::Item(..)) } impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { @@ -148,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { ExprKind::Block(block, ..) => match (block.stmts, block.expr) { (stmts, Some(e)) => { if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) { - self.visit_expr(e) + self.visit_expr(e); } }, ([first @ .., stmt], None) => { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 57652e5ff546..212d6234bdb3 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -47,9 +47,9 @@ declare_clippy_lint! { /// 12 + *y /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NEEDLESS_PASS_BY_REF_MUT, - suspicious, + nursery, "using a `&mut` argument when it's not mutated" } diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 4be140647fcc..0e4b6aa1b7d2 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -102,7 +102,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NON_CANONICAL_PARTIAL_ORD_IMPL, suspicious, "non-canonical implementation of `PartialOrd` on an `Ord` type" diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 4635e1164cd3..6b247cf5f6ae 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -312,7 +312,7 @@ declare_clippy_lint! { /// # let status_code = 200; /// if status_code <= 400 && status_code > 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub IMPOSSIBLE_COMPARISONS, correctness, "double comparisons that will never evaluate to `true`" @@ -332,7 +332,7 @@ declare_clippy_lint! { /// # let status_code = 200; /// if status_code <= 400 && status_code < 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_COMPARISONS, correctness, "double comparisons where one of them can be removed" diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 8a7e48746661..c951d9a4a09d 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -75,6 +75,7 @@ impl EarlyLintPass for RawStrings { if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) { return; } + let descr = lit.kind.descr(); if !str.contains(['\\', '"']) { span_lint_and_then( @@ -89,20 +90,17 @@ impl EarlyLintPass for RawStrings { let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1); let start = start.with_lo(r_pos); - if end.is_empty() { - diag.span_suggestion( - start, - "use a string literal instead", - format!("\"{str}\""), - Applicability::MachineApplicable, - ); - } else { - diag.multipart_suggestion( - "try", - vec![(start, String::new()), (end, String::new())], - Applicability::MachineApplicable, - ); + let mut remove = vec![(start, String::new())]; + // avoid debug ICE from empty suggestions + if !end.is_empty() { + remove.push((end, String::new())); } + + diag.multipart_suggestion_verbose( + format!("use a plain {descr} literal instead"), + remove, + Applicability::MachineApplicable, + ); }, ); if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) { @@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings { let (start, end) = hash_spans(expr.span, prefix, req, max); let message = match max - req { - _ if req == 0 => "remove all the hashes around the literal".to_string(), - 1 => "remove one hash from both sides of the literal".to_string(), - n => format!("remove {n} hashes from both sides of the literal"), + _ if req == 0 => format!("remove all the hashes around the {descr} literal"), + 1 => format!("remove one hash from both sides of the {descr} literal"), + n => format!("remove {n} hashes from both sides of the {descr} literal"), }; diag.multipart_suggestion( diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 0c89c7ee47d3..197742b5dd41 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro; use clippy_utils::ty::needs_ordered_drop; use rustc_ast::Mutability; use rustc_hir::def::Res; -use rustc_hir::{ - BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath, -}; +use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::{in_external_macro, is_from_async_await}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; @@ -39,7 +37,7 @@ declare_clippy_lint! { /// // no redefinition with the same name /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_LOCALS, correctness, "redundant redefinition of a local binding" @@ -68,21 +66,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { // the local does not change the effect of assignments to the binding. see #11290 if !affects_assignments(cx, mutability, binding_id, local.hir_id); // the local does not affect the code's drop behavior - if !affects_drop_behavior(cx, binding_id, local.hir_id, expr); + if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr)); // the local is user-controlled if !in_external_macro(cx.sess(), local.span); if !is_from_proc_macro(cx, expr); - // Async function parameters are lowered into the closure body, so we can't lint them. - // see `lower_maybe_async_body` in `rust_ast_lowering` - if !is_from_async_await(local.span); then { span_lint_and_help( cx, REDUNDANT_LOCALS, - vec![binding_pat.span, local.span], - "redundant redefinition of a binding", - None, - &format!("remove the redefinition of `{ident}`"), + local.span, + &format!("redundant redefinition of a binding `{ident}`"), + Some(binding_pat.span), + &format!("`{ident}` is initially defined here"), ); } } @@ -109,18 +104,3 @@ fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId // the binding is mutable and the rebinding is in a different scope than the original binding mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind) } - -/// Check if a rebinding of a local affects the code's drop behavior. -fn affects_drop_behavior<'tcx>( - cx: &LateContext<'tcx>, - bind: HirId, - rebind: HirId, - rebind_expr: &Expr<'tcx>, -) -> bool { - let hir = cx.tcx.hir(); - - // the rebinding is in a different scope than the original binding - // and the type of the binding cares about drop order - hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind) - && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr)) -} diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 5f54a10d1c41..b7396535eedf 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; @@ -99,6 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { if let Res::Def(_, def_id) = path.res && let Some(first_segment) = get_first_segment(path) && is_stable(cx, def_id) + && !in_external_macro(cx.sess(), path.span) + && !is_from_proc_macro(cx, &first_segment.ident) { let (lint, used_mod, replace_with) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 75c3c7a958a2..23da1de77303 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -294,7 +294,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. /// /// The minimum rust version that the project supports (msrv: Option = None), @@ -744,3 +744,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { (rows, column_widths) } + +#[cfg(test)] +mod tests { + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + use serde::de::IgnoredAny; + use std::fs; + use walkdir::WalkDir; + + #[test] + fn configs_are_tested() { + let mut names: FxHashSet = super::metadata::get_configuration_metadata() + .into_iter() + .map(|meta| meta.name.replace('_', "-")) + .collect(); + + let toml_files = WalkDir::new("../tests") + .into_iter() + .map(Result::unwrap) + .filter(|entry| entry.file_name() == "clippy.toml"); + + for entry in toml_files { + let file = fs::read_to_string(entry.path()).unwrap(); + #[allow(clippy::zero_sized_map_values)] + if let Ok(map) = toml::from_str::>(&file) { + for name in map.keys() { + names.remove(name.as_str()); + } + } + } + + assert!( + names.remove("allow-one-hash-in-raw-strings"), + "remove this when #11481 is fixed" + ); + + assert!( + names.is_empty(), + "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`" + ); + } +} diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index d09d02a7dfda..70b83149ce1a 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports { if self.warn_on_all || !self.check_exceptions(item, use_path.segments); let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id); if !used_imports.is_empty(); // Already handled by `unused_imports` + if !used_imports.contains(&kw::Underscore); then { let mut applicability = Applicability::MachineApplicable; let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index da083fb14aae..855aefa70cb1 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -3,12 +3,15 @@ use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; -use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait}; +use rustc_ast::{ + FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, + FormatTrait, +}; use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{sym, BytePos}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -450,6 +453,12 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos); + let lint_name = if name.starts_with("write") { + WRITE_LITERAL + } else { + PRINT_LITERAL + }; + let mut counts = vec![0u32; format_args.arguments.all_args().len()]; for piece in &format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece { @@ -457,6 +466,12 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { } } + let mut suggestion: Vec<(Span, String)> = vec![]; + // holds index of replaced positional arguments; used to decrement the index of the remaining + // positional arguments. + let mut replaced_position: Vec = vec![]; + let mut sug_span: Option = None; + for piece in &format_args.template { if let FormatArgsPiece::Placeholder(FormatPlaceholder { argument, @@ -471,9 +486,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() && let Some(value_string) = snippet_opt(cx, arg.expr.span) - { + { let (replacement, replace_raw) = match lit.kind { - LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { + LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { Some(extracted) => extracted, None => return, }, @@ -493,12 +508,6 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let lint = if name.starts_with("write") { - WRITE_LITERAL - } else { - PRINT_LITERAL - }; - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue }; let format_string_is_raw = format_string_snippet.starts_with('r'); @@ -519,29 +528,58 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { }, }; - span_lint_and_then( - cx, - lint, - arg.expr.span, - "literal with an empty format string", - |diag| { - if let Some(replacement) = replacement - // `format!("{}", "a")`, `format!("{named}", named = "b") - // ~~~~~ ~~~~~~~~~~~~~ - && let Some(removal_span) = format_arg_removal_span(format_args, index) - { - let replacement = replacement.replace('{', "{{").replace('}', "}}"); - diag.multipart_suggestion( - "try", - vec![(*placeholder_span, replacement), (removal_span, String::new())], - Applicability::MachineApplicable, - ); - } - }, - ); + sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span)); + if let Some((_, index)) = positional_arg_piece_span(piece) { + replaced_position.push(index); + } + + if let Some(replacement) = replacement + // `format!("{}", "a")`, `format!("{named}", named = "b") + // ~~~~~ ~~~~~~~~~~~~~ + && let Some(removal_span) = format_arg_removal_span(format_args, index) { + let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw); + suggestion.push((*placeholder_span, replacement)); + suggestion.push((removal_span, String::new())); + } } } + + // Decrement the index of the remaining by the number of replaced positional arguments + if !suggestion.is_empty() { + for piece in &format_args.template { + if let Some((span, index)) = positional_arg_piece_span(piece) + && suggestion.iter().all(|(s, _)| *s != span) { + let decrement = replaced_position.iter().filter(|i| **i < index).count(); + suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); + } + } + } + + if let Some(span) = sug_span { + span_lint_and_then(cx, lint_name, span, "literal with an empty format string", |diag| { + if !suggestion.is_empty() { + diag.multipart_suggestion("try", suggestion, Applicability::MachineApplicable); + } + }); + } +} + +/// Extract Span and its index from the given `piece`, iff it's positional argument. +fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { + match piece { + FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: + FormatArgPosition { + index: Ok(index), + kind: FormatArgPositionKind::Number, + .. + }, + span: Some(span), + .. + }) => Some((*span, *index)), + _ => None, + } } /// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw @@ -593,3 +631,47 @@ fn conservative_unescape(literal: &str) -> Result { if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) } } + +/// Replaces `{` with `{{` and `}` with `}}`. If `preserve_unicode_escapes` is `true` the braces in +/// `\u{xxxx}` are left unmodified +#[expect(clippy::match_same_arms)] +fn escape_braces(literal: &str, preserve_unicode_escapes: bool) -> String { + #[derive(Clone, Copy)] + enum State { + Normal, + Backslash, + UnicodeEscape, + } + + let mut escaped = String::with_capacity(literal.len()); + let mut state = State::Normal; + + for ch in literal.chars() { + state = match (ch, state) { + // Escape braces outside of unicode escapes by doubling them up + ('{' | '}', State::Normal) => { + escaped.push(ch); + State::Normal + }, + // If `preserve_unicode_escapes` isn't enabled stay in `State::Normal`, otherwise: + // + // \u{aaaa} \\ \x01 + // ^ ^ ^ + ('\\', State::Normal) if preserve_unicode_escapes => State::Backslash, + // \u{aaaa} + // ^ + ('u', State::Backslash) => State::UnicodeEscape, + // \xAA \\ + // ^ ^ + (_, State::Backslash) => State::Normal, + // \u{aaaa} + // ^ + ('}', State::UnicodeEscape) => State::Normal, + _ => state, + }; + + escaped.push(ch); + } + + escaped +} diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 1596bb773976..8522493f67b3 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.74" +version = "0.1.75" edition = "2021" publish = false diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index d596eed4b7c4..0bae7056c4fb 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -9,11 +9,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::interpret::{alloc_range, Scalar}; use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; +use rustc_target::abi::Size; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; use std::iter; @@ -403,7 +404,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && adt_def.is_struct() && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field) { - miri_to_const(self.lcx, desired_field) + mir_to_const(self.lcx, desired_field) } else { result @@ -483,7 +484,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None) .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty))?; - let result = miri_to_const(self.lcx, result)?; + let result = mir_to_const(self.lcx, result)?; self.source = ConstantSource::Constant; Some(result) }, @@ -655,10 +656,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { +pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { use rustc_middle::mir::ConstValue; - match result { - mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { + let mir::Const::Val(val, _) = result else { + // We only work on evaluated consts. + return None; + }; + match (val, result.ty().kind()) { + (ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), @@ -671,42 +676,28 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), _ => None, }, - mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => - { - let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; + (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { + let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; String::from_utf8(data.to_owned()).ok().map(Constant::Str) }, - mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => { - let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory(); - match result.ty().kind() { - ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), - ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) { - Some(len) => alloc - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) - .to_owned() - .array_chunks::<4>() - .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk)))) - .collect::>>>() - .map(Constant::Vec), - _ => None, - }, - ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) { - Some(len) => alloc - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) - .to_owned() - .array_chunks::<8>() - .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk)))) - .collect::>>>() - .map(Constant::Vec), - _ => None, - }, - _ => None, - }, - _ => None, + (_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)), + (ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => { + let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); + let len = len.try_to_target_usize(lcx.tcx)?; + let ty::Float(flt) = sub_type.kind() else { + return None; + }; + let size = Size::from_bits(flt.bit_width()); + let mut res = Vec::new(); + for idx in 0..len { + let range = alloc_range(offset + size * idx, size); + let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?; + res.push(match flt { + FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)), + FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)), + }); } + Some(Constant::Vec(res)) }, _ => None, } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 64ca2ff78736..c2c97259d38b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -80,7 +80,6 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def::{DefKind, Res}; @@ -113,7 +112,7 @@ use rustc_span::{sym, Span}; use rustc_target::abi::Integer; use visitors::Visitable; -use crate::consts::{constant, miri_to_const, Constant}; +use crate::consts::{constant, mir_to_const, Constant}; use crate::higher::Range; use crate::ty::{ adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, @@ -1509,9 +1508,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) - && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) - && let min_const_kind = Const::from_value(const_val, bnd_ty) - && let Some(min_const) = miri_to_const(cx, min_const_kind) + && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx)) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const @@ -1525,9 +1522,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) - && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) - && let max_const_kind = Const::from_value(const_val, bnd_ty) - && let Some(max_const) = miri_to_const(cx, max_const_kind) + && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const @@ -2456,11 +2451,12 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { }) } -/// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied +/// Checks if `id` has a `#[cfg(test)]` attribute applied /// -/// Note: Add `//@compile-flags: --test` to UI tests with a `#[cfg(test)]` function -pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { - fn is_cfg_test(attr: &Attribute) -> bool { +/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent +/// use [`is_in_cfg_test`] +pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { + tcx.hir().attrs(id).iter().any(|attr| { if attr.has_name(sym::cfg) && let Some(items) = attr.meta_item_list() && let [item] = &*items @@ -2470,11 +2466,14 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { } else { false } - } + }) +} + +/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied +pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { tcx.hir() - .parent_iter(id) - .flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id)) - .any(is_cfg_test) + .parent_id_iter(id) + .any(|parent_id| is_cfg_test(tcx, parent_id)) } /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 0faff05eb231..df839c2106f1 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,7 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,71,0 { TUPLE_ARRAY_CONVERSIONS } + 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 3b47a451345e..d752fe7d97eb 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -62,6 +62,27 @@ where } } } +impl<'tcx, A, B> Visitable<'tcx> for (A, B) +where + A: Visitable<'tcx>, + B: Visitable<'tcx>, +{ + fn visit>(self, visitor: &mut V) { + let (a, b) = self; + a.visit(visitor); + b.visit(visitor); + } +} +impl<'tcx, T> Visitable<'tcx> for Option +where + T: Visitable<'tcx>, +{ + fn visit>(self, visitor: &mut V) { + if let Some(x) = self { + x.visit(visitor); + } + } +} macro_rules! visitable_ref { ($t:ident, $f:ident) => { impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { @@ -748,3 +769,26 @@ pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { }) .is_some() } + +/// If the local is only used once in `visitable` returns the path expression referencing the given +/// local +pub fn local_used_once<'tcx>( + cx: &LateContext<'tcx>, + visitable: impl Visitable<'tcx>, + id: HirId, +) -> Option<&'tcx Expr<'tcx>> { + let mut expr = None; + + let cf = for_each_expr_with_closures(cx, visitable, |e| { + if path_to_local_id(e, id) && expr.replace(e).is_some() { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }); + if cf.is_some() { + return None; + } + + expr +} diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 1470da61fac0..beea9fd00e7a 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.74" +version = "0.1.75" edition = "2021" publish = false diff --git a/rust-toolchain b/rust-toolchain index 5ce22b65f007..fe2c77ab47f0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-09-25" +channel = "nightly-2023-10-06" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/driver.rs b/src/driver.rs index 1d89477dcc16..d47767faed9e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -26,6 +26,8 @@ use std::ops::Deref; use std::path::Path; use std::process::exit; +use anstream::println; + /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. fn arg_value<'a, T: Deref>( @@ -162,39 +164,15 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } } +#[allow(clippy::ignored_unit_patterns)] fn display_help() { - println!( - "\ -Checks a package to catch common mistakes and improve your Rust code. - -Usage: - cargo clippy [options] [--] [...] - -Common options: - -h, --help Print this message - --rustc Pass all args to rustc - -V, --version Print version info and exit - -For the other options see `cargo check --help`. - -To allow or deny a lint from the command line you can use `cargo clippy --` -with: - - -W --warn OPT Set lint warnings - -A --allow OPT Set lint allowed - -D --deny OPT Set lint denied - -F --forbid OPT Set lint forbidden - -You can use tool lints to allow or deny lints from your code, eg.: - - #[allow(clippy::needless_lifetimes)] -" - ); + println!("{}", help_message()); } const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml"; #[allow(clippy::too_many_lines)] +#[allow(clippy::ignored_unit_patterns)] pub fn main() { let handler = EarlyErrorHandler::new(ErrorOutputType::default()); @@ -236,6 +214,7 @@ pub fn main() { if orig_args.iter().any(|a| a == "--version" || a == "-V") { let version_info = rustc_tools_util::get_version_info!(); + println!("{version_info}"); exit(0); } @@ -292,3 +271,25 @@ pub fn main() { } })) } + +#[must_use] +fn help_message() -> &'static str { + color_print::cstr!( + "Checks a file to catch common mistakes and improve your Rust code. +Run clippy-driver with the same arguments you use for rustc + +Usage: + clippy-driver [OPTIONS] INPUT + +Common options: + -h, --help Print this message + -V, --version Print version info and exit + --rustc Pass all arguments to rustc + +Allowing / Denying lints +You can use tool lints to allow or deny lints from your code, e.g.: + + #[allow(clippy::needless_lifetimes)] +" + ) +} diff --git a/src/main.rs b/src/main.rs index 26b655076cf6..bbf7d22c8504 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,37 +6,14 @@ use std::env; use std::path::PathBuf; use std::process::{self, Command}; -const CARGO_CLIPPY_HELP: &str = "Checks a package to catch common mistakes and improve your Rust code. - -Usage: - cargo clippy [options] [--] [...] - -Common options: - --no-deps Run Clippy only on the given crate, without linting the dependencies - --fix Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets` - -h, --help Print this message - -V, --version Print version info and exit - --explain LINT Print the documentation for a given lint - -For the other options see `cargo check --help`. - -To allow or deny a lint from the command line you can use `cargo clippy --` -with: - - -W --warn OPT Set lint warnings - -A --allow OPT Set lint allowed - -D --deny OPT Set lint denied - -F --forbid OPT Set lint forbidden - -You can use tool lints to allow or deny lints from your code, e.g.: - - #[allow(clippy::needless_lifetimes)] -"; +use anstream::println; +#[allow(clippy::ignored_unit_patterns)] fn show_help() { - println!("{CARGO_CLIPPY_HELP}"); + println!("{}", help_message()); } +#[allow(clippy::ignored_unit_patterns)] fn show_version() { let version_info = rustc_tools_util::get_version_info!(); println!("{version_info}"); @@ -168,6 +145,38 @@ where } } +#[must_use] +pub fn help_message() -> &'static str { + color_print::cstr!( +"Checks a package to catch common mistakes and improve your Rust code. + +Usage: + cargo clippy [OPTIONS] [--] [<>...] + +Common options: + --no-deps Run Clippy only on the given crate, without linting the dependencies + --fix Automatically apply lint suggestions. This flag implies --no-deps and --all-targets + -h, --help Print this message + -V, --version Print version info and exit + --explain [LINT] Print the documentation for a given lint + +See all options with cargo check --help. + +Allowing / Denying lints + +To allow or deny a lint from the command line you can use cargo clippy -- with: + + -W / --warn [LINT] Set lint warnings + -A / --allow [LINT] Set lint allowed + -D / --deny [LINT] Set lint denied + -F / --forbid [LINT] Set lint forbidden + +You can use tool lints to allow or deny lints from your code, e.g.: + + #[allow(clippy::needless_lifetimes)] +" + ) +} #[cfg(test)] mod tests { use super::ClippyCmd; diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 37f0ec2b37d8..79a95d775b11 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -21,6 +21,18 @@ pub fn derive(_: TokenStream) -> TokenStream { output } +#[proc_macro_derive(ImplStructWithStdDisplay)] +pub fn derive_std(_: TokenStream) -> TokenStream { + quote! { + struct A {} + impl ::std::fmt::Display for A { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "A") + } + } + } +} + #[proc_macro_derive(FieldReassignWithDefault)] pub fn derive_foo(_input: TokenStream) -> TokenStream { quote! { @@ -141,3 +153,19 @@ pub fn shadow_derive(_: TokenStream) -> TokenStream { .into(), ]) } + +#[proc_macro_derive(StructIgnoredUnitPattern)] +pub fn derive_ignored_unit_pattern(_: TokenStream) -> TokenStream { + quote! { + struct A; + impl A { + fn a(&self) -> Result<(), ()> { + unimplemented!() + } + + pub fn b(&self) { + let _ = self.a().unwrap(); + } + } + } +} diff --git a/tests/ui/ignored_unit_patterns.fixed b/tests/ui/ignored_unit_patterns.fixed index 6c6f21fee16b..15eaf1f659ab 100644 --- a/tests/ui/ignored_unit_patterns.fixed +++ b/tests/ui/ignored_unit_patterns.fixed @@ -1,3 +1,4 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::ignored_unit_patterns)] #![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)] @@ -14,8 +15,22 @@ fn main() { //~^ ERROR: matching over `()` is more explicit let _ = foo().map_err(|()| todo!()); //~^ ERROR: matching over `()` is more explicit + + println!( + "{:?}", + match foo() { + Ok(()) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(()) => {}, + //~^ ERROR: matching over `()` is more explicit + } + ); } +// ignored_unit_patterns in derive macro should be ok +#[derive(proc_macro_derive::StructIgnoredUnitPattern)] +pub struct B; + #[allow(unused)] pub fn moo(_: ()) { let () = foo().unwrap(); diff --git a/tests/ui/ignored_unit_patterns.rs b/tests/ui/ignored_unit_patterns.rs index 5e8c2e03ba2c..9cac3a440aba 100644 --- a/tests/ui/ignored_unit_patterns.rs +++ b/tests/ui/ignored_unit_patterns.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::ignored_unit_patterns)] #![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)] @@ -14,8 +15,22 @@ fn main() { //~^ ERROR: matching over `()` is more explicit let _ = foo().map_err(|_| todo!()); //~^ ERROR: matching over `()` is more explicit + + println!( + "{:?}", + match foo() { + Ok(_) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(_) => {}, + //~^ ERROR: matching over `()` is more explicit + } + ); } +// ignored_unit_patterns in derive macro should be ok +#[derive(proc_macro_derive::StructIgnoredUnitPattern)] +pub struct B; + #[allow(unused)] pub fn moo(_: ()) { let _ = foo().unwrap(); diff --git a/tests/ui/ignored_unit_patterns.stderr b/tests/ui/ignored_unit_patterns.stderr index df5e1d89e906..cac01a87dba0 100644 --- a/tests/ui/ignored_unit_patterns.stderr +++ b/tests/ui/ignored_unit_patterns.stderr @@ -1,5 +1,5 @@ error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:10:12 + --> $DIR/ignored_unit_patterns.rs:11:12 | LL | Ok(_) => {}, | ^ help: use `()` instead of `_`: `()` @@ -8,28 +8,40 @@ LL | Ok(_) => {}, = help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:11:13 + --> $DIR/ignored_unit_patterns.rs:12:13 | LL | Err(_) => {}, | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:13:15 + --> $DIR/ignored_unit_patterns.rs:14:15 | LL | if let Ok(_) = foo() {} | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:15:28 + --> $DIR/ignored_unit_patterns.rs:16:28 | LL | let _ = foo().map_err(|_| todo!()); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:21:9 + --> $DIR/ignored_unit_patterns.rs:22:16 + | +LL | Ok(_) => {}, + | ^ help: use `()` instead of `_`: `()` + +error: matching over `()` is more explicit + --> $DIR/ignored_unit_patterns.rs:24:17 + | +LL | Err(_) => {}, + | ^ help: use `()` instead of `_`: `()` + +error: matching over `()` is more explicit + --> $DIR/ignored_unit_patterns.rs:36:9 | LL | let _ = foo().unwrap(); | ^ help: use `()` instead of `_`: `()` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index 281e12c7b938..765c67011474 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -7,8 +7,6 @@ fn fn_constref(i: &i32) -> i32 { unimplemented!() } fn fn_mutref(i: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` unimplemented!() } fn fooi() -> i32 { diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index c32b5e323c09..a78e47d02290 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,5 +1,5 @@ error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:24:11 + --> $DIR/infinite_loop.rs:22:11 | LL | while y < 10 { | ^^^^^^ @@ -8,7 +8,7 @@ LL | while y < 10 { = note: `#[deny(clippy::while_immutable_condition)]` on by default error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:31:11 + --> $DIR/infinite_loop.rs:29:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:40:11 + --> $DIR/infinite_loop.rs:38:11 | LL | while !cond { | ^^^^^ @@ -24,7 +24,7 @@ LL | while !cond { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:86:11 + --> $DIR/infinite_loop.rs:84:11 | LL | while i < 3 { | ^^^^^ @@ -32,7 +32,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:93:11 + --> $DIR/infinite_loop.rs:91:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:99:11 + --> $DIR/infinite_loop.rs:97:11 | LL | while i < 3 { | ^^^^^ @@ -48,7 +48,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:116:11 + --> $DIR/infinite_loop.rs:114:11 | LL | while i < 3 { | ^^^^^ @@ -56,7 +56,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:123:11 + --> $DIR/infinite_loop.rs:121:11 | LL | while i < 3 { | ^^^^^ @@ -64,7 +64,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:191:15 + --> $DIR/infinite_loop.rs:189:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | while self.count < n { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:201:11 + --> $DIR/infinite_loop.rs:199:11 | LL | while y < 10 { | ^^^^^^ @@ -82,7 +82,7 @@ LL | while y < 10 { = help: rewrite it as `if cond { loop { } }` error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:210:11 + --> $DIR/infinite_loop.rs:208:11 | LL | while y < 10 { | ^^^^^^ @@ -91,14 +91,5 @@ LL | while y < 10 { = note: this loop contains `return`s or `break`s = help: rewrite it as `if cond { loop { } }` -error: this argument is a mutable reference, but not used mutably - --> $DIR/infinite_loop.rs:9:17 - | -LL | fn fn_mutref(i: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs new file mode 100644 index 000000000000..6be3bb8abddd --- /dev/null +++ b/tests/ui/into_iter_without_iter.rs @@ -0,0 +1,124 @@ +//@no-rustfix +#![warn(clippy::into_iter_without_iter)] + +use std::iter::IntoIterator; + +fn main() { + { + struct S; + + impl<'a> IntoIterator for &'a S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + type IntoIter = std::slice::Iter<'a, u8>; + type Item = &'a u8; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + impl<'a> IntoIterator for &'a mut S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, u8>; + type Item = &'a mut u8; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + struct S(T); + impl<'a, T> IntoIterator for &'a S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + impl<'a, T> IntoIterator for &'a mut S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + // Both iter and iter_mut methods exist, don't lint + struct S<'a, T>(&'a T); + + impl<'a, T> S<'a, T> { + fn iter(&self) -> std::slice::Iter<'a, T> { + todo!() + } + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { + todo!() + } + } + + impl<'a, T> IntoIterator for &S<'a, T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + + impl<'a, T> IntoIterator for &mut S<'a, T> { + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + // Only `iter` exists, no `iter_mut` + struct S<'a, T>(&'a T); + + impl<'a, T> S<'a, T> { + fn iter(&self) -> std::slice::Iter<'a, T> { + todo!() + } + } + + impl<'a, T> IntoIterator for &S<'a, T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + + impl<'a, T> IntoIterator for &mut S<'a, T> { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + // `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize" + // aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead + // to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias). + struct S; + + impl S { + fn iter(&self) -> std::slice::Iter<'static, u8> { + todo!() + } + } + + type Alias = S; + + impl IntoIterator for &Alias { + type IntoIter = std::slice::Iter<'static, u8>; + type Item = &'static u8; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } +} diff --git a/tests/ui/into_iter_without_iter.stderr b/tests/ui/into_iter_without_iter.stderr new file mode 100644 index 000000000000..f543d1d8e86c --- /dev/null +++ b/tests/ui/into_iter_without_iter.stderr @@ -0,0 +1,114 @@ +error: `IntoIterator` implemented for a reference type without an `iter` method + --> $DIR/into_iter_without_iter.rs:10:9 + | +LL | / impl<'a> IntoIterator for &'a S { +LL | | +LL | | type IntoIter = std::slice::Iter<'a, u8>; +LL | | type Item = &'a u8; +... | +LL | | } +LL | | } + | |_________^ + | + = note: `-D clippy::into-iter-without-iter` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::into_iter_without_iter)]` +help: consider implementing `iter` + | +LL ~ +LL + impl S { +LL + fn iter(&self) -> std::slice::Iter<'a, u8> { +LL + <&Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter_mut` method + --> $DIR/into_iter_without_iter.rs:18:9 + | +LL | / impl<'a> IntoIterator for &'a mut S { +LL | | +LL | | type IntoIter = std::slice::IterMut<'a, u8>; +LL | | type Item = &'a mut u8; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter_mut` + | +LL ~ +LL + impl S { +LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, u8> { +LL + <&mut Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter` method + --> $DIR/into_iter_without_iter.rs:29:9 + | +LL | / impl<'a, T> IntoIterator for &'a S { +LL | | +LL | | type IntoIter = std::slice::Iter<'a, T>; +LL | | type Item = &'a T; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter` + | +LL ~ +LL + impl S { +LL + fn iter(&self) -> std::slice::Iter<'a, T> { +LL + <&Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter_mut` method + --> $DIR/into_iter_without_iter.rs:37:9 + | +LL | / impl<'a, T> IntoIterator for &'a mut S { +LL | | +LL | | type IntoIter = std::slice::IterMut<'a, T>; +LL | | type Item = &'a mut T; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter_mut` + | +LL ~ +LL + impl S { +LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { +LL + <&mut Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter_mut` method + --> $DIR/into_iter_without_iter.rs:93:9 + | +LL | / impl<'a, T> IntoIterator for &mut S<'a, T> { +LL | | +LL | | type IntoIter = std::slice::IterMut<'a, T>; +LL | | type Item = &'a mut T; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter_mut` + | +LL ~ +LL + impl S<'a, T> { +LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { +LL + <&mut Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui/items_after_test_module/after_proc_macros.rs b/tests/ui/items_after_test_module/after_proc_macros.rs new file mode 100644 index 000000000000..d9c0aef88c8c --- /dev/null +++ b/tests/ui/items_after_test_module/after_proc_macros.rs @@ -0,0 +1,11 @@ +//@aux-build:../auxiliary/proc_macros.rs +extern crate proc_macros; + +proc_macros::with_span! { + span + #[cfg(test)] + mod tests {} +} + +#[test] +fn f() {} diff --git a/tests/ui/items_after_test_module/auxiliary/submodule.rs b/tests/ui/items_after_test_module/auxiliary/submodule.rs new file mode 100644 index 000000000000..69d61790121c --- /dev/null +++ b/tests/ui/items_after_test_module/auxiliary/submodule.rs @@ -0,0 +1,4 @@ +#[cfg(test)] +mod tests {} + +fn in_submodule() {} diff --git a/tests/ui/items_after_test_module/block_module.stderr b/tests/ui/items_after_test_module/block_module.stderr deleted file mode 100644 index 1b6257471618..000000000000 --- a/tests/ui/items_after_test_module/block_module.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: Option 'test' given more than once - diff --git a/tests/ui/items_after_test_module/in_submodule.rs b/tests/ui/items_after_test_module/in_submodule.rs new file mode 100644 index 000000000000..7132e71764eb --- /dev/null +++ b/tests/ui/items_after_test_module/in_submodule.rs @@ -0,0 +1,8 @@ +#[path = "auxiliary/submodule.rs"] +mod submodule; + +#[cfg(test)] +mod tests { + #[test] + fn t() {} +} diff --git a/tests/ui/items_after_test_module/in_submodule.stderr b/tests/ui/items_after_test_module/in_submodule.stderr new file mode 100644 index 000000000000..4e99876365cf --- /dev/null +++ b/tests/ui/items_after_test_module/in_submodule.stderr @@ -0,0 +1,14 @@ +error: items after a test module + --> $DIR/auxiliary/submodule.rs:2:1 + | +LL | mod tests {} + | ^^^^^^^^^ +LL | +LL | fn in_submodule() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::items-after-test-module` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]` + +error: aborting due to previous error + diff --git a/tests/ui/items_after_test_module/multiple_modules.rs b/tests/ui/items_after_test_module/multiple_modules.rs new file mode 100644 index 000000000000..8ab9e8200f18 --- /dev/null +++ b/tests/ui/items_after_test_module/multiple_modules.rs @@ -0,0 +1,11 @@ +#[cfg(test)] +mod tests { + #[test] + fn f() {} +} + +#[cfg(test)] +mod more_tests { + #[test] + fn g() {} +} diff --git a/tests/ui/items_after_test_module/block_module.rs b/tests/ui/items_after_test_module/root_module.fixed similarity index 86% rename from tests/ui/items_after_test_module/block_module.rs rename to tests/ui/items_after_test_module/root_module.fixed index 5136b2557ec1..d444100a76b9 100644 --- a/tests/ui/items_after_test_module/block_module.rs +++ b/tests/ui/items_after_test_module/root_module.fixed @@ -1,4 +1,3 @@ -//@compile-flags: --test #![allow(unused)] #![warn(clippy::items_after_test_module)] @@ -6,6 +5,13 @@ fn main() {} fn should_not_lint() {} +fn should_lint() {} + +const SHOULD_ALSO_LINT: usize = 1; +macro_rules! should_lint { + () => {}; +} + #[allow(dead_code)] #[allow(unused)] // Some attributes to check that span replacement is good enough #[allow(clippy::allow_attributes)] @@ -14,10 +20,3 @@ mod tests { #[test] fn hi() {} } - -fn should_lint() {} - -const SHOULD_ALSO_LINT: usize = 1; -macro_rules! should_not_lint { - () => {}; -} diff --git a/tests/ui/items_after_test_module/root_module.rs b/tests/ui/items_after_test_module/root_module.rs new file mode 100644 index 000000000000..57da01639cca --- /dev/null +++ b/tests/ui/items_after_test_module/root_module.rs @@ -0,0 +1,22 @@ +#![allow(unused)] +#![warn(clippy::items_after_test_module)] + +fn main() {} + +fn should_not_lint() {} + +#[allow(dead_code)] +#[allow(unused)] // Some attributes to check that span replacement is good enough +#[allow(clippy::allow_attributes)] +#[cfg(test)] +mod tests { + #[test] + fn hi() {} +} + +fn should_lint() {} + +const SHOULD_ALSO_LINT: usize = 1; +macro_rules! should_lint { + () => {}; +} diff --git a/tests/ui/items_after_test_module/root_module.stderr b/tests/ui/items_after_test_module/root_module.stderr new file mode 100644 index 000000000000..67bc82ebff91 --- /dev/null +++ b/tests/ui/items_after_test_module/root_module.stderr @@ -0,0 +1,20 @@ +error: items after a test module + --> $DIR/root_module.rs:12:1 + | +LL | mod tests { + | ^^^^^^^^^ +... +LL | fn should_lint() {} + | ^^^^^^^^^^^^^^^^ +LL | +LL | const SHOULD_ALSO_LINT: usize = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | macro_rules! should_lint { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::items-after-test-module` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]` + = help: move the items to before the test module was defined + +error: aborting due to previous error + diff --git a/tests/ui/iter_without_into_iter.rs b/tests/ui/iter_without_into_iter.rs new file mode 100644 index 000000000000..cedb756c79de --- /dev/null +++ b/tests/ui/iter_without_into_iter.rs @@ -0,0 +1,120 @@ +//@no-rustfix +#![warn(clippy::iter_without_into_iter)] + +fn main() { + { + struct S; + impl S { + pub fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + [].iter() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + [].iter_mut() + } + } + } + { + struct S; + impl S { + pub fn iter(&self) -> impl Iterator { + // RPITIT is not stable, so we can't generally suggest it here yet + [].iter() + } + } + } + { + struct S<'a>(&'a mut [u8]); + impl<'a> S<'a> { + pub fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + self.0.iter() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + self.0.iter_mut() + } + } + } + { + // Incompatible signatures + struct S; + impl S { + pub fn iter(self) -> std::slice::Iter<'static, u8> { + todo!() + } + } + struct S2; + impl S2 { + pub async fn iter(&self) -> std::slice::Iter<'static, u8> { + todo!() + } + } + struct S3; + impl S3 { + pub fn iter(&self, _additional_param: ()) -> std::slice::Iter<'static, u8> { + todo!() + } + } + struct S4(T); + impl S4 { + pub fn iter(&self) -> std::slice::Iter<'static, (T, U)> { + todo!() + } + } + struct S5(T); + impl S5 { + pub fn iter(&self) -> std::slice::Iter<'static, T> { + todo!() + } + } + } + { + struct S(T); + impl S { + pub fn iter(&self) -> std::slice::Iter<'_, T> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + todo!() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + todo!() + } + } + } + { + struct S(T); + impl S { + pub fn iter(&self) -> std::slice::Iter<'_, T> { + // Don't lint, there's an existing (wrong) IntoIterator impl + todo!() + } + } + + impl<'a, T> IntoIterator for &'a S { + type Item = &'a String; + type IntoIter = std::slice::Iter<'a, String>; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + struct S(T); + impl S { + pub fn iter_mut(&self) -> std::slice::IterMut<'_, T> { + // Don't lint, there's an existing (wrong) IntoIterator impl + todo!() + } + } + + impl<'a, T> IntoIterator for &'a mut S { + type Item = &'a mut String; + type IntoIter = std::slice::IterMut<'a, String>; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } +} diff --git a/tests/ui/iter_without_into_iter.stderr b/tests/ui/iter_without_into_iter.stderr new file mode 100644 index 000000000000..9d0b99415a50 --- /dev/null +++ b/tests/ui/iter_without_into_iter.stderr @@ -0,0 +1,150 @@ +error: `iter` method without an `IntoIterator` impl for `&S` + --> $DIR/iter_without_into_iter.rs:8:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | | +LL | | [].iter() +LL | | } + | |_____________^ + | + = note: `-D clippy::iter-without-into-iter` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_without_into_iter)]` +help: consider implementing `IntoIterator` for `&S` + | +LL ~ +LL + impl IntoIterator for &S { +LL + type IntoIter = std::slice::Iter<'_, u8>; +LL + type Iter = &u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter_mut` method without an `IntoIterator` impl for `&mut S` + --> $DIR/iter_without_into_iter.rs:12:13 + | +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { +LL | | +LL | | [].iter_mut() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&mut S` + | +LL ~ +LL + impl IntoIterator for &mut S { +LL + type IntoIter = std::slice::IterMut<'_, u8>; +LL + type Iter = &mut u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter` method without an `IntoIterator` impl for `&S<'a>` + --> $DIR/iter_without_into_iter.rs:30:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | | +LL | | self.0.iter() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&S<'a>` + | +LL ~ +LL + impl IntoIterator for &S<'a> { +LL + type IntoIter = std::slice::Iter<'_, u8>; +LL + type Iter = &u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter_mut` method without an `IntoIterator` impl for `&mut S<'a>` + --> $DIR/iter_without_into_iter.rs:34:13 + | +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { +LL | | +LL | | self.0.iter_mut() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&mut S<'a>` + | +LL ~ +LL + impl IntoIterator for &mut S<'a> { +LL + type IntoIter = std::slice::IterMut<'_, u8>; +LL + type Iter = &mut u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter` method without an `IntoIterator` impl for `&S5` + --> $DIR/iter_without_into_iter.rs:68:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> { +LL | | todo!() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&S5` + | +LL ~ +LL + impl IntoIterator for &S5 { +LL + type IntoIter = std::slice::Iter<'static, T>; +LL + type Iter = &T; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter` method without an `IntoIterator` impl for `&S` + --> $DIR/iter_without_into_iter.rs:76:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> { +LL | | +LL | | todo!() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&S` + | +LL ~ +LL + impl IntoIterator for &S { +LL + type IntoIter = std::slice::Iter<'_, T>; +LL + type Iter = &T; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter_mut` method without an `IntoIterator` impl for `&mut S` + --> $DIR/iter_without_into_iter.rs:80:13 + | +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { +LL | | +LL | | todo!() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&mut S` + | +LL ~ +LL + impl IntoIterator for &mut S { +LL + type IntoIter = std::slice::IterMut<'_, T>; +LL + type Iter = &mut T; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: aborting due to 7 previous errors + diff --git a/tests/ui/let_underscore_future.rs b/tests/ui/let_underscore_future.rs index 873ae667ab71..c2185e9785d8 100644 --- a/tests/ui/let_underscore_future.rs +++ b/tests/ui/let_underscore_future.rs @@ -9,8 +9,6 @@ fn custom() -> impl Future { } fn do_something_to_future(future: &mut impl Future) {} -//~^ ERROR: this argument is a mutable reference, but not used mutably -//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` fn main() { let _ = some_async_fn(); diff --git a/tests/ui/let_underscore_future.stderr b/tests/ui/let_underscore_future.stderr index 3ba99c6377b7..ef927a8083bc 100644 --- a/tests/ui/let_underscore_future.stderr +++ b/tests/ui/let_underscore_future.stderr @@ -1,5 +1,5 @@ error: non-binding `let` on a future - --> $DIR/let_underscore_future.rs:16:5 + --> $DIR/let_underscore_future.rs:14:5 | LL | let _ = some_async_fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _ = some_async_fn(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]` error: non-binding `let` on a future - --> $DIR/let_underscore_future.rs:18:5 + --> $DIR/let_underscore_future.rs:16:5 | LL | let _ = custom(); | ^^^^^^^^^^^^^^^^^ @@ -17,21 +17,12 @@ LL | let _ = custom(); = help: consider awaiting the future or dropping explicitly with `std::mem::drop` error: non-binding `let` on a future - --> $DIR/let_underscore_future.rs:23:5 + --> $DIR/let_underscore_future.rs:21:5 | LL | let _ = future; | ^^^^^^^^^^^^^^^ | = help: consider awaiting the future or dropping explicitly with `std::mem::drop` -error: this argument is a mutable reference, but not used mutably - --> $DIR/let_underscore_future.rs:11:35 - | -LL | fn do_something_to_future(future: &mut impl Future) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/manual_hash_one.fixed b/tests/ui/manual_hash_one.fixed new file mode 100644 index 000000000000..edfd9c4a47bb --- /dev/null +++ b/tests/ui/manual_hash_one.fixed @@ -0,0 +1,89 @@ +#![warn(clippy::manual_hash_one)] +#![allow(clippy::needless_borrows_for_generic_args)] + +use std::hash::{BuildHasher, Hash, Hasher}; + +fn returned(b: impl BuildHasher) -> u64 { + + + b.hash_one(&true) +} + +fn unsized_receiver(b: impl BuildHasher, s: &str) { + + + let _ = b.hash_one(&s[4..10]); +} + +fn owned_value(b: impl BuildHasher, v: Vec) -> Vec { + + + let _ = b.hash_one(&v); + v +} + +fn reused_hasher(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + let _ = hasher.finish(); +} + +fn reused_hasher_in_return(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + hasher.finish() +} + +fn no_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); +} + +fn hash_twice(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + true.hash(&mut hasher); + let _ = hasher.finish(); +} + +fn other_hasher(b: impl BuildHasher) { + let mut other_hasher = b.build_hasher(); + + let mut hasher = b.build_hasher(); + true.hash(&mut other_hasher); + let _ = hasher.finish(); +} + +fn finish_then_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); + true.hash(&mut hasher); +} + +fn in_macro(b: impl BuildHasher) { + macro_rules! m { + ($b:expr) => {{ + let mut hasher = $b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + }}; + } + + m!(b); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} + +#[clippy::msrv = "1.71"] +fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { + + + let _ = b.hash_one(&v); +} diff --git a/tests/ui/manual_hash_one.rs b/tests/ui/manual_hash_one.rs new file mode 100644 index 000000000000..ee61522853f0 --- /dev/null +++ b/tests/ui/manual_hash_one.rs @@ -0,0 +1,89 @@ +#![warn(clippy::manual_hash_one)] +#![allow(clippy::needless_borrows_for_generic_args)] + +use std::hash::{BuildHasher, Hash, Hasher}; + +fn returned(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + hasher.finish() +} + +fn unsized_receiver(b: impl BuildHasher, s: &str) { + let mut hasher = b.build_hasher(); + s[4..10].hash(&mut hasher); + let _ = hasher.finish(); +} + +fn owned_value(b: impl BuildHasher, v: Vec) -> Vec { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); + v +} + +fn reused_hasher(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + let _ = hasher.finish(); +} + +fn reused_hasher_in_return(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + hasher.finish() +} + +fn no_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); +} + +fn hash_twice(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + true.hash(&mut hasher); + let _ = hasher.finish(); +} + +fn other_hasher(b: impl BuildHasher) { + let mut other_hasher = b.build_hasher(); + + let mut hasher = b.build_hasher(); + true.hash(&mut other_hasher); + let _ = hasher.finish(); +} + +fn finish_then_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); + true.hash(&mut hasher); +} + +fn in_macro(b: impl BuildHasher) { + macro_rules! m { + ($b:expr) => {{ + let mut hasher = $b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + }}; + } + + m!(b); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} + +#[clippy::msrv = "1.71"] +fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} diff --git a/tests/ui/manual_hash_one.stderr b/tests/ui/manual_hash_one.stderr new file mode 100644 index 000000000000..3ce6f41e1f91 --- /dev/null +++ b/tests/ui/manual_hash_one.stderr @@ -0,0 +1,56 @@ +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:9:5 + | +LL | hasher.finish() + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-hash-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_hash_one)]` +help: try + | +LL ~ +LL ~ +LL ~ b.hash_one(&true) + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:15:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&s[4..10]); + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:21:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&v); + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:88:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&v); + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_let_else_match.fixed b/tests/ui/manual_let_else_match.fixed index 09b713f04101..588ba5edd8f1 100644 --- a/tests/ui/manual_let_else_match.fixed +++ b/tests/ui/manual_let_else_match.fixed @@ -133,3 +133,7 @@ fn not_fire() { [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data, }; } + +fn issue11579() { + let Some(msg) = Some("hi") else { unreachable!("can't happen") }; +} diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs index e6af47384200..c37b5613ff7d 100644 --- a/tests/ui/manual_let_else_match.rs +++ b/tests/ui/manual_let_else_match.rs @@ -170,3 +170,11 @@ fn not_fire() { [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data, }; } + +fn issue11579() { + let msg = match Some("hi") { + //~^ ERROR: this could be rewritten as `let...else` + Some(m) => m, + _ => unreachable!("can't happen"), + }; +} diff --git a/tests/ui/manual_let_else_match.stderr b/tests/ui/manual_let_else_match.stderr index 8ca2c84072d0..18bfe324ba76 100644 --- a/tests/ui/manual_let_else_match.stderr +++ b/tests/ui/manual_let_else_match.stderr @@ -92,5 +92,15 @@ LL | | _ => return, LL | | }; | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };` -error: aborting due to 9 previous errors +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else_match.rs:175:5 + | +LL | / let msg = match Some("hi") { +LL | | +LL | | Some(m) => m, +LL | | _ => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let Some(msg) = Some("hi") else { unreachable!("can't happen") };` + +error: aborting due to 10 previous errors diff --git a/tests/ui/manual_non_exhaustive_enum.rs b/tests/ui/manual_non_exhaustive_enum.rs index 0e439dabfd65..e32ba8631761 100644 --- a/tests/ui/manual_non_exhaustive_enum.rs +++ b/tests/ui/manual_non_exhaustive_enum.rs @@ -10,10 +10,9 @@ enum E { _C, } -// user forgot to remove the marker +// if the user explicitly marks as nonexhaustive we shouldn't warn them #[non_exhaustive] enum Ep { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern A, B, #[doc(hidden)] diff --git a/tests/ui/manual_non_exhaustive_enum.stderr b/tests/ui/manual_non_exhaustive_enum.stderr index ce7e21c94bbd..7361a4a2cbbe 100644 --- a/tests/ui/manual_non_exhaustive_enum.stderr +++ b/tests/ui/manual_non_exhaustive_enum.stderr @@ -22,23 +22,5 @@ LL | _C, = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` -error: this seems like a manual implementation of the non-exhaustive pattern - --> $DIR/manual_non_exhaustive_enum.rs:15:1 - | -LL | / enum Ep { -LL | | -LL | | A, -LL | | B, -LL | | #[doc(hidden)] -LL | | _C, -LL | | } - | |_^ - | -help: remove this variant - --> $DIR/manual_non_exhaustive_enum.rs:20:5 - | -LL | _C, - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index 806921321768..2d70bfd4c770 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -32,8 +32,6 @@ fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet = HashMap::new(); //~^ ERROR: mutable key type m.keys().cloned().collect() diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index 3701769a9ca7..48eeaff78a78 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -14,103 +14,94 @@ LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> Hash | ^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:37:5 + --> $DIR/mut_key.rs:35:5 | LL | let _other: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:65:22 + --> $DIR/mut_key.rs:63:22 | LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:78:5 + --> $DIR/mut_key.rs:76:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:80:5 + --> $DIR/mut_key.rs:78:5 | LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:82:5 + --> $DIR/mut_key.rs:80:5 | LL | let _map = HashMap::<&mut usize, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:85:5 + --> $DIR/mut_key.rs:83:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:87:5 + --> $DIR/mut_key.rs:85:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:89:5 + --> $DIR/mut_key.rs:87:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:91:5 + --> $DIR/mut_key.rs:89:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:93:5 + --> $DIR/mut_key.rs:91:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:95:5 + --> $DIR/mut_key.rs:93:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:97:5 + --> $DIR/mut_key.rs:95:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:100:5 + --> $DIR/mut_key.rs:98:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:102:5 + --> $DIR/mut_key.rs:100:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:104:5 + --> $DIR/mut_key.rs:102:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this argument is a mutable reference, but not used mutably - --> $DIR/mut_key.rs:31:32 - | -LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 18 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index f3db226e4e7f..1d7faaa5e75e 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -22,8 +22,6 @@ impl MyStruct { fn takes_an_immutable_reference(&self, a: &i32) {} fn takes_a_mutable_reference(&self, a: &mut i32) {} - //~^ ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` } #[warn(clippy::unnecessary_mut_passed)] diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index d7a0d0c22525..87db08e2a742 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -1,5 +1,5 @@ error: the function `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:32:34 + --> $DIR/mut_reference.rs:30:34 | LL | takes_an_immutable_reference(&mut 42); | ^^^^^^^ @@ -8,25 +8,16 @@ LL | takes_an_immutable_reference(&mut 42); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` error: the function `as_ptr` doesn't need a mutable reference - --> $DIR/mut_reference.rs:36:12 + --> $DIR/mut_reference.rs:34:12 | LL | as_ptr(&mut 42); | ^^^^^^^ error: the method `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:41:44 + --> $DIR/mut_reference.rs:39:44 | LL | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ -error: this argument is a mutable reference, but not used mutably - --> $DIR/mut_reference.rs:24:44 - | -LL | fn takes_a_mutable_reference(&self, a: &mut i32) {} - | ^^^^^^^^ help: consider changing to: `&i32` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index 9cddcb3df237..39d76f999002 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -1,4 +1,5 @@ #![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)] +#![warn(clippy::needless_pass_by_ref_mut)] #![feature(lint_reasons)] //@no-rustfix use std::ptr::NonNull; diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 0c7fbd5df6d9..aa937c3f6af2 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,5 +1,5 @@ error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:6:11 + --> $DIR/needless_pass_by_ref_mut.rs:7:11 | LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:31:12 + --> $DIR/needless_pass_by_ref_mut.rs:32:12 | LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:44:29 + --> $DIR/needless_pass_by_ref_mut.rs:45:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:49:31 + --> $DIR/needless_pass_by_ref_mut.rs:50:31 | LL | fn badger(&mut self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:126:16 + --> $DIR/needless_pass_by_ref_mut.rs:127:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:130:16 + --> $DIR/needless_pass_by_ref_mut.rs:131:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:134:16 + --> $DIR/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:138:16 + --> $DIR/needless_pass_by_ref_mut.rs:139:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:142:24 + --> $DIR/needless_pass_by_ref_mut.rs:143:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:146:24 + --> $DIR/needless_pass_by_ref_mut.rs:147:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:150:32 + --> $DIR/needless_pass_by_ref_mut.rs:151:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:154:24 + --> $DIR/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:154:45 + --> $DIR/needless_pass_by_ref_mut.rs:155:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:188:16 + --> $DIR/needless_pass_by_ref_mut.rs:189:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:194:20 + --> $DIR/needless_pass_by_ref_mut.rs:195:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:208:39 + --> $DIR/needless_pass_by_ref_mut.rs:209:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:216:26 + --> $DIR/needless_pass_by_ref_mut.rs:217:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:235:34 + --> $DIR/needless_pass_by_ref_mut.rs:236:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:247:25 + --> $DIR/needless_pass_by_ref_mut.rs:248:25 | LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -124,7 +124,7 @@ LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:254:20 + --> $DIR/needless_pass_by_ref_mut.rs:255:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,7 +132,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:265:26 + --> $DIR/needless_pass_by_ref_mut.rs:266:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` diff --git a/tests/ui/needless_raw_string.fixed b/tests/ui/needless_raw_string.fixed index 855498105135..4ea711fd67a1 100644 --- a/tests/ui/needless_raw_string.fixed +++ b/tests/ui/needless_raw_string.fixed @@ -18,4 +18,8 @@ fn main() { multiline string "; + + "no hashes"; + b"no hashes"; + c"no hashes"; } diff --git a/tests/ui/needless_raw_string.rs b/tests/ui/needless_raw_string.rs index 06d497303871..b6239f9b1f03 100644 --- a/tests/ui/needless_raw_string.rs +++ b/tests/ui/needless_raw_string.rs @@ -18,4 +18,8 @@ fn main() { multiline string "#; + + r"no hashes"; + br"no hashes"; + cr"no hashes"; } diff --git a/tests/ui/needless_raw_string.stderr b/tests/ui/needless_raw_string.stderr index e6806b31b1d9..276bc84c6c37 100644 --- a/tests/ui/needless_raw_string.stderr +++ b/tests/ui/needless_raw_string.stderr @@ -6,7 +6,7 @@ LL | r#"aaa"#; | = note: `-D clippy::needless-raw-strings` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]` -help: try +help: use a plain string literal instead | LL - r#"aaa"#; LL + "aaa"; @@ -18,7 +18,7 @@ error: unnecessary raw string literal LL | br#"aaa"#; | ^^^^^^^^^ | -help: try +help: use a plain byte string literal instead | LL - br#"aaa"#; LL + b"aaa"; @@ -30,7 +30,7 @@ error: unnecessary raw string literal LL | cr#"aaa"#; | ^^^^^^^^^ | -help: try +help: use a plain C string literal instead | LL - cr#"aaa"#; LL + c"aaa"; @@ -46,7 +46,7 @@ LL | | string LL | | "#; | |______^ | -help: try +help: use a plain string literal instead | LL ~ " LL | a @@ -55,5 +55,41 @@ LL | string LL ~ "; | -error: aborting due to 4 previous errors +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:22:5 + | +LL | r"no hashes"; + | ^^^^^^^^^^^^ + | +help: use a plain string literal instead + | +LL - r"no hashes"; +LL + "no hashes"; + | + +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:23:5 + | +LL | br"no hashes"; + | ^^^^^^^^^^^^^ + | +help: use a plain byte string literal instead + | +LL - br"no hashes"; +LL + b"no hashes"; + | + +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:24:5 + | +LL | cr"no hashes"; + | ^^^^^^^^^^^^^ + | +help: use a plain C string literal instead + | +LL - cr"no hashes"; +LL + c"no hashes"; + | + +error: aborting due to 7 previous errors diff --git a/tests/ui/needless_raw_string_hashes.stderr b/tests/ui/needless_raw_string_hashes.stderr index 4399c6555c2c..017160b1a421 100644 --- a/tests/ui/needless_raw_string_hashes.stderr +++ b/tests/ui/needless_raw_string_hashes.stderr @@ -6,7 +6,7 @@ LL | r#"\aaa"#; | = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]` -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL - r#"\aaa"#; LL + r"\aaa"; @@ -18,7 +18,7 @@ error: unnecessary hashes around raw string literal LL | r##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^ | -help: remove one hash from both sides of the literal +help: remove one hash from both sides of the string literal | LL - r##"Hello "world"!"##; LL + r#"Hello "world"!"#; @@ -30,7 +30,7 @@ error: unnecessary hashes around raw string literal LL | r######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 2 hashes from both sides of the literal +help: remove 2 hashes from both sides of the string literal | LL - r######" "### "## "# "######; LL + r####" "### "## "# "####; @@ -42,7 +42,7 @@ error: unnecessary hashes around raw string literal LL | r######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 3 hashes from both sides of the literal +help: remove 3 hashes from both sides of the string literal | LL - r######" "aa" "# "## "######; LL + r###" "aa" "# "## "###; @@ -54,7 +54,7 @@ error: unnecessary hashes around raw string literal LL | br#"\aaa"#; | ^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the byte string literal | LL - br#"\aaa"#; LL + br"\aaa"; @@ -66,7 +66,7 @@ error: unnecessary hashes around raw string literal LL | br##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ | -help: remove one hash from both sides of the literal +help: remove one hash from both sides of the byte string literal | LL - br##"Hello "world"!"##; LL + br#"Hello "world"!"#; @@ -78,7 +78,7 @@ error: unnecessary hashes around raw string literal LL | br######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 2 hashes from both sides of the literal +help: remove 2 hashes from both sides of the byte string literal | LL - br######" "### "## "# "######; LL + br####" "### "## "# "####; @@ -90,7 +90,7 @@ error: unnecessary hashes around raw string literal LL | br######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 3 hashes from both sides of the literal +help: remove 3 hashes from both sides of the byte string literal | LL - br######" "aa" "# "## "######; LL + br###" "aa" "# "## "###; @@ -102,7 +102,7 @@ error: unnecessary hashes around raw string literal LL | cr#"\aaa"#; | ^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the C string literal | LL - cr#"\aaa"#; LL + cr"\aaa"; @@ -114,7 +114,7 @@ error: unnecessary hashes around raw string literal LL | cr##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ | -help: remove one hash from both sides of the literal +help: remove one hash from both sides of the C string literal | LL - cr##"Hello "world"!"##; LL + cr#"Hello "world"!"#; @@ -126,7 +126,7 @@ error: unnecessary hashes around raw string literal LL | cr######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 2 hashes from both sides of the literal +help: remove 2 hashes from both sides of the C string literal | LL - cr######" "### "## "# "######; LL + cr####" "### "## "# "####; @@ -138,7 +138,7 @@ error: unnecessary hashes around raw string literal LL | cr######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 3 hashes from both sides of the literal +help: remove 3 hashes from both sides of the C string literal | LL - cr######" "aa" "# "## "######; LL + cr###" "aa" "# "## "###; @@ -154,7 +154,7 @@ LL | | string LL | | "#; | |______^ | -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL ~ r" LL | \a @@ -169,7 +169,7 @@ error: unnecessary hashes around raw string literal LL | r###"rust"###; | ^^^^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL - r###"rust"###; LL + r"rust"; @@ -181,7 +181,7 @@ error: unnecessary hashes around raw string literal LL | r#"hello world"#; | ^^^^^^^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL - r#"hello world"#; LL + r"hello world"; diff --git a/tests/ui/print_literal.fixed b/tests/ui/print_literal.fixed index 88cd3a54b410..a7157c07f8a9 100644 --- a/tests/ui/print_literal.fixed +++ b/tests/ui/print_literal.fixed @@ -39,20 +39,30 @@ fn main() { // throw a warning println!("hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either println!("hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // The string literal from `file!()` has a callsite span that isn't marked as coming from an // expansion println!("file: {}", file!()); + + // Braces in unicode escapes should not be escaped + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}"); + println!("\\\u{1234}"); + // This does not lint because it would have to suggest unescaping the character + println!(r"{}", "\u{ab123}"); + // These are not unicode escapes + println!("\\u{{ab123}} \\u{{{{"); + println!(r"\u{{ab123}} \u{{{{"); + println!("\\{{ab123}} \\u{{{{"); + println!("\\u{{ab123}}"); + println!("\\\\u{{1234}}"); + + println!("mixed: {{hello}} {world}"); } diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index bd7444c9606a..4b04b42744cc 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -39,20 +39,30 @@ fn main() { // throw a warning println!("{0} {1}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("{1} {0}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either println!("{foo} {bar}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("{bar} {foo}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // The string literal from `file!()` has a callsite span that isn't marked as coming from an // expansion println!("file: {}", file!()); + + // Braces in unicode escapes should not be escaped + println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); + println!("{}", "\\\u{1234}"); + // This does not lint because it would have to suggest unescaping the character + println!(r"{}", "\u{ab123}"); + // These are not unicode escapes + println!("{}", r"\u{ab123} \u{{"); + println!(r"{}", r"\u{ab123} \u{{"); + println!("{}", r"\{ab123} \u{{"); + println!("{}", "\\u{ab123}"); + println!("{}", "\\\\u{1234}"); + + println!("mixed: {} {world}", "{hello}"); } diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 1d9751b92e9c..8c011d7bc0a6 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -52,97 +52,145 @@ error: literal with an empty format string --> $DIR/print_literal.rs:40:25 | LL | println!("{0} {1}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: try | LL - println!("{0} {1}", "hello", "world"); -LL + println!("hello {1}", "world"); +LL + println!("hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:40:34 - | -LL | println!("{0} {1}", "hello", "world"); - | ^^^^^^^ - | -help: try - | -LL - println!("{0} {1}", "hello", "world"); -LL + println!("{0} world", "hello"); - | - -error: literal with an empty format string - --> $DIR/print_literal.rs:43:34 + --> $DIR/print_literal.rs:42:25 | LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: try | LL - println!("{1} {0}", "hello", "world"); -LL + println!("world {0}", "hello"); +LL + println!("world hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:43:25 + --> $DIR/print_literal.rs:46:35 | -LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | println!("{foo} {bar}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{1} {0}", "hello", "world"); -LL + println!("{1} hello", "world"); +LL - println!("{foo} {bar}", foo = "hello", bar = "world"); +LL + println!("hello world"); | error: literal with an empty format string --> $DIR/print_literal.rs:48:35 | -LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ - | -help: try - | -LL - println!("{foo} {bar}", foo = "hello", bar = "world"); -LL + println!("hello {bar}", bar = "world"); - | - -error: literal with an empty format string - --> $DIR/print_literal.rs:48:50 - | -LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ - | -help: try - | -LL - println!("{foo} {bar}", foo = "hello", bar = "world"); -LL + println!("{foo} world", foo = "hello"); - | - -error: literal with an empty format string - --> $DIR/print_literal.rs:51:50 - | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("world {foo}", foo = "hello"); +LL + println!("world hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:51:35 + --> $DIR/print_literal.rs:56:20 | -LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("{bar} hello", bar = "world"); +LL - println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); +LL + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}"); | -error: aborting due to 12 previous errors +error: literal with an empty format string + --> $DIR/print_literal.rs:57:20 + | +LL | println!("{}", "\\\u{1234}"); + | ^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", "\\\u{1234}"); +LL + println!("\\\u{1234}"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:61:20 + | +LL | println!("{}", r"\u{ab123} \u{{"); + | ^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", r"\u{ab123} \u{{"); +LL + println!("\\u{{ab123}} \\u{{{{"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:62:21 + | +LL | println!(r"{}", r"\u{ab123} \u{{"); + | ^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - println!(r"{}", r"\u{ab123} \u{{"); +LL + println!(r"\u{{ab123}} \u{{{{"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:63:20 + | +LL | println!("{}", r"\{ab123} \u{{"); + | ^^^^^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", r"\{ab123} \u{{"); +LL + println!("\\{{ab123}} \\u{{{{"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:64:20 + | +LL | println!("{}", "\\u{ab123}"); + | ^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", "\\u{ab123}"); +LL + println!("\\u{{ab123}}"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:65:20 + | +LL | println!("{}", "\\\\u{1234}"); + | ^^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", "\\\\u{1234}"); +LL + println!("\\\\u{{1234}}"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:67:35 + | +LL | println!("mixed: {} {world}", "{hello}"); + | ^^^^^^^^^ + | +help: try + | +LL - println!("mixed: {} {world}", "{hello}"); +LL + println!("mixed: {{hello}} {world}"); + | + +error: aborting due to 16 previous errors diff --git a/tests/ui/redundant_locals.rs b/tests/ui/redundant_locals.rs index c5d93e4365d9..e81db300f15a 100644 --- a/tests/ui/redundant_locals.rs +++ b/tests/ui/redundant_locals.rs @@ -118,3 +118,40 @@ fn macros() { let x = x; } } + +struct WithDrop(usize); +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +struct InnerDrop(WithDrop); + +struct ComposeDrop { + d: WithDrop, +} + +struct WithoutDrop(usize); + +fn drop_trait() { + let a = WithDrop(1); + let b = WithDrop(2); + let a = a; +} + +fn without_drop() { + let a = WithoutDrop(1); + let b = WithoutDrop(2); + let a = a; +} + +fn drop_inner() { + let a = InnerDrop(WithDrop(1)); + let b = InnerDrop(WithDrop(2)); + let a = a; +} + +fn drop_compose() { + let a = ComposeDrop { d: WithDrop(1) }; + let b = ComposeDrop { d: WithDrop(1) }; + let a = a; +} diff --git a/tests/ui/redundant_locals.stderr b/tests/ui/redundant_locals.stderr index 13b872e9576d..d794a87fe7df 100644 --- a/tests/ui/redundant_locals.stderr +++ b/tests/ui/redundant_locals.stderr @@ -1,137 +1,172 @@ -error: redundant redefinition of a binding +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:12:5 + | +LL | let x = x; + | ^^^^^^^^^^ + | +help: `x` is initially defined here --> $DIR/redundant_locals.rs:11:9 | LL | let x = 1; | ^ -LL | let x = x; - | ^^^^^^^^^^ - | - = help: remove the redefinition of `x` = note: `-D clippy::redundant-locals` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]` -error: redundant redefinition of a binding +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:17:5 + | +LL | let mut x = x; + | ^^^^^^^^^^^^^^ + | +help: `x` is initially defined here --> $DIR/redundant_locals.rs:16:9 | LL | let mut x = 1; | ^^^^^ -LL | let mut x = x; - | ^^^^^^^^^^^^^^ - | - = help: remove the redefinition of `x` -error: redundant redefinition of a binding +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:47:5 + | +LL | let x = x; + | ^^^^^^^^^^ + | +help: `x` is initially defined here --> $DIR/redundant_locals.rs:46:14 | LL | fn parameter(x: i32) { | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:52:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:51:9 | LL | let x = 1; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:53:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:52:9 | LL | let x = x; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:54:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:53:9 | LL | let x = x; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:55:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:54:9 | LL | let x = x; | ^ -LL | let x = x; + +error: redundant redefinition of a binding `a` + --> $DIR/redundant_locals.rs:61:5 + | +LL | let a = a; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `a` is initially defined here --> $DIR/redundant_locals.rs:59:9 | LL | let a = 1; | ^ -LL | let b = 2; -LL | let a = a; + +error: redundant redefinition of a binding `b` + --> $DIR/redundant_locals.rs:62:5 + | +LL | let b = b; | ^^^^^^^^^^ | - = help: remove the redefinition of `a` - -error: redundant redefinition of a binding +help: `b` is initially defined here --> $DIR/redundant_locals.rs:60:9 | LL | let b = 2; | ^ -LL | let a = a; -LL | let b = b; - | ^^^^^^^^^^ - | - = help: remove the redefinition of `b` -error: redundant redefinition of a binding +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:68:9 + | +LL | let x = x; + | ^^^^^^^^^^ + | +help: `x` is initially defined here --> $DIR/redundant_locals.rs:67:13 | LL | let x = 1; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:75:9 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:74:13 | LL | let x = 1; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:78:9 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:77:6 | LL | |x: i32| { | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:97:9 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:94:9 | LL | let x = 1; | ^ -... -LL | let x = x; - | ^^^^^^^^^^ + +error: redundant redefinition of a binding `a` + --> $DIR/redundant_locals.rs:144:5 | - = help: remove the redefinition of `x` +LL | let a = a; + | ^^^^^^^^^^ + | +help: `a` is initially defined here + --> $DIR/redundant_locals.rs:142:9 + | +LL | let a = WithoutDrop(1); + | ^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs index 550ec0072681..33211b32d74b 100644 --- a/tests/ui/should_impl_trait/method_list_2.rs +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -40,8 +40,6 @@ impl T { pub fn hash(&self, state: &mut T) { //~^ ERROR: method `hash` can be confused for the standard trait method `std::hash::Ha - //~| ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` unimplemented!() } diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index 79afddea2479..c257f4113426 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -38,8 +38,6 @@ error: method `hash` can be confused for the standard trait method `std::hash::H | LL | / pub fn hash(&self, state: &mut T) { LL | | -LL | | -LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -47,7 +45,7 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> $DIR/method_list_2.rs:48:5 + --> $DIR/method_list_2.rs:46:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | @@ -58,7 +56,7 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> $DIR/method_list_2.rs:53:5 + --> $DIR/method_list_2.rs:51:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | @@ -69,7 +67,7 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> $DIR/method_list_2.rs:58:5 + --> $DIR/method_list_2.rs:56:5 | LL | / pub fn into_iter(self) -> Self { LL | | @@ -80,7 +78,7 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> $DIR/method_list_2.rs:63:5 + --> $DIR/method_list_2.rs:61:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | @@ -91,7 +89,7 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> $DIR/method_list_2.rs:68:5 + --> $DIR/method_list_2.rs:66:5 | LL | / pub fn neg(self) -> Self { LL | | @@ -102,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> $DIR/method_list_2.rs:73:5 + --> $DIR/method_list_2.rs:71:5 | LL | / pub fn next(&mut self) -> Option { LL | | @@ -113,7 +111,7 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> $DIR/method_list_2.rs:78:5 + --> $DIR/method_list_2.rs:76:5 | LL | / pub fn not(self) -> Self { LL | | @@ -124,7 +122,7 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> $DIR/method_list_2.rs:83:5 + --> $DIR/method_list_2.rs:81:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | @@ -135,7 +133,7 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> $DIR/method_list_2.rs:88:5 + --> $DIR/method_list_2.rs:86:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | @@ -146,7 +144,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> $DIR/method_list_2.rs:93:5 + --> $DIR/method_list_2.rs:91:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | @@ -157,7 +155,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> $DIR/method_list_2.rs:98:5 + --> $DIR/method_list_2.rs:96:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | @@ -167,15 +165,5 @@ LL | | } | = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name -error: this argument is a mutable reference, but not used mutably - --> $DIR/method_list_2.rs:41:31 - | -LL | pub fn hash(&self, state: &mut T) { - | ^^^^^^ help: consider changing to: `&T` - | - = warning: changing this function will impact semver compatibility - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs index 5c3086c9d69e..16f81019574f 100644 --- a/tests/ui/slow_vector_initialization.rs +++ b/tests/ui/slow_vector_initialization.rs @@ -103,8 +103,6 @@ fn from_empty_vec() { } fn do_stuff(vec: &mut [u8]) {} -//~^ ERROR: this argument is a mutable reference, but not used mutably -//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` fn extend_vector_with_manipulations_between() { let len = 300; diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index 4d24400ecb59..16a7057653c1 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -105,14 +105,5 @@ LL | vec1 = vec![]; LL | vec1.resize(10, 0); | ^^^^^^^^^^^^^^^^^^ -error: this argument is a mutable reference, but not used mutably - --> $DIR/slow_vector_initialization.rs:105:18 - | -LL | fn do_stuff(vec: &mut [u8]) {} - | ^^^^^^^^^ help: consider changing to: `&[u8]` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index 8027c053fb5b..a7555704fbe0 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -1,8 +1,12 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::std_instead_of_core)] #![allow(unused_imports)] extern crate alloc; +#[macro_use] +extern crate proc_macro_derive; + #[warn(clippy::std_instead_of_core)] fn std_instead_of_core() { // Regular import @@ -55,6 +59,13 @@ fn alloc_instead_of_core() { //~^ ERROR: used import from `alloc` instead of `core` } +mod std_in_proc_macro_derive { + #[warn(clippy::alloc_instead_of_core)] + #[allow(unused)] + #[derive(ImplStructWithStdDisplay)] + struct B {} +} + fn main() { std_instead_of_core(); std_instead_of_alloc(); diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index 63a096384d71..af7f3399f492 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -1,8 +1,12 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::std_instead_of_core)] #![allow(unused_imports)] extern crate alloc; +#[macro_use] +extern crate proc_macro_derive; + #[warn(clippy::std_instead_of_core)] fn std_instead_of_core() { // Regular import @@ -55,6 +59,13 @@ fn alloc_instead_of_core() { //~^ ERROR: used import from `alloc` instead of `core` } +mod std_in_proc_macro_derive { + #[warn(clippy::alloc_instead_of_core)] + #[allow(unused)] + #[derive(ImplStructWithStdDisplay)] + struct B {} +} + fn main() { std_instead_of_core(); std_instead_of_alloc(); diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index ca26f77bd37f..4f7bdc4045e7 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -1,5 +1,5 @@ error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:9:9 + --> $DIR/std_instead_of_core.rs:13:9 | LL | use std::hash::Hasher; | ^^^ help: consider importing the item from `core`: `core` @@ -8,49 +8,49 @@ LL | use std::hash::Hasher; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:12:11 + --> $DIR/std_instead_of_core.rs:16:11 | LL | use ::std::hash::Hash; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:18:9 + --> $DIR/std_instead_of_core.rs:22:9 | LL | use std::fmt::{Debug, Result}; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:22:15 + --> $DIR/std_instead_of_core.rs:26:15 | LL | let ptr = std::ptr::null::(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:24:21 + --> $DIR/std_instead_of_core.rs:28:21 | LL | let ptr_mut = ::std::ptr::null_mut::(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:28:16 + --> $DIR/std_instead_of_core.rs:32:16 | LL | let cell = std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:30:27 + --> $DIR/std_instead_of_core.rs:34:27 | LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:39:9 + --> $DIR/std_instead_of_core.rs:43:9 | LL | use std::iter::Iterator; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:46:9 + --> $DIR/std_instead_of_core.rs:50:9 | LL | use std::vec; | ^^^ help: consider importing the item from `alloc`: `alloc` @@ -59,13 +59,13 @@ LL | use std::vec; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:48:9 + --> $DIR/std_instead_of_core.rs:52:9 | LL | use std::vec::Vec; | ^^^ help: consider importing the item from `alloc`: `alloc` error: used import from `alloc` instead of `core` - --> $DIR/std_instead_of_core.rs:54:9 + --> $DIR/std_instead_of_core.rs:58:9 | LL | use alloc::slice::from_ref; | ^^^^^ help: consider importing the item from `core`: `core` diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 2828f9d048ef..6fdd728b9b72 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -69,6 +69,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use self::exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use self::exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index cbe70e505d8c..20e06d4b3664 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -69,6 +69,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use self::exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use self::exports_underscore_ish::*; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 3c750815bafc..01a5414778c1 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:97:13 + --> $DIR/wildcard_imports.rs:94:13 + | +LL | use self::exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `self::exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports.rs:125:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:103:75 + --> $DIR/wildcard_imports.rs:131:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:104:13 + --> $DIR/wildcard_imports.rs:132:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:20 + --> $DIR/wildcard_imports.rs:144:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:30 + --> $DIR/wildcard_imports.rs:144:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:123:13 + --> $DIR/wildcard_imports.rs:151:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:152:9 + --> $DIR/wildcard_imports.rs:180:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:161:9 + --> $DIR/wildcard_imports.rs:189:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:162:9 + --> $DIR/wildcard_imports.rs:190:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:173:13 + --> $DIR/wildcard_imports.rs:201:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:208:17 + --> $DIR/wildcard_imports.rs:236:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:216:13 + --> $DIR/wildcard_imports.rs:244:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:225:17 + --> $DIR/wildcard_imports.rs:253:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:234:13 + --> $DIR/wildcard_imports.rs:262:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:242:13 + --> $DIR/wildcard_imports.rs:270:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index b27281fa25c5..6a9fe007d654 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr index 709a665d65c2..e39f240a4aa2 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:91:13 + --> $DIR/wildcard_imports_2021.rs:89:13 + | +LL | use exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:119:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:97:75 + --> $DIR/wildcard_imports_2021.rs:125:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:98:13 + --> $DIR/wildcard_imports_2021.rs:126:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:20 + --> $DIR/wildcard_imports_2021.rs:138:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:30 + --> $DIR/wildcard_imports_2021.rs:138:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:117:13 + --> $DIR/wildcard_imports_2021.rs:145:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:146:9 + --> $DIR/wildcard_imports_2021.rs:174:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:183:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:156:9 + --> $DIR/wildcard_imports_2021.rs:184:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:167:13 + --> $DIR/wildcard_imports_2021.rs:195:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:202:17 + --> $DIR/wildcard_imports_2021.rs:230:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:210:13 + --> $DIR/wildcard_imports_2021.rs:238:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:219:17 + --> $DIR/wildcard_imports_2021.rs:247:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:228:13 + --> $DIR/wildcard_imports_2021.rs:256:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:236:13 + --> $DIR/wildcard_imports_2021.rs:264:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index b27281fa25c5..6a9fe007d654 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr index 709a665d65c2..e39f240a4aa2 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:91:13 + --> $DIR/wildcard_imports_2021.rs:89:13 + | +LL | use exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:119:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:97:75 + --> $DIR/wildcard_imports_2021.rs:125:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:98:13 + --> $DIR/wildcard_imports_2021.rs:126:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:20 + --> $DIR/wildcard_imports_2021.rs:138:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:30 + --> $DIR/wildcard_imports_2021.rs:138:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:117:13 + --> $DIR/wildcard_imports_2021.rs:145:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:146:9 + --> $DIR/wildcard_imports_2021.rs:174:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:183:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:156:9 + --> $DIR/wildcard_imports_2021.rs:184:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:167:13 + --> $DIR/wildcard_imports_2021.rs:195:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:202:17 + --> $DIR/wildcard_imports_2021.rs:230:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:210:13 + --> $DIR/wildcard_imports_2021.rs:238:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:219:17 + --> $DIR/wildcard_imports_2021.rs:247:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:228:13 + --> $DIR/wildcard_imports_2021.rs:256:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:236:13 + --> $DIR/wildcard_imports_2021.rs:264:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index 7dd2103eca7e..18ebc0f51274 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::*; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/write_literal.fixed b/tests/ui/write_literal.fixed index ee577574d289..3d216b76cbf3 100644 --- a/tests/ui/write_literal.fixed +++ b/tests/ui/write_literal.fixed @@ -43,16 +43,22 @@ fn main() { // throw a warning writeln!(v, "hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either writeln!(v, "hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string + + // #10128 + writeln!(v, "hello {0} world", 2); + //~^ ERROR: literal with an empty format string + writeln!(v, "world {0} hello", 2); + //~^ ERROR: literal with an empty format string + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4); + //~^ ERROR: literal with an empty format string + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4); + //~^ ERROR: literal with an empty format string } diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 588e8fd413a4..79d6daa2e3b5 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -43,16 +43,22 @@ fn main() { // throw a warning writeln!(v, "{0} {1}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "{1} {0}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string + + // #10128 + writeln!(v, "{0} {1} {2}", "hello", 2, "world"); + //~^ ERROR: literal with an empty format string + writeln!(v, "{2} {1} {0}", "hello", 2, "world"); + //~^ ERROR: literal with an empty format string + writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); + //~^ ERROR: literal with an empty format string + writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); + //~^ ERROR: literal with an empty format string } diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 372a54cf769f..ee0d536e954f 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -52,96 +52,96 @@ error: literal with an empty format string --> $DIR/write_literal.rs:44:28 | LL | writeln!(v, "{0} {1}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: try | LL - writeln!(v, "{0} {1}", "hello", "world"); -LL + writeln!(v, "hello {1}", "world"); +LL + writeln!(v, "hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:44:37 - | -LL | writeln!(v, "{0} {1}", "hello", "world"); - | ^^^^^^^ - | -help: try - | -LL - writeln!(v, "{0} {1}", "hello", "world"); -LL + writeln!(v, "{0} world", "hello"); - | - -error: literal with an empty format string - --> $DIR/write_literal.rs:47:37 + --> $DIR/write_literal.rs:46:28 | LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: try | LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "world {0}", "hello"); +LL + writeln!(v, "world hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:47:28 + --> $DIR/write_literal.rs:50:38 | -LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "{1} hello", "world"); +LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); +LL + writeln!(v, "hello world"); | error: literal with an empty format string --> $DIR/write_literal.rs:52:38 | -LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ - | -help: try - | -LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); -LL + writeln!(v, "hello {bar}", bar = "world"); - | - -error: literal with an empty format string - --> $DIR/write_literal.rs:52:53 - | -LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ - | -help: try - | -LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); -LL + writeln!(v, "{foo} world", foo = "hello"); - | - -error: literal with an empty format string - --> $DIR/write_literal.rs:55:53 - | LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "world {foo}", foo = "hello"); +LL + writeln!(v, "world hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:55:38 + --> $DIR/write_literal.rs:56:32 | -LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | writeln!(v, "{0} {1} {2}", "hello", 2, "world"); + | ^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "{bar} hello", bar = "world"); +LL - writeln!(v, "{0} {1} {2}", "hello", 2, "world"); +LL + writeln!(v, "hello {0} world", 2); + | + +error: literal with an empty format string + --> $DIR/write_literal.rs:58:32 + | +LL | writeln!(v, "{2} {1} {0}", "hello", 2, "world"); + | ^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - writeln!(v, "{2} {1} {0}", "hello", 2, "world"); +LL + writeln!(v, "world {0} hello", 2); + | + +error: literal with an empty format string + --> $DIR/write_literal.rs:60:39 + | +LL | writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); + | ^^^^^^^ + | +help: try + | +LL - writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); +LL + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4); + | + +error: literal with an empty format string + --> $DIR/write_literal.rs:62:41 + | +LL | writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); +LL + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4); | error: aborting due to 12 previous errors diff --git a/tests/ui/write_literal_2.rs b/tests/ui/write_literal_2.rs index aa0c13c13408..b2ed552d46bc 100644 --- a/tests/ui/write_literal_2.rs +++ b/tests/ui/write_literal_2.rs @@ -1,6 +1,6 @@ //@no-rustfix: overlapping suggestions #![allow(unused_must_use)] -#![warn(clippy::needless_raw_strings, clippy::write_literal)] +#![warn(clippy::write_literal)] use std::io::Write; @@ -11,9 +11,7 @@ fn main() { //~^ ERROR: literal with an empty format string //~| NOTE: `-D clippy::write-literal` implied by `-D warnings` writeln!(v, r"{}", r"{hello}"); - //~^ ERROR: unnecessary raw string literal - //~| NOTE: `-D clippy::needless-raw-strings` implied by `-D warnings` - //~| ERROR: literal with an empty format string + //~^ ERROR: literal with an empty format string writeln!(v, "{}", '\''); //~^ ERROR: literal with an empty format string writeln!(v, "{}", '"'); @@ -26,17 +24,14 @@ fn main() { v, "some {}", "hello \ - //~^ ERROR: literal with an empty format string - world!" + world!", + //~^^ ERROR: literal with an empty format string ); writeln!( v, "some {}\ {} \\ {}", - "1", - "2", - "3", - //~^ ERROR: literal with an empty format string + "1", "2", "3", ); writeln!(v, "{}", "\\"); //~^ ERROR: literal with an empty format string @@ -51,7 +46,6 @@ fn main() { // hard mode writeln!(v, r#"{}{}"#, '#', '"'); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // should not lint writeln!(v, r"{}", "\r"); } diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index 6d382a267ad8..81ef49de082e 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -1,14 +1,3 @@ -error: unnecessary raw string literal - --> $DIR/write_literal_2.rs:13:24 - | -LL | writeln!(v, r"{}", r"{hello}"); - | -^^^^^^^^^ - | | - | help: use a string literal instead: `"{hello}"` - | - = note: `-D clippy::needless-raw-strings` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]` - error: literal with an empty format string --> $DIR/write_literal_2.rs:10:23 | @@ -36,7 +25,7 @@ LL + writeln!(v, r"{{hello}}"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:17:23 + --> $DIR/write_literal_2.rs:15:23 | LL | writeln!(v, "{}", '\''); | ^^^^ @@ -48,7 +37,7 @@ LL + writeln!(v, "'"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:19:23 + --> $DIR/write_literal_2.rs:17:23 | LL | writeln!(v, "{}", '"'); | ^^^ @@ -60,13 +49,13 @@ LL + writeln!(v, "\""); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:21:24 + --> $DIR/write_literal_2.rs:19:24 | LL | writeln!(v, r"{}", '"'); | ^^^ error: literal with an empty format string - --> $DIR/write_literal_2.rs:23:24 + --> $DIR/write_literal_2.rs:21:24 | LL | writeln!(v, r"{}", '\''); | ^^^^ @@ -78,59 +67,32 @@ LL + writeln!(v, r"'"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:28:9 + --> $DIR/write_literal_2.rs:26:9 | LL | / "hello \ -LL | | -LL | | world!" +LL | | world!", | |_______________^ | help: try | LL ~ "some hello \ -LL + -LL ~ world!" +LL ~ world!", | error: literal with an empty format string - --> $DIR/write_literal_2.rs:36:9 + --> $DIR/write_literal_2.rs:34:9 | -LL | "1", - | ^^^ +LL | "1", "2", "3", + | ^^^^^^^^^^^^^ | help: try | LL ~ "some 1\ -LL ~ {} \\ {}", +LL ~ 2 \\ 3", | error: literal with an empty format string - --> $DIR/write_literal_2.rs:37:9 - | -LL | "2", - | ^^^ - | -help: try - | -LL ~ 2 \\ {}", -LL ~ "1", - | - -error: literal with an empty format string - --> $DIR/write_literal_2.rs:38:9 - | -LL | "3", - | ^^^ - | -help: try - | -LL ~ {} \\ 3", -LL | "1", -LL ~ "2", - | - -error: literal with an empty format string - --> $DIR/write_literal_2.rs:41:23 + --> $DIR/write_literal_2.rs:36:23 | LL | writeln!(v, "{}", "\\"); | ^^^^ @@ -142,7 +104,7 @@ LL + writeln!(v, "\\"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:43:24 + --> $DIR/write_literal_2.rs:38:24 | LL | writeln!(v, r"{}", "\\"); | ^^^^ @@ -154,7 +116,7 @@ LL + writeln!(v, r"\"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:45:26 + --> $DIR/write_literal_2.rs:40:26 | LL | writeln!(v, r#"{}"#, "\\"); | ^^^^ @@ -166,7 +128,7 @@ LL + writeln!(v, r#"\"#); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:47:23 + --> $DIR/write_literal_2.rs:42:23 | LL | writeln!(v, "{}", r"\"); | ^^^^ @@ -178,7 +140,7 @@ LL + writeln!(v, "\\"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:49:23 + --> $DIR/write_literal_2.rs:44:23 | LL | writeln!(v, "{}", "\r"); | ^^^^ @@ -190,16 +152,10 @@ LL + writeln!(v, "\r"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:52:28 + --> $DIR/write_literal_2.rs:47:28 | LL | writeln!(v, r#"{}{}"#, '#', '"'); - | ^^^ + | ^^^^^^^^ -error: literal with an empty format string - --> $DIR/write_literal_2.rs:52:33 - | -LL | writeln!(v, r#"{}{}"#, '#', '"'); - | ^^^ - -error: aborting due to 18 previous errors +error: aborting due to 14 previous errors From 68d2082d69d61af56d0b9d73035b274ea0e2e8de Mon Sep 17 00:00:00 2001 From: koka Date: Fri, 6 Oct 2023 18:22:32 +0900 Subject: [PATCH 010/107] Fix ice --- clippy_lints/src/redundant_locals.rs | 2 +- tests/ui/redundant_locals.rs | 8 ++++++++ tests/ui/redundant_locals.stderr | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 197742b5dd41..a1a0e8f35208 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id); if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id); // the previous binding has the same mutability - if find_binding(binding_pat, ident).unwrap().1 == mutability; + if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability); // the local does not change the effect of assignments to the binding. see #11290 if !affects_assignments(cx, mutability, binding_id, local.hir_id); // the local does not affect the code's drop behavior diff --git a/tests/ui/redundant_locals.rs b/tests/ui/redundant_locals.rs index e81db300f15a..182d067a5e9f 100644 --- a/tests/ui/redundant_locals.rs +++ b/tests/ui/redundant_locals.rs @@ -117,6 +117,14 @@ fn macros() { let x = 1; let x = x; } + + let x = 10; + macro_rules! rebind_outer_macro { + ($x:ident) => { + let x = x; + }; + } + rebind_outer_macro!(y); } struct WithDrop(usize); diff --git a/tests/ui/redundant_locals.stderr b/tests/ui/redundant_locals.stderr index d794a87fe7df..30ab4aa2ea91 100644 --- a/tests/ui/redundant_locals.stderr +++ b/tests/ui/redundant_locals.stderr @@ -157,13 +157,13 @@ LL | let x = 1; | ^ error: redundant redefinition of a binding `a` - --> $DIR/redundant_locals.rs:144:5 + --> $DIR/redundant_locals.rs:152:5 | LL | let a = a; | ^^^^^^^^^^ | help: `a` is initially defined here - --> $DIR/redundant_locals.rs:142:9 + --> $DIR/redundant_locals.rs:150:9 | LL | let a = WithoutDrop(1); | ^ From bffba76b52dfe96f42fb153c02824237968a15c8 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 7 Oct 2023 10:54:45 +0200 Subject: [PATCH 011/107] Fix two typos in lint description --- clippy_lints/src/iter_without_into_iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 43e1b92c9b9a..abfc50369b5b 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -56,8 +56,8 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains - /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax - /// in case of ambiguity with another `Intoiterator` impl. + /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax + /// in case of ambiguity with another `IntoIterator` impl. /// /// ### Example /// ```rust From 1c6fa2989d056de1183e5df1e1d778e925a6a6fe Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 7 Oct 2023 16:33:06 +0200 Subject: [PATCH 012/107] [`into_iter_without_iter`]: look for `iter` method in deref chains --- clippy_lints/src/iter_without_into_iter.rs | 25 ++++++++++++++-- tests/ui/into_iter_without_iter.rs | 34 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 43e1b92c9b9a..ee3d1735043d 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Symbol}; +use std::iter; declare_clippy_lint! { /// ### What it does @@ -52,7 +53,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// This is the opposite of the `iter_without_into_iter` lint. - /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method. + /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method + /// on the type or on any of the types in its `Deref` chain. /// /// ### Why is this bad? /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains @@ -102,7 +104,20 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool { !matches!(ty.kind, TyKind::OpaqueDef(..)) } -fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { +/// Returns the deref chain of a type, starting with the type itself. +fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator> + 'cx { + iter::successors(Some(ty), |&ty| { + if let Some(deref_did) = cx.tcx.lang_items().deref_trait() + && implements_trait(cx, ty, deref_did, &[]) + { + make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) + } else { + None + } + }) +} + +fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { cx.tcx.inherent_impls(ty_did).iter().any(|&did| { cx.tcx @@ -127,7 +142,11 @@ impl LateLintPass<'_> for IterWithoutIntoIter { Mutability::Mut => sym::iter_mut, Mutability::Not => sym::iter, } - && !type_has_inherent_method(cx, ty, expected_method_name) + && !deref_chain(cx, ty) + .any(|ty| { + // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method + ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) + }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { if item.ident.name == sym!(IntoIter) { Some(cx.tcx.hir().impl_item(item.id).expect_type().span) diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs index 6be3bb8abddd..e6ff821a8ad0 100644 --- a/tests/ui/into_iter_without_iter.rs +++ b/tests/ui/into_iter_without_iter.rs @@ -122,3 +122,37 @@ fn main() { } } } + +fn issue11635() { + // A little more involved than the original repro in the issue, but this tests that it correctly + // works for more than one deref step + + use std::ops::Deref; + + pub struct Thing(Vec); + pub struct Thing2(Thing); + + impl Deref for Thing { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl Deref for Thing2 { + type Target = Thing; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl<'a> IntoIterator for &'a Thing2 { + type Item = &'a u8; + type IntoIter = <&'a [u8] as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } + } +} From 850f2f5b61c62c72cb3c29196d93e896cf7edd48 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 8 Oct 2023 19:35:41 +0100 Subject: [PATCH 013/107] Update ui_test to 0.21.2 --- Cargo.toml | 2 +- tests/compile-test.rs | 88 +++++++------------------------------------ 2 files changed, 15 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cbcb42dad79b..2c50addfd7df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ color-print = "0.3.4" # Sync version with Cargo anstream = "0.5.0" [dev-dependencies] -ui_test = "0.20" +ui_test = "0.21.2" tester = "0.9" regex = "1.5" toml = "0.7.3" diff --git a/tests/compile-test.rs b/tests/compile-test.rs index f340cf5938a7..1494c7d31796 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -105,27 +105,20 @@ static EXTERN_FLAGS: LazyLock> = LazyLock::new(|| { // whether to run internal tests or not const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); -fn canonicalize(path: impl AsRef) -> PathBuf { - let path = path.as_ref(); - fs::create_dir_all(path).unwrap(); - fs::canonicalize(path).unwrap_or_else(|err| panic!("{} cannot be canonicalized: {err}", path.display())) -} - fn base_config(test_dir: &str) -> (Config, Args) { let mut args = Args::test().unwrap(); args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); + let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())); let mut config = Config { mode: Mode::Yolo { rustfix: ui_test::RustfixMode::Everything, }, - stderr_filters: vec![(Match::PathBackslash, b"/")], - stdout_filters: vec![], filter_files: env::var("TESTNAME") .map(|filters| filters.split(',').map(str::to_string).collect()) .unwrap_or_default(), target: None, - out_dir: canonicalize(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())).join("ui_test"), + out_dir: target_dir.join("ui_test"), ..Config::rustc(Path::new("tests").join(test_dir)) }; config.with_args(&args, /* bless by default */ false); @@ -168,19 +161,13 @@ fn run_ui() { config .program .envs - .push(("CLIPPY_CONF_DIR".into(), Some(canonicalize("tests").into()))); - - let quiet = args.quiet; + .push(("CLIPPY_CONF_DIR".into(), Some("tests".into()))); ui_test::run_tests_generic( vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - if quiet { - status_emitter::Text::quiet() - } else { - status_emitter::Text::verbose() - }, + status_emitter::Text::from(args.format), ) .unwrap(); } @@ -194,17 +181,12 @@ fn run_internal_tests() { if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling { *err = "cargo uitest --features internal -- -- --bless".into(); } - let quiet = args.quiet; ui_test::run_tests_generic( vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - if quiet { - status_emitter::Text::quiet() - } else { - status_emitter::Text::verbose() - }, + status_emitter::Text::from(args.format), ) .unwrap(); } @@ -212,22 +194,9 @@ fn run_internal_tests() { fn run_ui_toml() { let (mut config, args) = base_config("ui-toml"); - config.stderr_filters = vec![ - ( - Match::Exact( - canonicalize("tests") - .parent() - .unwrap() - .to_string_lossy() - .as_bytes() - .to_vec(), - ), - b"$DIR", - ), - (Match::Exact(b"\\".to_vec()), b"/"), - ]; - - let quiet = args.quiet; + config + .stderr_filters + .push((Match::from(env::current_dir().unwrap().as_path()), b"$DIR")); ui_test::run_tests_generic( vec![config], @@ -238,11 +207,7 @@ fn run_ui_toml() { .envs .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into()))); }, - if quiet { - status_emitter::Text::quiet() - } else { - status_emitter::Text::verbose() - }, + status_emitter::Text::from(args.format), ) .unwrap(); } @@ -270,22 +235,9 @@ fn run_ui_cargo() { }); config.edition = None; - config.stderr_filters = vec![ - ( - Match::Exact( - canonicalize("tests") - .parent() - .unwrap() - .to_string_lossy() - .as_bytes() - .to_vec(), - ), - b"$DIR", - ), - (Match::Exact(b"\\".to_vec()), b"/"), - ]; - - let quiet = args.quiet; + config + .stderr_filters + .push((Match::from(env::current_dir().unwrap().as_path()), b"$DIR")); let ignored_32bit = |path: &Path| { // FIXME: for some reason the modules are linted in a different order for this test @@ -297,20 +249,8 @@ fn run_ui_cargo() { |path, config| { path.ends_with("Cargo.toml") && ui_test::default_any_file_filter(path, config) && !ignored_32bit(path) }, - |config, path, _file_contents| { - config.out_dir = canonicalize( - std::env::current_dir() - .unwrap() - .join("target") - .join("ui_test_cargo/") - .join(path.parent().unwrap()), - ); - }, - if quiet { - status_emitter::Text::quiet() - } else { - status_emitter::Text::verbose() - }, + |_config, _path, _file_contents| {}, + status_emitter::Text::from(args.format), ) .unwrap(); } From 5ed338dff9ab543460e83c9fbe462373c0b99a82 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 21 Sep 2023 22:37:32 +0200 Subject: [PATCH 014/107] `impl_trait_in_params` now supports impls and traits --- .../src/functions/impl_trait_in_params.rs | 120 +++++++++++++----- clippy_lints/src/functions/mod.rs | 11 +- clippy_lints/src/lib.rs | 1 + .../impl_trait_in_params/true/clippy.toml | 1 + .../true/impl_trait_in_params.rs | 10 ++ tests/ui/impl_trait_in_params.rs | 29 ++++- tests/ui/impl_trait_in_params.stderr | 30 ++++- 7 files changed, 158 insertions(+), 44 deletions(-) create mode 100644 tests/ui-toml/impl_trait_in_params/true/clippy.toml create mode 100644 tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index 597fca888851..4a776dd26133 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,50 +1,100 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test_function; +use rustc_hir as hir; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, HirId}; +use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind}; use rustc_lint::LateContext; +use rustc_span::symbol::Ident; use rustc_span::Span; use super::IMPL_TRAIT_IN_PARAMS; +fn report( + cx: &LateContext<'_>, + param: &GenericParam<'_>, + ident: &Ident, + generics: &Generics<'_>, + first_param_span: Span, +) { + // No generics with nested generics, and no generics like FnMut(x) + span_lint_and_then( + cx, + IMPL_TRAIT_IN_PARAMS, + param.span, + "`impl Trait` used as a function parameter", + |diag| { + if let Some(gen_span) = generics.span_for_param_suggestion() { + // If there's already a generic param with the same bound, do not lint **this** suggestion. + diag.span_suggestion_with_style( + gen_span, + "add a type parameter", + format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), + rustc_errors::Applicability::HasPlaceholders, + rustc_errors::SuggestionStyle::ShowAlways, + ); + } else { + diag.span_suggestion_with_style( + Span::new( + first_param_span.lo() - rustc_span::BytePos(1), + ident.span.hi(), + ident.span.ctxt(), + ident.span.parent(), + ), + "add a type parameter", + format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), + rustc_errors::Applicability::HasPlaceholders, + rustc_errors::SuggestionStyle::ShowAlways, + ); + } + }, + ); +} + pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { - if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id) - { - if let FnKind::ItemFn(ident, generics, _) = kind { + if_chain! { + if let FnKind::ItemFn(ident, generics, _) = kind; + if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public(); + if !is_in_test_function(cx.tcx, hir_id); + then { for param in generics.params { if param.is_impl_trait() { - // No generics with nested generics, and no generics like FnMut(x) - span_lint_and_then( - cx, - IMPL_TRAIT_IN_PARAMS, - param.span, - "'`impl Trait` used as a function parameter'", - |diag| { - if let Some(gen_span) = generics.span_for_param_suggestion() { - diag.span_suggestion_with_style( - gen_span, - "add a type parameter", - format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, - ); - } else { - diag.span_suggestion_with_style( - Span::new( - body.params[0].span.lo() - rustc_span::BytePos(1), - ident.span.hi(), - ident.span.ctxt(), - ident.span.parent(), - ), - "add a type parameter", - format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, - ); - } - }, - ); + report(cx, param, ident, generics, body.params[0].span); + }; + } + } + } +} + +pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + if_chain! { + if let ImplItemKind::Fn(_, body_id) = impl_item.kind; + if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id()); + if let hir::ItemKind::Impl(impl_) = item.kind; + if let hir::Impl { of_trait, .. } = *impl_; + if of_trait.is_none(); + let body = cx.tcx.hir().body(body_id); + if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public(); + if !is_in_test_function(cx.tcx, impl_item.hir_id()); + then { + for param in impl_item.generics.params { + if param.is_impl_trait() { + report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span); + } + } + } + } +} + +pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) { + if_chain! { + if !avoid_breaking_exported_api; + if let TraitItemKind::Fn(sig, _) = trait_item.kind; + if !is_in_test_function(cx.tcx, trait_item.hir_id()); + then { + for param in trait_item.generics.params { + if param.is_impl_trait() { + report(cx, param, &trait_item.ident, trait_item.generics, sig.decl.inputs[0].span); } } } diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index ee10334c67f1..55ebd44a60c2 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -364,14 +364,21 @@ pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64, + avoid_breaking_exported_api: bool, } impl Functions { - pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self { + pub fn new( + too_many_arguments_threshold: u64, + too_many_lines_threshold: u64, + large_error_threshold: u64, + avoid_breaking_exported_api: bool, + ) -> Self { Self { too_many_arguments_threshold, too_many_lines_threshold, large_error_threshold, + avoid_breaking_exported_api, } } } @@ -415,6 +422,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); result::check_impl_item(cx, item, self.large_error_threshold); + impl_trait_in_params::check_impl_item(cx, item); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { @@ -422,5 +430,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions { not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); result::check_trait_item(cx, item, self.large_error_threshold); + impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fa009c8b2d6c..8a4c2fc2c43d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -758,6 +758,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: too_many_arguments_threshold, too_many_lines_threshold, large_error_threshold, + avoid_breaking_exported_api, )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); diff --git a/tests/ui-toml/impl_trait_in_params/true/clippy.toml b/tests/ui-toml/impl_trait_in_params/true/clippy.toml new file mode 100644 index 000000000000..0e7ffd070a35 --- /dev/null +++ b/tests/ui-toml/impl_trait_in_params/true/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = true \ No newline at end of file diff --git a/tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs b/tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs new file mode 100644 index 000000000000..d1176ab89635 --- /dev/null +++ b/tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs @@ -0,0 +1,10 @@ +//! As avoid-breaking-exported-api is `true`, nothing here should lint +#![warn(clippy::impl_trait_in_params)] +#![no_main] + +trait Trait {} + +trait T { + fn t(_: impl Trait); + fn tt(_: T); +} diff --git a/tests/ui/impl_trait_in_params.rs b/tests/ui/impl_trait_in_params.rs index b652e4a4abe2..825bb76e3f78 100644 --- a/tests/ui/impl_trait_in_params.rs +++ b/tests/ui/impl_trait_in_params.rs @@ -1,20 +1,41 @@ #![allow(unused)] #![warn(clippy::impl_trait_in_params)] + //@no-rustfix pub trait Trait {} pub trait AnotherTrait {} // Should warn pub fn a(_: impl Trait) {} -//~^ ERROR: '`impl Trait` used as a function parameter' -//~| NOTE: `-D clippy::impl-trait-in-params` implied by `-D warnings` +//~^ ERROR: `impl Trait` used as a function parameter pub fn c(_: C, _: impl Trait) {} -//~^ ERROR: '`impl Trait` used as a function parameter' -fn d(_: impl AnotherTrait) {} +//~^ ERROR: `impl Trait` used as a function parameter // Shouldn't warn pub fn b(_: B) {} fn e>(_: T) {} +fn d(_: impl AnotherTrait) {} + +//------ IMPLS + +trait T { + // See test in ui-toml for a case where avoid-breaking-exported-api is set to true + fn t(_: impl Trait); + fn tt(_: T) {} +} + +struct S; +impl S { + pub fn h(_: impl Trait) {} //~ ERROR: `impl Trait` used as a function parameter + fn i(_: impl Trait) {} + pub fn j(_: J) {} + pub fn k>(_: K, _: impl AnotherTrait) {} //~ ERROR: `impl Trait` used as a function parameter +} + +// Trying with traits +impl T for S { + fn t(_: impl Trait) {} +} fn main() {} diff --git a/tests/ui/impl_trait_in_params.stderr b/tests/ui/impl_trait_in_params.stderr index 36b4f27e9a45..9f6e545c3f28 100644 --- a/tests/ui/impl_trait_in_params.stderr +++ b/tests/ui/impl_trait_in_params.stderr @@ -1,5 +1,5 @@ -error: '`impl Trait` used as a function parameter' - --> $DIR/impl_trait_in_params.rs:8:13 +error: `impl Trait` used as a function parameter + --> $DIR/impl_trait_in_params.rs:9:13 | LL | pub fn a(_: impl Trait) {} | ^^^^^^^^^^ @@ -11,7 +11,7 @@ help: add a type parameter LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {} | +++++++++++++++++++++++++++++++ -error: '`impl Trait` used as a function parameter' +error: `impl Trait` used as a function parameter --> $DIR/impl_trait_in_params.rs:11:29 | LL | pub fn c(_: C, _: impl Trait) {} @@ -22,5 +22,27 @@ help: add a type parameter LL | pub fn c(_: C, _: impl Trait) {} | +++++++++++++++++++++++++++++++ -error: aborting due to 2 previous errors +error: `impl Trait` used as a function parameter + --> $DIR/impl_trait_in_params.rs:30:17 + | +LL | pub fn h(_: impl Trait) {} + | ^^^^^^^^^^ + | +help: add a type parameter + | +LL | pub fn h<{ /* Generic name */ }: Trait>(_: impl Trait) {} + | +++++++++++++++++++++++++++++++ + +error: `impl Trait` used as a function parameter + --> $DIR/impl_trait_in_params.rs:33:45 + | +LL | pub fn k>(_: K, _: impl AnotherTrait) {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a type parameter + | +LL | pub fn k, { /* Generic name */ }: AnotherTrait>(_: K, _: impl AnotherTrait) {} + | +++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 4 previous errors From 775573768ed4bef5e0ebbfe7aa782a615eff2c51 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sat, 23 Sep 2023 20:36:06 +0200 Subject: [PATCH 015/107] Fix tests, only lint for public tests --- .../src/functions/impl_trait_in_params.rs | 10 +++++++--- tests/ui-toml/impl_trait_in_params/clippy.toml | 1 + .../impl_trait_in_params/impl_trait_in_params.rs | 16 ++++++++++++++++ .../impl_trait_in_params.stderr | 15 +++++++++++++++ .../impl_trait_in_params/true/clippy.toml | 1 - .../true/impl_trait_in_params.rs | 10 ---------- tests/ui/impl_trait_in_params.rs | 12 +++++++++--- tests/ui/impl_trait_in_params.stderr | 4 ++-- 8 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 tests/ui-toml/impl_trait_in_params/clippy.toml create mode 100644 tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs create mode 100644 tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr delete mode 100644 tests/ui-toml/impl_trait_in_params/true/clippy.toml delete mode 100644 tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index 4a776dd26133..ee66c841ed25 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use super::IMPL_TRAIT_IN_PARAMS; @@ -89,12 +89,16 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) { if_chain! { if !avoid_breaking_exported_api; - if let TraitItemKind::Fn(sig, _) = trait_item.kind; + if let TraitItemKind::Fn(_, _) = trait_item.kind; + if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id()); + // ^^ (Will always be a trait) + if !item.vis_span.is_empty(); // Is public if !is_in_test_function(cx.tcx, trait_item.hir_id()); then { for param in trait_item.generics.params { if param.is_impl_trait() { - report(cx, param, &trait_item.ident, trait_item.generics, sig.decl.inputs[0].span); + let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1)); + report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi()); } } } diff --git a/tests/ui-toml/impl_trait_in_params/clippy.toml b/tests/ui-toml/impl_trait_in_params/clippy.toml new file mode 100644 index 000000000000..87e1f235741d --- /dev/null +++ b/tests/ui-toml/impl_trait_in_params/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false \ No newline at end of file diff --git a/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs b/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs new file mode 100644 index 000000000000..08fc7edf1c86 --- /dev/null +++ b/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs @@ -0,0 +1,16 @@ +//! As avoid-breaking-exported-api is `false`, nothing here should lint +#![warn(clippy::impl_trait_in_params)] +#![no_main] +//@no-rustfix + +pub trait Trait {} + +trait Private { + fn t(_: impl Trait); + fn tt(_: T); +} + +pub trait Public { + fn t(_: impl Trait); //~ ERROR: `impl Trait` used as a function parameter + fn tt(_: T); +} diff --git a/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr b/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr new file mode 100644 index 000000000000..80c4f5ed4b0c --- /dev/null +++ b/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr @@ -0,0 +1,15 @@ +error: `impl Trait` used as a function parameter + --> $DIR/impl_trait_in_params.rs:14:13 + | +LL | fn t(_: impl Trait); + | ^^^^^^^^^^ + | + = note: `-D clippy::impl-trait-in-params` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::impl_trait_in_params)]` +help: add a type parameter + | +LL | fn t<{ /* Generic name */ }: Trait>(_: impl Trait); + | +++++++++++++++++++++++++++++++ + +error: aborting due to previous error + diff --git a/tests/ui-toml/impl_trait_in_params/true/clippy.toml b/tests/ui-toml/impl_trait_in_params/true/clippy.toml deleted file mode 100644 index 0e7ffd070a35..000000000000 --- a/tests/ui-toml/impl_trait_in_params/true/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -avoid-breaking-exported-api = true \ No newline at end of file diff --git a/tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs b/tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs deleted file mode 100644 index d1176ab89635..000000000000 --- a/tests/ui-toml/impl_trait_in_params/true/impl_trait_in_params.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! As avoid-breaking-exported-api is `true`, nothing here should lint -#![warn(clippy::impl_trait_in_params)] -#![no_main] - -trait Trait {} - -trait T { - fn t(_: impl Trait); - fn tt(_: T); -} diff --git a/tests/ui/impl_trait_in_params.rs b/tests/ui/impl_trait_in_params.rs index 825bb76e3f78..a6251a370d1d 100644 --- a/tests/ui/impl_trait_in_params.rs +++ b/tests/ui/impl_trait_in_params.rs @@ -19,8 +19,14 @@ fn d(_: impl AnotherTrait) {} //------ IMPLS -trait T { - // See test in ui-toml for a case where avoid-breaking-exported-api is set to true +pub trait Public { + // See test in ui-toml for a case where avoid-breaking-exported-api is set to false + fn t(_: impl Trait); + fn tt(_: T) {} +} + +trait Private { + // This shouldn't lint fn t(_: impl Trait); fn tt(_: T) {} } @@ -34,7 +40,7 @@ impl S { } // Trying with traits -impl T for S { +impl Public for S { fn t(_: impl Trait) {} } diff --git a/tests/ui/impl_trait_in_params.stderr b/tests/ui/impl_trait_in_params.stderr index 9f6e545c3f28..0ae7a3672d19 100644 --- a/tests/ui/impl_trait_in_params.stderr +++ b/tests/ui/impl_trait_in_params.stderr @@ -23,7 +23,7 @@ LL | pub fn c(_: C, _: impl Trait) {} | +++++++++++++++++++++++++++++++ error: `impl Trait` used as a function parameter - --> $DIR/impl_trait_in_params.rs:30:17 + --> $DIR/impl_trait_in_params.rs:36:17 | LL | pub fn h(_: impl Trait) {} | ^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | pub fn h<{ /* Generic name */ }: Trait>(_: impl Trait) {} | +++++++++++++++++++++++++++++++ error: `impl Trait` used as a function parameter - --> $DIR/impl_trait_in_params.rs:33:45 + --> $DIR/impl_trait_in_params.rs:39:45 | LL | pub fn k>(_: K, _: impl AnotherTrait) {} | ^^^^^^^^^^^^^^^^^^^^^^ From 5d85a24442bb478745876b73ebbada623c1b629e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:52:46 +0000 Subject: [PATCH 016/107] Merge commit '81dc066758ec150b43822d4a0c84aae20fe10f40' into sync_cg_clif-2023-10-09 --- Cargo.lock | 166 +++-- Cargo.toml | 16 +- Readme.md | 14 +- build_system/build_backend.rs | 2 + build_system/prepare.rs | 6 +- build_system/tests.rs | 67 +- build_system/utils.rs | 35 +- config.txt | 1 - example/mini_core.rs | 6 + ...ortable-simd-Allow-internal-features.patch | 24 - ...h-gets-miscompiled-with-llvm-sysroot.patch | 25 + ...7-coretests-128bit-atomic-operations.patch | 2 +- patches/portable-simd-lock.toml | 72 +-- patches/rand-lock.toml | 575 ++++++++++++++++-- patches/regex-lock.toml | 462 +++++++------- patches/stdlib-lock.toml | 28 +- rust-toolchain | 2 +- scripts/setup_rust_fork.sh | 2 +- scripts/test_rustc_tests.sh | 18 +- src/abi/mod.rs | 6 +- src/abi/pass_mode.rs | 6 +- src/abi/returning.rs | 4 +- src/allocator.rs | 4 +- src/analyze.rs | 4 +- src/base.rs | 7 +- src/cast.rs | 4 +- src/common.rs | 13 +- src/concurrency_limiter.rs | 3 +- src/constant.rs | 8 +- src/debuginfo/emit.rs | 3 +- src/debuginfo/line_info.rs | 16 +- src/debuginfo/mod.rs | 8 +- src/debuginfo/object.rs | 7 +- src/debuginfo/unwind.rs | 4 +- src/driver/aot.rs | 3 +- src/driver/jit.rs | 3 +- src/global_asm.rs | 23 +- src/inline_asm.rs | 140 +++-- src/intrinsics/llvm.rs | 4 +- src/intrinsics/llvm_aarch64.rs | 39 +- src/intrinsics/llvm_x86.rs | 10 +- src/intrinsics/mod.rs | 7 +- src/intrinsics/simd.rs | 39 +- src/lib.rs | 39 +- src/pointer.rs | 5 +- src/pretty_clif.rs | 22 +- src/value_and_place.rs | 10 +- 47 files changed, 1230 insertions(+), 734 deletions(-) delete mode 100644 patches/0001-portable-simd-Allow-internal-features.patch create mode 100644 patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch diff --git a/Cargo.lock b/Cargo.lock index af8e43da4eaf..7c324421be9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" @@ -25,12 +25,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -39,9 +33,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "cfg-if" @@ -51,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec27af72e56235eb326b5bf2de4e70ab7c5ac1fb683a1829595badaf821607fd" +checksum = "03b9d1a9e776c27ad55d7792a380785d1fe8c2d7b099eed8dbd8f4af2b598192" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2231e12925e6c5f4bc9c95b62a798eea6ed669a95bc3e00f8b2adb3b7b9b7a80" +checksum = "5528483314c2dd5da438576cd8a9d0b3cedad66fb8a4727f90cd319a81950038" dependencies = [ "bumpalo", "cranelift-bforest", @@ -72,7 +66,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.13.2", + "hashbrown 0.14.0", "log", "regalloc2", "smallvec", @@ -81,39 +75,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413b00b8dfb3aab85674a534677e7ca08854b503f164a70ec0634fce80996e2c" +checksum = "0f46a8318163f7682e35b8730ba93c1b586a2da8ce12a0ed545efc1218550f70" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0feb9ecc8193ef5cb04f494c5bd835e5bfec4bde726e7ac0444fc9dd76229e" +checksum = "37d1239cfd50eecfaed468d46943f8650e32969591868ad50111613704da6c70" [[package]] name = "cranelift-control" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72eedd2afcf5fee1e042eaaf18d3750e48ad0eca364a9f5971ecfdd5ef85bf71" +checksum = "bcc530560c8f16cc1d4dd7ea000c56f519c60d1a914977abe849ce555c35a61d" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7af19157be42671073cf8c2a52d6a4ae1e7b11f1dcb4131fede356d9f91c29dd" +checksum = "f333fa641a9ad2bff0b107767dcb972c18c2bfab7969805a1d7e42449ccb0408" [[package]] name = "cranelift-frontend" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dc7636c5fad156be7d9ae691cd1aaecd97326caf2ab534ba168056d56aa76c" +checksum = "06abf6563015a80f03f8bc4df307d0a81363f4eb73108df3a34f6e66fb6d5307" dependencies = [ "cranelift-codegen", "log", @@ -123,15 +117,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1111aea4fb6fade5779903f184249a3fc685a799fe4ec59126f9af59c7c2a74" +checksum = "0eb29d0edc8a5c029ed0f7ca77501f272738e3c410020b4a00f42ffe8ad2a8aa" [[package]] name = "cranelift-jit" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dadf88076317f6286ec77ebbe65978734fb43b6befdc96f52ff4c4c511841644" +checksum = "d16e8c5e212b1e63658aada17553497e7a259acab61f044d1f185527efa609fb" dependencies = [ "anyhow", "cranelift-codegen", @@ -149,9 +143,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6bae8a82dbf82241b1083e57e06870d2c2bdc9852727be99d58477513816953" +checksum = "d3b5fd273e1a959e920c7a9d790b1646d31acc8782bb549bad5ab85dd2fc9aa7" dependencies = [ "anyhow", "cranelift-codegen", @@ -160,9 +154,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecfc01a634448468a698beac433d98040033046678a0eed3ca39a3a9f63ae86" +checksum = "006056a7fa920870bad06bf8e1b3033d70cbb7ee625b035efa9d90882a931868" dependencies = [ "cranelift-codegen", "libc", @@ -171,9 +165,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee14a7276999f0dcaae2de84043e2c2de50820fb89b3db56fab586a4ad26734" +checksum = "9c8be1b0e7720f30fec31be0c0b0b23caef2a73fa751190c6a251c1362e8f8c9" dependencies = [ "anyhow", "cranelift-codegen", @@ -195,33 +189,27 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "gimli" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" dependencies = [ "fallible-iterator", - "indexmap 1.9.3", + "indexmap", "stable_deref_trait", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.13.2" @@ -236,15 +224,8 @@ name = "hashbrown" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "ahash", ] [[package]] @@ -259,9 +240,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libloading" @@ -275,12 +256,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "mach" @@ -293,27 +271,27 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "object" -version = "0.30.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "crc32fast", - "hashbrown 0.13.2", - "indexmap 1.9.3", + "hashbrown 0.14.0", + "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "regalloc2" @@ -357,7 +335,7 @@ dependencies = [ "cranelift-native", "cranelift-object", "gimli", - "indexmap 2.0.0", + "indexmap", "libloading", "object", "smallvec", @@ -366,15 +344,15 @@ dependencies = [ [[package]] name = "slice-group-by" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "stable_deref_trait" @@ -396,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "11.0.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34eb67f0829a5614ec54716c8e0c9fe68fab7b9df3686c85f719c9d247f7169" +checksum = "c6ff5f3707a5e3797deeeeac6ac26b2e1dd32dbc06693c0ab52e8ac4d18ec706" dependencies = [ "cfg-if", "libc", @@ -438,9 +416,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -453,42 +431,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index 8ded81d7399b..28a37b7995b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.98", features = ["unwind", "all-arch"] } -cranelift-frontend = { version = "0.98" } -cranelift-module = { version = "0.98" } -cranelift-native = { version = "0.98" } -cranelift-jit = { version = "0.98", optional = true } -cranelift-object = { version = "0.98" } +cranelift-codegen = { version = "0.100", features = ["unwind", "all-arch"] } +cranelift-frontend = { version = "0.100" } +cranelift-module = { version = "0.100" } +cranelift-native = { version = "0.100" } +cranelift-jit = { version = "0.100", optional = true } +cranelift-object = { version = "0.100" } target-lexicon = "0.12.0" -gimli = { version = "0.27.2", default-features = false, features = ["write"]} -object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.28", default-features = false, features = ["write"]} +object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.7.3", optional = true } diff --git a/Readme.md b/Readme.md index 62eaef359af9..6f2027be96de 100644 --- a/Readme.md +++ b/Readme.md @@ -60,18 +60,14 @@ You need to do this steps to successfully compile and use the cranelift backend 2. Run `python x.py setup` and choose option for compiler (`b`). 3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt` * (Optional) You can also build cargo by adding `src/tools/cargo` to previous command. -4. Copy exectutable files from `./build/host/stage2-tools//release` -to `./build/host/stage2/bin/`. Note that you would need to do this every time you rebuilt `rust` repository. -5. Copy cargo from another toolchain: `cp $(rustup which cargo) .build//stage2/bin/cargo` - * Another option is to build it at step 3 and copy with other executables at step 4. -6. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`. -7. (Windows only) compile the build system: `rustc +stage2 -O build_system/main.rs -o y.exe`. -8. You need to prefix every `./y.sh` (or `y` if you built `build_system/main.rs` as `y`) command by `rustup run stage2` to make cg_clif use your local changes in rustc. - +4. Copy cargo from a nightly toolchain: `cp $(rustup +nightly which cargo) ./build/host/stage2/bin/cargo`. Note that you would need to do this every time you rebuilt `rust` repository. +5. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`. +6. (Windows only) compile the build system: `rustc +stage2 -O build_system/main.rs -o y.exe`. +7. You need to prefix every `./y.sh` (or `y` if you built `build_system/main.rs` as `y`) command by `rustup run stage2` to make cg_clif use your local changes in rustc. * `rustup run stage2 ./y.sh prepare` * `rustup run stage2 ./y.sh build` * (Optional) run tests: `rustup run stage2 ./y.sh test` -9. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. +8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. ## Configuration diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index e434c36f9922..d90111adf776 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -20,6 +20,8 @@ pub(crate) fn build_backend( let mut rustflags = rustflags_from_env("RUSTFLAGS"); + rustflags.push("-Zallow-features=rustc_private".to_owned()); + if is_ci() { // Deny warnings on CI rustflags.push("-Dwarnings".to_owned()); diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 165296cb4a98..16e7a4bafaee 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -122,10 +122,10 @@ impl GitRepo { if download_dir.exists() { let actual_hash = format!("{:016x}", hash_dir(&download_dir)); if actual_hash == self.content_hash { - println!("[FRESH] {}", download_dir.display()); + eprintln!("[FRESH] {}", download_dir.display()); return; } else { - println!( + eprintln!( "Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Downloading again.", download_dir = download_dir.display(), content_hash = self.content_hash, @@ -150,7 +150,7 @@ impl GitRepo { let actual_hash = format!("{:016x}", hash_dir(&download_dir)); if actual_hash != self.content_hash { - println!( + eprintln!( "Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}", download_dir = download_dir.display(), content_hash = self.content_hash, diff --git a/build_system/tests.rs b/build_system/tests.rs index e7bd8b1278c6..95ff6b754220 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -9,7 +9,7 @@ use crate::path::{Dirs, RelPath}; use crate::prepare::{apply_patches, GitRepo}; use crate::rustc_info::get_default_sysroot; use crate::shared_utils::rustflags_from_env; -use crate::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler, LogGroup}; +use crate::utils::{spawn_and_wait, CargoProject, Compiler, LogGroup}; use crate::{CodegenBackend, SysrootKind}; static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); @@ -101,13 +101,11 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"), ]; -// FIXME(rust-random/rand#1293): Newer rand versions fail to test on Windows. Update once this is -// fixed. pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rust-random", "rand", - "50b9a447410860af8d6db9a208c3576886955874", - "446203b96054891e", + "f3dd0b885c4597b9617ca79987a0dd899ab29fcb", + "3f869e4fcd602b66", "rand", ); @@ -116,8 +114,8 @@ pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir() pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "rust-lang", "regex", - "32fed9429eafba0ae92a64b01796a0c5a75b88c8", - "fcc4df7c5b902633", + "061ee815ef2c44101dba7b0b124600fcb03c1912", + "dc26aefbeeac03ca", "regex", ); @@ -126,8 +124,8 @@ pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( "rust-lang", "portable-simd", - "7c7dbe0c505ccbc02ff30c1e37381ab1d47bf46f", - "5bcc9c544f6fa7bd", + "4825b2a64d765317066948867e8714674419359b", + "8b188cc41f5af835", "portable-simd", ); @@ -180,40 +178,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::custom("test.regex-shootout-regex-dna", &|runner| { - REGEX_REPO.patch(&runner.dirs); - - REGEX.clean(&runner.dirs); - - let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--example").arg("shootout-regex-dna"); - spawn_and_wait(build_cmd); - - if runner.is_native { - let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs); - run_cmd.arg("--example").arg("shootout-regex-dna"); - - let input = fs::read_to_string( - REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"), - ) - .unwrap(); - let expected = fs::read_to_string( - REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"), - ) - .unwrap(); - - let output = spawn_and_wait_with_input(run_cmd, input); - - let output_matches = expected.lines().eq(output.lines()); - if !output_matches { - println!("Output files don't match!"); - println!("Expected Output:\n{}", expected); - println!("Actual Output:\n{}", output); - - std::process::exit(1); - } - } - }), TestCase::custom("test.regex", &|runner| { REGEX_REPO.patch(&runner.dirs); @@ -223,7 +187,22 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs); // regex-capi and regex-debug don't have any tests. Nor do they contain any code // that is useful to test with cg_clif. Skip building them to reduce test time. - run_cmd.args(["-p", "regex", "-p", "regex-syntax", "--", "-q"]); + run_cmd.args([ + "-p", + "regex", + "-p", + "regex-syntax", + "--release", + "--all-targets", + "--", + "-q", + ]); + spawn_and_wait(run_cmd); + + let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs); + // don't run integration tests for regex-autonata. they take like 2min each without + // much extra coverage of simd usage. + run_cmd.args(["-p", "regex-automata", "--release", "--lib", "--", "-q"]); spawn_and_wait(run_cmd); } else { eprintln!("Cross-Compiling: Not running tests"); diff --git a/build_system/utils.rs b/build_system/utils.rs index 24624cdeab1f..9f24c043a504 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -1,8 +1,8 @@ use std::env; use std::fs; -use std::io::{self, Write}; +use std::io; use std::path::{Path, PathBuf}; -use std::process::{self, Command, Stdio}; +use std::process::{self, Command}; use std::sync::atomic::{AtomicBool, Ordering}; use crate::path::{Dirs, RelPath}; @@ -47,7 +47,7 @@ impl Compiler { self.runner = vec!["wine".to_owned()]; } _ => { - println!("Unknown non-native platform"); + eprintln!("Unknown non-native platform"); } } } @@ -197,7 +197,9 @@ pub(crate) fn try_hard_link(src: impl AsRef, dst: impl AsRef) { #[track_caller] pub(crate) fn spawn_and_wait(mut cmd: Command) { - if !cmd.spawn().unwrap().wait().unwrap().success() { + let status = cmd.spawn().unwrap().wait().unwrap(); + if !status.success() { + eprintln!("{cmd:?} exited with status {:?}", status); process::exit(1); } } @@ -207,38 +209,17 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) { pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) { for i in 1..tries + 1 { if i != 1 { - println!("Command failed. Attempt {i}/{tries}:"); + eprintln!("Command failed. Attempt {i}/{tries}:"); } if cmd.spawn().unwrap().wait().unwrap().success() { return; } std::thread::sleep(std::time::Duration::from_secs(i * 5)); } - println!("The command has failed after {tries} attempts."); + eprintln!("The command has failed after {tries} attempts."); process::exit(1); } -#[track_caller] -pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String { - let mut child = cmd - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("Failed to spawn child process"); - - let mut stdin = child.stdin.take().expect("Failed to open stdin"); - std::thread::spawn(move || { - stdin.write_all(input.as_bytes()).expect("Failed to write to stdin"); - }); - - let output = child.wait_with_output().expect("Failed to read stdout"); - if !output.status.success() { - process::exit(1); - } - - String::from_utf8(output.stdout).unwrap() -} - pub(crate) fn remove_dir_if_exists(path: &Path) { match fs::remove_dir_all(&path) { Ok(()) => {} diff --git a/config.txt b/config.txt index fa1c9f4259c4..7ff805e58d96 100644 --- a/config.txt +++ b/config.txt @@ -46,6 +46,5 @@ aot.issue-59326 testsuite.extended_sysroot test.rust-random/rand test.libcore -test.regex-shootout-regex-dna test.regex test.portable-simd diff --git a/example/mini_core.rs b/example/mini_core.rs index 34c7e44b2881..934e4b1786fa 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -683,6 +683,12 @@ pub macro cfg() { /* compiler built-in */ } +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro asm() { + /* compiler built-in */ +} + #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] pub macro global_asm() { diff --git a/patches/0001-portable-simd-Allow-internal-features.patch b/patches/0001-portable-simd-Allow-internal-features.patch deleted file mode 100644 index 87252df1eabe..000000000000 --- a/patches/0001-portable-simd-Allow-internal-features.patch +++ /dev/null @@ -1,24 +0,0 @@ -From fcf75306d88e533b83eaff3f8d0ab9f307e8a84d Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Wed, 9 Aug 2023 10:01:17 +0000 -Subject: [PATCH] Allow internal features - ---- - crates/core_simd/src/lib.rs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs -index fde406b..b386116 100644 ---- a/crates/core_simd/src/lib.rs -+++ b/crates/core_simd/src/lib.rs -@@ -19,6 +19,7 @@ - #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really - #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] - #![unstable(feature = "portable_simd", issue = "86656")] -+#![allow(internal_features)] - //! Portable SIMD module. - - #[path = "mod.rs"] --- -2.34.1 - diff --git a/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch b/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch new file mode 100644 index 000000000000..e6ebdcec783a --- /dev/null +++ b/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch @@ -0,0 +1,25 @@ +From 5d4afb8d807d181038b6a004d17ed055a8d191b2 Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Mon, 2 Oct 2023 13:59:00 +0000 +Subject: [PATCH] Ignore test which gets miscompiled with llvm sysroot + +--- + regex-automata/src/util/pool.rs | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/regex-automata/src/util/pool.rs b/regex-automata/src/util/pool.rs +index c03d7b0..28b233b 100644 +--- a/regex-automata/src/util/pool.rs ++++ b/regex-automata/src/util/pool.rs +@@ -1081,6 +1081,8 @@ mod tests { + // into the pool. This in turn resulted in this test producing a data race. + #[cfg(feature = "std")] + #[test] ++ // FIXME(rustc_codegen_cranelift#1395) miscompilation of thread::scope with LLVM sysroot ++ #[ignore] + fn thread_owner_sync() { + let pool = Pool::new(|| vec!['a']); + { +-- +2.34.1 + diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-coretests-128bit-atomic-operations.patch index a650e10110bf..be29ae09bcfc 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-coretests-128bit-atomic-operations.patch @@ -19,9 +19,9 @@ index 897a5e9..331f66f 100644 #![feature(const_option_ext)] #![feature(const_result)] -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] + #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] #![feature(slice_group_by)] - #![feature(split_array)] diff --git a/atomic.rs b/atomic.rs index b735957..ea728b6 100644 --- a/atomic.rs diff --git a/patches/portable-simd-lock.toml b/patches/portable-simd-lock.toml index e7db1fd2c7fb..5c9dc7b361f9 100644 --- a/patches/portable-simd-lock.toml +++ b/patches/portable-simd-lock.toml @@ -16,9 +16,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" @@ -55,33 +55,33 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] [[package]] name = "log" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "ppv-lite86" @@ -91,9 +91,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -114,9 +114,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -199,15 +199,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", @@ -230,9 +230,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -252,9 +252,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", @@ -265,15 +265,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-bindgen-test" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e636f3a428ff62b3742ebc3c70e254dfe12b8c2b469d688ea59cdd4abcf502" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" dependencies = [ "console_error_panic_hook", "js-sys", @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18c1fad2f7c4958e7bcce014fa212f59a65d5e3721d0f77e6c0b27ede936ba3" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ "proc-macro2", "quote", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/patches/rand-lock.toml b/patches/rand-lock.toml index 66c515731c5e..aacf3653c169 100644 --- a/patches/rand-lock.toml +++ b/patches/rand-lock.toml @@ -2,6 +2,32 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -28,12 +54,114 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags", + "clap_lex", + "indexmap", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -57,9 +185,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -70,13 +198,48 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "easy-cast" version = "0.4.4" @@ -88,9 +251,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "float-ord" @@ -99,10 +262,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" [[package]] -name = "getrandom" -version = "0.2.9" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -110,25 +279,83 @@ dependencies = [ ] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "half" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] -name = "itoa" -version = "1.0.6" +name = "hermit-abi" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libm" @@ -138,24 +365,30 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "log" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", "libm", @@ -163,14 +396,60 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "libc", ] +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "os_str_bytes" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -179,18 +458,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -200,6 +479,7 @@ name = "rand" version = "0.9.0" dependencies = [ "bincode", + "criterion", "libc", "log", "rand_chacha", @@ -236,6 +516,7 @@ dependencies = [ "rand", "rand_pcg", "serde", + "serde_with", "special", ] @@ -271,48 +552,108 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.13" +name = "regex" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.37", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "special" version = "0.8.1" @@ -323,10 +664,16 @@ dependencies = [ ] [[package]] -name = "syn" -version = "2.0.18" +name = "strsim" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -334,13 +681,145 @@ dependencies = [ ] [[package]] -name = "unicode-ident" -version = "1.0.9" +name = "syn" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.37", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/patches/regex-lock.toml b/patches/regex-lock.toml index 0e4a33b90ea1..e0df6f9ae267 100644 --- a/patches/regex-lock.toml +++ b/patches/regex-lock.toml @@ -4,51 +4,49 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" dependencies = [ + "log", "memchr", ] [[package]] -name = "bitflags" -version = "1.3.2" +name = "anyhow" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] -name = "bzip2" -version = "0.3.3" +name = "arbitrary" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" dependencies = [ - "bzip2-sys", - "libc", + "derive_arbitrary", ] [[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "cc", + "hermit-abi", "libc", - "pkg-config", + "winapi", ] [[package]] -name = "cc" -version = "1.0.79" +name = "bstr" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "cfg-if" @@ -57,114 +55,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "docopt" -version = "1.1.1" +name = "derive_arbitrary" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" +checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" dependencies = [ - "lazy_static", - "regex 1.8.3", - "serde", - "strsim", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "filetime" -version = "0.2.21" +name = "doc-comment" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "windows-sys", + "atty", + "humantime", + "log", + "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "hashbrown" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "lexopt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] -name = "libpcre-sys" -version = "0.2.2" +name = "log" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ff3dd28ba96d6fe6752882f2f1b25ba8e1646448e79042442347cf3a92a6666" -dependencies = [ - "bzip2", - "libc", - "pkg-config", - "tar", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" dependencies = [ - "libc", - "winapi", + "log", ] [[package]] -name = "onig" -version = "3.2.2" +name = "memmap2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5eeb268a4620c74ea5768c6d2ccd492d60a47a8754666b91a46bfc35cd4d1ba" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ - "bitflags", - "lazy_static", "libc", - "onig_sys", ] [[package]] -name = "onig_sys" -version = "68.2.1" +name = "once_cell" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195ebddbb56740be48042ca117b8fb6e0d99fe392191a9362d82f5f69e510379" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -180,9 +193,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -205,96 +218,102 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" -version = "1.7.2" +version = "1.9.5" dependencies = [ "aho-corasick", - "lazy_static", + "anyhow", + "doc-comment", + "env_logger", + "memchr", + "once_cell", + "quickcheck", + "regex-automata", + "regex-syntax", + "regex-test", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +dependencies = [ + "aho-corasick", + "anyhow", + "bstr", + "doc-comment", + "env_logger", + "log", "memchr", "quickcheck", - "rand", - "regex-syntax 0.6.29", + "regex-syntax", + "regex-test", ] [[package]] -name = "regex" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" -dependencies = [ - "regex-syntax 0.7.2", -] - -[[package]] -name = "regex-benchmark" +name = "regex-cli" version = "0.1.0" dependencies = [ - "cc", - "cfg-if 0.1.10", - "docopt", - "lazy_static", - "libc", - "libpcre-sys", - "memmap", - "onig", - "pkg-config", - "regex 1.7.2", - "regex-syntax 0.6.29", - "serde", + "anyhow", + "bstr", + "lexopt", + "log", + "memmap2", + "regex", + "regex-automata", + "regex-lite", + "regex-syntax", + "tabwriter", + "textwrap", ] [[package]] -name = "regex-debug" +name = "regex-lite" version = "0.1.0" dependencies = [ - "docopt", - "regex 1.7.2", - "regex-syntax 0.6.29", - "serde", + "anyhow", + "regex-test", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.5" +dependencies = [ + "arbitrary", +] [[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +name = "regex-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "bstr", + "serde", + "toml", +] [[package]] name = "rure" version = "0.2.2" dependencies = [ "libc", - "regex 1.7.2", + "regex", ] [[package]] name = "serde" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -302,16 +321,19 @@ dependencies = [ ] [[package]] -name = "strsim" -version = "0.10.0" +name = "serde_spanned" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] [[package]] name = "syn" -version = "2.0.18" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -319,21 +341,74 @@ dependencies = [ ] [[package]] -name = "tar" -version = "0.4.38" +name = "tabwriter" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "08e1173ee641651a3095fe95d86ae314cd1f959888097debce3e0f9ca532eef1" dependencies = [ - "filetime", - "libc", - "xattr", + "unicode-width", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "wasi" @@ -357,6 +432,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -364,76 +448,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.48.0" +name = "winnow" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "xattr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" -dependencies = [ - "libc", + "memchr", ] diff --git a/patches/stdlib-lock.toml b/patches/stdlib-lock.toml index 5b79d6569bb0..de89c4f5eff8 100644 --- a/patches/stdlib-lock.toml +++ b/patches/stdlib-lock.toml @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.146" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" dependencies = [ "rustc-std-workspace-core", ] @@ -255,6 +255,27 @@ dependencies = [ "core", ] +[[package]] +name = "r-efi" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575fc2d9b3da54adbdfaddf6eca48fec256d977c8630a1750b8991347d1ac911" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "r-efi-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7" +dependencies = [ + "compiler_builtins", + "r-efi", + "rustc-std-workspace-core", +] + [[package]] name = "rand" version = "0.8.5" @@ -340,6 +361,7 @@ version = "0.0.0" dependencies = [ "addr2line", "alloc", + "cc", "cfg-if", "compiler_builtins", "core", @@ -353,6 +375,8 @@ dependencies = [ "panic_abort", "panic_unwind", "profiler_builtins", + "r-efi", + "r-efi-alloc", "rand", "rand_xorshift", "rustc-demangle", diff --git a/rust-toolchain b/rust-toolchain index 2cc5d7777a62..86ef127badd4 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-09-06" +channel = "nightly-2023-10-09" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index f09b9ef12deb..60ac6bc9951e 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -./y.sh build --no-unstable-features +./y.sh build echo "[SETUP] Rust fork" git clone https://github.com/rust-lang/rust.git || true diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 3fc462a39cc2..3b2a12ec0280 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -11,22 +11,17 @@ pushd rust command -v rg >/dev/null 2>&1 || cargo install ripgrep rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true -for test in $(rg --files-with-matches "lto|// needs-asm-support" tests/{codegen-units,ui,incremental}); do +for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do rm $test done -for test in tests/run-make/**/Makefile; do - if rg "# needs-asm-support" $test >/dev/null; then - rm -r $(dirname $test) - fi -done - for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do rm $test done git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed git checkout -- tests/ui/proc-macro/pretty-print-hack/ +git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # missing features @@ -35,8 +30,9 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR rm -r tests/run-make/comment-section # cg_clif doesn't yet write the .comment section # requires stack unwinding -# FIXME add needs-unwind to this test +# FIXME add needs-unwind to these tests rm -r tests/run-make/libtest-junit +rm tests/ui/asm/may_unwind.rs # extra warning about -Cpanic=abort for proc macros rm tests/ui/proc-macro/crt-static.rs @@ -77,6 +73,8 @@ rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same rm -r tests/run-make/use-extern-for-plugins # same +rm tests/ui/asm/x86_64/issue-82869.rs # vector regs in inline asm not yet supported +rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly # requires LTO rm -r tests/run-make/cdylib @@ -130,6 +128,7 @@ rm tests/ui/consts/issue-73976-monomorphic.rs # same rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs # same rm tests/ui/consts/issue-94675.rs # same +rm tests/ui/associated-types/issue-85103-layout-debug.rs # same # rustdoc-clif passes extra args, suppressing the help message when no args are passed rm -r tests/run-make/issue-88756-default-output @@ -154,9 +153,12 @@ rm -r tests/run-make/output-type-permutations # same rm -r tests/run-make/used # same rm -r tests/run-make/no-alloc-shim rm -r tests/run-make/emit-to-stdout +rm -r tests/run-make/compressed-debuginfo rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported +rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug with Generator's + # bugs in the test suite # ====================== rm tests/ui/backtrace.rs # TODO warning diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 5c7d7b20c5de..c75ad852f82d 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -6,6 +6,7 @@ mod returning; use std::borrow::Cow; +use cranelift_codegen::ir::{AbiParam, SigRef}; use cranelift_module::ModuleError; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::FnAbiOf; @@ -13,12 +14,9 @@ use rustc_session::Session; use rustc_target::abi::call::{Conv, FnAbi}; use rustc_target::spec::abi::Abi; -use cranelift_codegen::ir::{AbiParam, SigRef}; - use self::pass_mode::*; -use crate::prelude::*; - pub(crate) use self::returning::codegen_return; +use crate::prelude::*; fn clif_sig_from_fn_abi<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 0d16da48067a..7c9f8c1051cb 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -1,14 +1,14 @@ //! Argument passing -use crate::prelude::*; -use crate::value_and_place::assert_assignable; - use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; use rustc_target::abi::call::{ ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind, }; use smallvec::{smallvec, SmallVec}; +use crate::prelude::*; +use crate::value_and_place::assert_assignable; + pub(super) trait ArgAbiExt<'tcx> { fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>; fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec); diff --git a/src/abi/returning.rs b/src/abi/returning.rs index 646fb4a3cdc8..0799a22c6e16 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -1,10 +1,10 @@ //! Return value handling -use crate::prelude::*; - use rustc_target::abi::call::{ArgAbi, PassMode}; use smallvec::{smallvec, SmallVec}; +use crate::prelude::*; + /// Return a place where the return value of the current function can be written to. If necessary /// this adds an extra parameter pointing to where the return value needs to be stored. pub(super) fn codegen_return_param<'tcx>( diff --git a/src/allocator.rs b/src/allocator.rs index 4e4c595de825..e8af3e8c2555 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,8 +1,6 @@ //! Allocator shim // Adapted from rustc -use crate::prelude::*; - use rustc_ast::expand::allocator::{ alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, @@ -10,6 +8,8 @@ use rustc_ast::expand::allocator::{ use rustc_codegen_ssa::base::allocator_kind_for_codegen; use rustc_session::config::OomStrategy; +use crate::prelude::*; + /// Returns whether an allocator shim was created pub(crate) fn codegen( tcx: TyCtxt<'_>, diff --git a/src/analyze.rs b/src/analyze.rs index 359d581c1535..321612238ea4 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -1,11 +1,11 @@ //! SSA analysis -use crate::prelude::*; - use rustc_index::IndexVec; use rustc_middle::mir::StatementKind::*; use rustc_middle::ty::Ty; +use crate::prelude::*; + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub(crate) enum SsaKind { NotSsa, diff --git a/src/base.rs b/src/base.rs index 0c0a1e80a418..ac7389792c80 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,15 +1,14 @@ //! Codegen of a single function +use cranelift_codegen::ir::UserFuncName; +use cranelift_codegen::CodegenError; +use cranelift_module::ModuleError; use rustc_ast::InlineAsmOptions; use rustc_index::IndexVec; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use cranelift_codegen::ir::UserFuncName; -use cranelift_codegen::CodegenError; -use cranelift_module::ModuleError; - use crate::constant::ConstantCx; use crate::debuginfo::FunctionDebugContext; use crate::prelude::*; diff --git a/src/cast.rs b/src/cast.rs index 6bf3a866ba46..7e027c5f1b30 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -129,8 +129,8 @@ pub(crate) fn clif_int_or_float_cast( let (min, max) = match (to_ty, to_signed) { (types::I8, false) => (0, i64::from(u8::MAX)), (types::I16, false) => (0, i64::from(u16::MAX)), - (types::I8, true) => (i64::from(i8::MIN), i64::from(i8::MAX)), - (types::I16, true) => (i64::from(i16::MIN), i64::from(i16::MAX)), + (types::I8, true) => (i64::from(i8::MIN as u32), i64::from(i8::MAX as u32)), + (types::I16, true) => (i64::from(i16::MIN as u32), i64::from(i16::MAX as u32)), _ => unreachable!(), }; let min_val = fx.bcx.ins().iconst(types::I32, min); diff --git a/src/common.rs b/src/common.rs index 359b430b4e57..8958369267e5 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,6 +1,5 @@ use cranelift_codegen::isa::TargetFrontendConfig; use gimli::write::FileId; - use rustc_data_structures::sync::Lrc; use rustc_index::IndexVec; use rustc_middle::ty::layout::{ @@ -204,9 +203,9 @@ pub(crate) fn type_min_max_value( (types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => { 0i64 } - (types::I8, true) => i64::from(i8::MIN), - (types::I16, true) => i64::from(i16::MIN), - (types::I32, true) => i64::from(i32::MIN), + (types::I8, true) => i64::from(i8::MIN as u8), + (types::I16, true) => i64::from(i16::MIN as u16), + (types::I32, true) => i64::from(i32::MIN as u32), (types::I64, true) => i64::MIN, _ => unreachable!(), }; @@ -216,9 +215,9 @@ pub(crate) fn type_min_max_value( (types::I16, false) => i64::from(u16::MAX), (types::I32, false) => i64::from(u32::MAX), (types::I64, false) => u64::MAX as i64, - (types::I8, true) => i64::from(i8::MAX), - (types::I16, true) => i64::from(i16::MAX), - (types::I32, true) => i64::from(i32::MAX), + (types::I8, true) => i64::from(i8::MAX as u8), + (types::I16, true) => i64::from(i16::MAX as u16), + (types::I32, true) => i64::from(i32::MAX as u32), (types::I64, true) => i64::MAX, _ => unreachable!(), }; diff --git a/src/concurrency_limiter.rs b/src/concurrency_limiter.rs index d2b928db7d4d..20f2ee4c76a5 100644 --- a/src/concurrency_limiter.rs +++ b/src/concurrency_limiter.rs @@ -1,8 +1,7 @@ use std::sync::{Arc, Condvar, Mutex}; -use rustc_session::Session; - use jobserver::HelperThread; +use rustc_session::Session; // FIXME don't panic when a worker thread panics diff --git a/src/constant.rs b/src/constant.rs index 14b10ed8b9a5..1cb6fa077231 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,12 +1,11 @@ //! Handling of `static`s, `const`s and promoted allocations +use cranelift_module::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar}; use rustc_middle::mir::ConstValue; -use cranelift_module::*; - use crate::prelude::*; pub(crate) struct ConstantCx { @@ -101,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>( if fx.clif_type(layout.ty).is_some() { return CValue::const_val(fx, layout, int); } else { - let raw_val = int.to_bits(int.size()).unwrap(); + let raw_val = int.size().truncate(int.to_bits(int.size()).unwrap()); let val = match int.size().bytes() { 1 => fx.bcx.ins().iconst(types::I8, raw_val as i64), 2 => fx.bcx.ins().iconst(types::I16, raw_val as i64), @@ -187,8 +186,7 @@ pub(crate) fn codegen_const_value<'tcx>( ConstValue::Slice { data, meta } => { let alloc_id = fx.tcx.reserve_and_set_memory_alloc(data); let ptr = pointer_for_allocation(fx, alloc_id).get_addr(fx); - // FIXME: the `try_from` here can actually fail, e.g. for very long ZST slices. - let len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(meta).unwrap()); + let len = fx.bcx.ins().iconst(fx.pointer_type, meta as i64); CValue::by_val_pair(ptr, len, layout) } } diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index c4a5627e662f..81b819a55464 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -1,10 +1,9 @@ //! Write the debuginfo into an object file. use cranelift_object::ObjectProduct; -use rustc_data_structures::fx::FxHashMap; - use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; use gimli::{RunTimeEndian, SectionId}; +use rustc_data_structures::fx::FxHashMap; use super::object::WriteDebugInfo; use super::DebugContext; diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index b19b935a0fea..d00d19f9a80c 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -3,20 +3,18 @@ use std::ffi::OsStr; use std::path::{Component, Path}; -use crate::debuginfo::FunctionDebugContext; -use crate::prelude::*; - +use cranelift_codegen::binemit::CodeOffset; +use cranelift_codegen::MachSrcLoc; +use gimli::write::{ + Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable, +}; use rustc_data_structures::sync::Lrc; use rustc_span::{ FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, }; -use cranelift_codegen::binemit::CodeOffset; -use cranelift_codegen::MachSrcLoc; - -use gimli::write::{ - Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable, -}; +use crate::debuginfo::FunctionDebugContext; +use crate::prelude::*; // OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`. fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) { diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 8a4b1cccf146..9e78cc259ce1 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -5,11 +5,8 @@ mod line_info; mod object; mod unwind; -use crate::prelude::*; - use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::TargetIsa; - use gimli::write::{ Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList, UnitEntryId, @@ -17,8 +14,9 @@ use gimli::write::{ use gimli::{Encoding, Format, LineEncoding, RunTimeEndian}; use indexmap::IndexSet; -pub(crate) use emit::{DebugReloc, DebugRelocName}; -pub(crate) use unwind::UnwindContext; +pub(crate) use self::emit::{DebugReloc, DebugRelocName}; +pub(crate) use self::unwind::UnwindContext; +use crate::prelude::*; pub(crate) fn producer() -> String { format!( diff --git a/src/debuginfo/object.rs b/src/debuginfo/object.rs index 9dc9b2cf9f8a..f1840a7bf730 100644 --- a/src/debuginfo/object.rs +++ b/src/debuginfo/object.rs @@ -1,12 +1,9 @@ -use rustc_data_structures::fx::FxHashMap; - use cranelift_module::FuncId; use cranelift_object::ObjectProduct; - +use gimli::SectionId; use object::write::{Relocation, StandardSegment}; use object::{RelocationEncoding, SectionKind}; - -use gimli::SectionId; +use rustc_data_structures::fx::FxHashMap; use crate::debuginfo::{DebugReloc, DebugRelocName}; diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 493359c743f1..35278e6fb29d 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -1,15 +1,13 @@ //! Unwind info generation (`.eh_frame`) -use crate::prelude::*; - use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; - use cranelift_object::ObjectProduct; use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; use gimli::RunTimeEndian; use super::object::WriteDebugInfo; +use crate::prelude::*; pub(crate) struct UnwindContext { endian: RunTimeEndian, diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 3e93830951c5..cc2f5d727146 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use std::sync::Arc; use std::thread::JoinHandle; +use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -17,8 +18,6 @@ use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; use rustc_session::Session; -use cranelift_object::{ObjectBuilder, ObjectModule}; - use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::global_asm::GlobalAsmConfig; use crate::{prelude::*, BackendConfig}; diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 1c606494f383..6ee65d12c73e 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -6,13 +6,12 @@ use std::ffi::CString; use std::os::raw::{c_char, c_int}; use std::sync::{mpsc, Mutex, OnceLock}; +use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; use rustc_span::Symbol; -use cranelift_jit::{JITBuilder, JITModule}; - use crate::{prelude::*, BackendConfig}; use crate::{CodegenCx, CodegenMode}; diff --git a/src/global_asm.rs b/src/global_asm.rs index baadd7a9e812..ebd9b728d90b 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -9,16 +9,22 @@ use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::{InlineAsmOperand, ItemId}; use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_target::asm::InlineAsmArch; use crate::prelude::*; pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { let item = tcx.hir().item(item_id); if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { - if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - global_asm.push_str("\n.intel_syntax noprefix\n"); - } else { - global_asm.push_str("\n.att_syntax\n"); + let is_x86 = + matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); + + if is_x86 { + if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { + global_asm.push_str("\n.intel_syntax noprefix\n"); + } else { + global_asm.push_str("\n.att_syntax\n"); + } } for piece in asm.template { match *piece { @@ -65,7 +71,11 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, } } } - global_asm.push_str("\n.att_syntax\n\n"); + + global_asm.push('\n'); + if is_x86 { + global_asm.push_str(".att_syntax\n\n"); + } } else { bug!("Expected GlobalAsm found {:?}", item); } @@ -115,11 +125,12 @@ pub(crate) fn compile_global_asm( } // Remove all LLVM style comments - let global_asm = global_asm + let mut global_asm = global_asm .lines() .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line }) .collect::>() .join("\n"); + global_asm.push('\n'); let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)); diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 50bbf8105fdb..dd2127d554dd 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -1,13 +1,14 @@ //! Codegen of `asm!` invocations. -use crate::prelude::*; - use std::fmt::Write; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir::InlineAsmOperand; use rustc_span::sym; use rustc_target::asm::*; +use target_lexicon::BinaryFormat; + +use crate::prelude::*; enum CInlineAsmOperand<'tcx> { In { @@ -43,7 +44,9 @@ pub(crate) fn codegen_inline_asm<'tcx>( ) { // FIXME add .eh_frame unwind info directives - if !template.is_empty() { + if !template.is_empty() + && (cfg!(not(feature = "inline_asm")) || fx.tcx.sess.target.is_like_windows) + { // Used by panic_abort if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { fx.bcx.ins().trap(TrapCode::User(1)); @@ -589,11 +592,29 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } fn generate_asm_wrapper(&self, asm_name: &str) -> String { + let binary_format = crate::target_triple(self.tcx.sess).binary_format; + let mut generated_asm = String::new(); - writeln!(generated_asm, ".globl {}", asm_name).unwrap(); - writeln!(generated_asm, ".type {},@function", asm_name).unwrap(); - writeln!(generated_asm, ".section .text.{},\"ax\",@progbits", asm_name).unwrap(); - writeln!(generated_asm, "{}:", asm_name).unwrap(); + match binary_format { + BinaryFormat::Elf => { + writeln!(generated_asm, ".globl {}", asm_name).unwrap(); + writeln!(generated_asm, ".type {},@function", asm_name).unwrap(); + writeln!(generated_asm, ".section .text.{},\"ax\",@progbits", asm_name).unwrap(); + writeln!(generated_asm, "{}:", asm_name).unwrap(); + } + BinaryFormat::Macho => { + writeln!(generated_asm, ".globl _{}", asm_name).unwrap(); + writeln!(generated_asm, "_{}:", asm_name).unwrap(); + } + BinaryFormat::Coff => { + writeln!(generated_asm, ".globl {}", asm_name).unwrap(); + writeln!(generated_asm, "{}:", asm_name).unwrap(); + } + _ => self + .tcx + .sess + .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")), + } let is_x86 = matches!(self.arch, InlineAsmArch::X86 | InlineAsmArch::X86_64); @@ -690,8 +711,19 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if is_x86 { generated_asm.push_str(".att_syntax\n"); } - writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap(); - generated_asm.push_str(".text\n"); + + match binary_format { + BinaryFormat::Elf => { + writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap(); + generated_asm.push_str(".text\n"); + } + BinaryFormat::Macho | BinaryFormat::Coff => {} + _ => self + .tcx + .sess + .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")), + } + generated_asm.push_str("\n\n"); generated_asm @@ -699,25 +731,19 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn prologue(generated_asm: &mut String, arch: InlineAsmArch) { match arch { - InlineAsmArch::X86 => { - generated_asm.push_str(" push ebp\n"); - generated_asm.push_str(" mov ebp,[esp+8]\n"); - } InlineAsmArch::X86_64 => { generated_asm.push_str(" push rbp\n"); - generated_asm.push_str(" mov rbp,rdi\n"); + generated_asm.push_str(" mov rbp,rsp\n"); + generated_asm.push_str(" push rbx\n"); // rbx is callee saved + // rbx is reserved by LLVM for the "base pointer", so rustc doesn't allow using it + generated_asm.push_str(" mov rbx,rdi\n"); } - InlineAsmArch::RiscV32 => { - generated_asm.push_str(" addi sp, sp, -8\n"); - generated_asm.push_str(" sw ra, 4(sp)\n"); - generated_asm.push_str(" sw s0, 0(sp)\n"); - generated_asm.push_str(" mv s0, a0\n"); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" addi sp, sp, -16\n"); - generated_asm.push_str(" sd ra, 8(sp)\n"); - generated_asm.push_str(" sd s0, 0(sp)\n"); - generated_asm.push_str(" mv s0, a0\n"); + InlineAsmArch::AArch64 => { + generated_asm.push_str(" stp fp, lr, [sp, #-32]!\n"); + generated_asm.push_str(" mov fp, sp\n"); + generated_asm.push_str(" str x19, [sp, #24]\n"); // x19 is callee saved + // x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it + generated_asm.push_str(" mov x19, x0\n"); } _ => unimplemented!("prologue for {:?}", arch), } @@ -725,24 +751,14 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn epilogue(generated_asm: &mut String, arch: InlineAsmArch) { match arch { - InlineAsmArch::X86 => { - generated_asm.push_str(" pop ebp\n"); - generated_asm.push_str(" ret\n"); - } InlineAsmArch::X86_64 => { + generated_asm.push_str(" pop rbx\n"); generated_asm.push_str(" pop rbp\n"); generated_asm.push_str(" ret\n"); } - InlineAsmArch::RiscV32 => { - generated_asm.push_str(" lw s0, 0(sp)\n"); - generated_asm.push_str(" lw ra, 4(sp)\n"); - generated_asm.push_str(" addi sp, sp, 8\n"); - generated_asm.push_str(" ret\n"); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" ld s0, 0(sp)\n"); - generated_asm.push_str(" ld ra, 8(sp)\n"); - generated_asm.push_str(" addi sp, sp, 16\n"); + InlineAsmArch::AArch64 => { + generated_asm.push_str(" ldr x19, [sp, #24]\n"); + generated_asm.push_str(" ldp fp, lr, [sp], #32\n"); generated_asm.push_str(" ret\n"); } _ => unimplemented!("epilogue for {:?}", arch), @@ -751,11 +767,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn epilogue_noreturn(generated_asm: &mut String, arch: InlineAsmArch) { match arch { - InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + InlineAsmArch::X86_64 => { generated_asm.push_str(" ud2\n"); } - InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - generated_asm.push_str(" ebreak\n"); + InlineAsmArch::AArch64 => { + generated_asm.push_str(" brk #0x1"); } _ => unimplemented!("epilogue_noreturn for {:?}", arch), } @@ -768,25 +784,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { offset: Size, ) { match arch { - InlineAsmArch::X86 => { - write!(generated_asm, " mov [ebp+0x{:x}], ", offset.bytes()).unwrap(); - reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap(); - generated_asm.push('\n'); - } InlineAsmArch::X86_64 => { - write!(generated_asm, " mov [rbp+0x{:x}], ", offset.bytes()).unwrap(); + write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap(); reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); generated_asm.push('\n'); } - InlineAsmArch::RiscV32 => { - generated_asm.push_str(" sw "); - reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap(); - writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" sd "); - reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); - writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); + InlineAsmArch::AArch64 => { + generated_asm.push_str(" str "); + reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); + writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } _ => unimplemented!("save_register for {:?}", arch), } @@ -799,25 +805,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { offset: Size, ) { match arch { - InlineAsmArch::X86 => { - generated_asm.push_str(" mov "); - reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap(); - writeln!(generated_asm, ", [ebp+0x{:x}]", offset.bytes()).unwrap(); - } InlineAsmArch::X86_64 => { generated_asm.push_str(" mov "); reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); - writeln!(generated_asm, ", [rbp+0x{:x}]", offset.bytes()).unwrap(); + writeln!(generated_asm, ", [rbx+0x{:x}]", offset.bytes()).unwrap(); } - InlineAsmArch::RiscV32 => { - generated_asm.push_str(" lw "); - reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap(); - writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" ld "); - reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); - writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); + InlineAsmArch::AArch64 => { + generated_asm.push_str(" ldr "); + reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); + writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } _ => unimplemented!("restore_register for {:?}", arch), } diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index 63b5402f2b6d..c16947609980 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -1,10 +1,10 @@ //! Emulate LLVM intrinsics +use rustc_middle::ty::GenericArgsRef; + use crate::intrinsics::*; use crate::prelude::*; -use rustc_middle::ty::GenericArgsRef; - pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index c20a9915930e..0c211a06dc4a 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -1,10 +1,10 @@ //! Emulate AArch64 LLVM intrinsics +use rustc_middle::ty::GenericArgsRef; + use crate::intrinsics::*; use crate::prelude::*; -use rustc_middle::ty::GenericArgsRef; - pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, @@ -156,6 +156,41 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( }); } + // FIXME generalize vector types + "llvm.aarch64.neon.tbl1.v16i8" => { + intrinsic_args!(fx, args => (t, idx); intrinsic); + + let zero = fx.bcx.ins().iconst(types::I8, 0); + for i in 0..16 { + let idx_lane = idx.value_lane(fx, i).load_scalar(fx); + let is_zero = + fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, idx_lane, 16); + let t_idx = fx.bcx.ins().uextend(fx.pointer_type, idx_lane); + let t_lane = t.value_lane_dyn(fx, t_idx).load_scalar(fx); + let res = fx.bcx.ins().select(is_zero, zero, t_lane); + ret.place_lane(fx, i).to_ptr().store(fx, res, MemFlags::trusted()); + } + } + + // FIXME generalize vector types + "llvm.aarch64.neon.umaxp.v16i8" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + // FIXME add helper for horizontal pairwise operations + for i in 0..8 { + let lane1 = a.value_lane(fx, i * 2).load_scalar(fx); + let lane2 = a.value_lane(fx, i * 2 + 1).load_scalar(fx); + let res = fx.bcx.ins().umax(lane1, lane2); + ret.place_lane(fx, i).to_ptr().store(fx, res, MemFlags::trusted()); + } + for i in 0..8 { + let lane1 = b.value_lane(fx, i * 2).load_scalar(fx); + let lane2 = b.value_lane(fx, i * 2 + 1).load_scalar(fx); + let res = fx.bcx.ins().umax(lane1, lane2); + ret.place_lane(fx, 8 + i).to_ptr().store(fx, res, MemFlags::trusted()); + } + } + /* _ if intrinsic.starts_with("llvm.aarch64.neon.sshl.v") || intrinsic.starts_with("llvm.aarch64.neon.sqshl.v") diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index e62de6b61477..0c9a94e1c231 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1,10 +1,10 @@ //! Emulate x86 LLVM intrinsics +use rustc_middle::ty::GenericArgsRef; + use crate::intrinsics::*; use crate::prelude::*; -use rustc_middle::ty::GenericArgsRef; - pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, @@ -74,8 +74,10 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( }; let x = codegen_operand(fx, x); let y = codegen_operand(fx, y); - let kind = crate::constant::mir_operand_get_const_val(fx, kind) - .expect("llvm.x86.sse2.cmp.* kind not const"); + let kind = match kind { + Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0, + Operand::Copy(_) | Operand::Move(_) => unreachable!("{kind:?}"), + }; let flt_cc = match kind .try_to_bits(Size::from_bytes(1)) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 36e9ba9c7f8e..e94091e6a25e 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -18,17 +18,16 @@ mod llvm_aarch64; mod llvm_x86; mod simd; -pub(crate) use cpuid::codegen_cpuid_call; -pub(crate) use llvm::codegen_llvm_intrinsic_call; - +use cranelift_codegen::ir::AtomicRmwOp; use rustc_middle::ty; use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::GenericArgsRef; use rustc_span::symbol::{kw, sym, Symbol}; +pub(crate) use self::cpuid::codegen_cpuid_call; +pub(crate) use self::llvm::codegen_llvm_intrinsic_call; use crate::prelude::*; -use cranelift_codegen::ir::AtomicRmwOp; fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! { bug!("wrong number of args for intrinsic {}", intrinsic); diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 6efbe1498635..ea137c4ca1e8 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -148,7 +148,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let total_len = lane_count * 2; let indexes = - idx.iter().map(|idx| idx.unwrap_leaf().try_to_u16().unwrap()).collect::>(); + idx.iter().map(|idx| idx.unwrap_leaf().try_to_u32().unwrap()).collect::>(); for &idx in &indexes { assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len); @@ -216,8 +216,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let indexes = { use rustc_middle::mir::interpret::*; - let idx_const = crate::constant::mir_operand_get_const_val(fx, idx) - .expect("simd_shuffle idx not const"); + let idx_const = match idx { + Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0, + Operand::Copy(_) | Operand::Move(_) => unreachable!("{idx:?}"), + }; let idx_bytes = match idx_const { ConstValue::Indirect { alloc_id, offset } => { @@ -343,7 +345,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_lane); } - sym::simd_neg => { + sym::simd_neg + | sym::simd_bswap + | sym::simd_bitreverse + | sym::simd_ctlz + | sym::simd_cttz => { intrinsic_args!(fx, args => (a); intrinsic); if !a.layout().ty.is_simd() { @@ -351,16 +357,21 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - simd_for_each_lane( - fx, - a, - ret, - &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() { - ty::Int(_) => fx.bcx.ins().ineg(lane), - ty::Float(_) => fx.bcx.ins().fneg(lane), - _ => unreachable!(), - }, - ); + simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| match ( + lane_ty.kind(), + intrinsic, + ) { + (ty::Int(_), sym::simd_neg) => fx.bcx.ins().ineg(lane), + (ty::Float(_), sym::simd_neg) => fx.bcx.ins().fneg(lane), + + (ty::Uint(ty::UintTy::U8) | ty::Int(ty::IntTy::I8), sym::simd_bswap) => lane, + (ty::Uint(_) | ty::Int(_), sym::simd_bswap) => fx.bcx.ins().bswap(lane), + (ty::Uint(_) | ty::Int(_), sym::simd_bitreverse) => fx.bcx.ins().bitrev(lane), + (ty::Uint(_) | ty::Int(_), sym::simd_ctlz) => fx.bcx.ins().clz(lane), + (ty::Uint(_) | ty::Int(_), sym::simd_cttz) => fx.bcx.ins().ctz(lane), + + _ => unreachable!(), + }); } sym::simd_add diff --git a/src/lib.rs b/src/lib.rs index d01ded8abaa5..522fe7e425b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,8 @@ use std::any::Any; use std::cell::{Cell, RefCell}; use std::sync::Arc; +use cranelift_codegen::isa::TargetIsa; +use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::profiling::SelfProfilerRef; @@ -39,9 +41,6 @@ use rustc_session::config::OutputFilenames; use rustc_session::Session; use rustc_span::Symbol; -use cranelift_codegen::isa::TargetIsa; -use cranelift_codegen::settings::{self, Configurable}; - pub use crate::config::*; use crate::prelude::*; @@ -76,22 +75,6 @@ mod value_and_place; mod vtable; mod prelude { - pub(crate) use rustc_span::{FileNameDisplayPreference, Span}; - - pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; - pub(crate) use rustc_middle::bug; - pub(crate) use rustc_middle::mir::{self, *}; - pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout}; - pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, - TypeFoldable, TypeVisitableExt, UintTy, - }; - pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; - - pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; - - pub(crate) use rustc_index::Idx; - pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC}; pub(crate) use cranelift_codegen::ir::function::Function; pub(crate) use cranelift_codegen::ir::types; @@ -103,6 +86,18 @@ mod prelude { pub(crate) use cranelift_codegen::Context; pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module}; + pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; + pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; + pub(crate) use rustc_index::Idx; + pub(crate) use rustc_middle::bug; + pub(crate) use rustc_middle::mir::{self, *}; + pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout}; + pub(crate) use rustc_middle::ty::{ + self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, + TypeFoldable, TypeVisitableExt, UintTy, + }; + pub(crate) use rustc_span::{FileNameDisplayPreference, Span}; + pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; pub(crate) use crate::abi::*; pub(crate) use crate::base::{codegen_operand, codegen_place}; @@ -263,9 +258,9 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc "elf_gd", diff --git a/src/pointer.rs b/src/pointer.rs index b60e56720ed5..11ac6b946783 100644 --- a/src/pointer.rs +++ b/src/pointer.rs @@ -1,11 +1,10 @@ //! Defines [`Pointer`] which is used to improve the quality of the generated clif ir for pointer //! operations. -use crate::prelude::*; - +use cranelift_codegen::ir::immediates::Offset32; use rustc_target::abi::Align; -use cranelift_codegen::ir::immediates::Offset32; +use crate::prelude::*; /// A pointer pointing either to a certain address, a certain stack slot or nothing. #[derive(Copy, Clone, Debug)] diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 0ead50c34eac..da84e54a9163 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -63,8 +63,8 @@ use cranelift_codegen::{ ir::entities::AnyEntity, write::{FuncWriter, PlainWriter}, }; - use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::{OutputFilenames, OutputType}; use crate::prelude::*; @@ -80,15 +80,17 @@ impl CommentWriter { pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { let enabled = should_write_ir(tcx); let global_comments = if enabled { - vec![ - format!("symbol {}", tcx.symbol_name(instance).name), - format!("instance {:?}", instance), - format!( - "abi {:?}", - RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()) - ), - String::new(), - ] + with_no_trimmed_paths!({ + vec![ + format!("symbol {}", tcx.symbol_name(instance).name), + format!("instance {:?}", instance), + format!( + "abi {:?}", + RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()) + ), + String::new(), + ] + }) } else { vec![] }; diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 45893a4f3ac4..3a6a6c9e3f50 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -1,11 +1,10 @@ //! Definition of [`CValue`] and [`CPlace`] -use crate::prelude::*; - -use rustc_middle::ty::FnSig; - use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::immediates::Offset32; +use rustc_middle::ty::FnSig; + +use crate::prelude::*; fn codegen_field<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, @@ -310,7 +309,8 @@ impl<'tcx> CValue<'tcx> { fx.bcx.ins().iconcat(lsb, msb) } ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Ref(..) | ty::RawPtr(..) => { - fx.bcx.ins().iconst(clif_ty, const_val.to_bits(layout.size).unwrap() as i64) + let raw_val = const_val.size().truncate(const_val.to_bits(layout.size).unwrap()); + fx.bcx.ins().iconst(clif_ty, raw_val as i64) } ty::Float(FloatTy::F32) => { fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap())) From 70b8d15a854fb90d58a929f2b554f08a61c63b9a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 6 Oct 2023 20:35:52 +0000 Subject: [PATCH 017/107] Extend impl's def_span to include where clauses --- tests/ui/crashes/ice-6252.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index cb65360d1291..f929bec9583c 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -31,7 +31,7 @@ LL | const VAL: T; | ------------ `VAL` from trait ... LL | impl TypeVal for Multiply where N: TypeVal {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation error: aborting due to 3 previous errors From ed2f5baba6a62a0b535cfa6050356ad6cd5997e6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:36:23 +0000 Subject: [PATCH 018/107] Reuse determine_cgu_reuse from cg_ssa in cg_clif --- src/driver/aot.rs | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index cc2f5d727146..7a94c3aaef6a 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -8,6 +8,7 @@ use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; +use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -489,32 +490,3 @@ pub(crate) fn run_aot( concurrency_limiter, }) } - -// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953 -fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { - if !tcx.dep_graph.is_fully_enabled() { - return CguReuse::No; - } - - let work_product_id = &cgu.work_product_id(); - if tcx.dep_graph.previous_work_product(work_product_id).is_none() { - // We don't have anything cached for this CGU. This can happen - // if the CGU did not exist in the previous session. - return CguReuse::No; - } - - // Try to mark the CGU as green. If it we can do so, it means that nothing - // affecting the LLVM module has changed and we can re-use a cached version. - // If we compile with any kind of LTO, this means we can re-use the bitcode - // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only - // know that later). If we are not doing LTO, there is only one optimized - // version of each module, so we re-use that. - let dep_node = cgu.codegen_dep_node(tcx); - assert!( - !tcx.dep_graph.dep_node_exists(&dep_node), - "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", - cgu.name() - ); - - if tcx.try_mark_green(&dep_node) { CguReuse::PostLto } else { CguReuse::No } -} From e006e2c9c6cc09e88c35586f87a214ac8e6c91d1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Sep 2023 11:23:35 +0000 Subject: [PATCH 019/107] Remove cgu_reuse_tracker from Session This removes a bit of global mutable state --- src/driver/aot.rs | 68 +++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 7a94c3aaef6a..aaead1ffc5fd 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; +use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; @@ -15,7 +16,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; use rustc_session::Session; @@ -375,43 +375,47 @@ pub(crate) fn run_aot( } } + // Calculate the CGU reuse + let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { + cgus.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::>() + }); + + rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { + for (i, cgu) in cgus.iter().enumerate() { + let cgu_reuse = cgu_reuse[i]; + cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); + } + }); + let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len()); let modules = tcx.sess.time("codegen mono items", || { cgus.iter() - .map(|cgu| { - let cgu_reuse = if backend_config.disable_incr_cache { - CguReuse::No - } else { - determine_cgu_reuse(tcx, cgu) - }; - tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); - - match cgu_reuse { - CguReuse::No => { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( - dep_node, - tcx, - ( - backend_config.clone(), - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.sess.diagnostic()), - ), - module_codegen, - Some(rustc_middle::dep_graph::hash_result), - ) - .0 - } - CguReuse::PreLto => unreachable!(), - CguReuse::PostLto => { - concurrency_limiter.job_already_done(); - OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) - } + .enumerate() + .map(|(i, cgu)| match cgu_reuse[i] { + CguReuse::No => { + let dep_node = cgu.codegen_dep_node(tcx); + tcx.dep_graph + .with_task( + dep_node, + tcx, + ( + backend_config.clone(), + global_asm_config.clone(), + cgu.name(), + concurrency_limiter.acquire(tcx.sess.diagnostic()), + ), + module_codegen, + Some(rustc_middle::dep_graph::hash_result), + ) + .0 + } + CguReuse::PreLto => unreachable!(), + CguReuse::PostLto => { + concurrency_limiter.job_already_done(); + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) } }) .collect::>() From 3c0d3f2bf1a830a23e117382a094e6d13f41e58b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:49:10 +0000 Subject: [PATCH 020/107] Fix review comments --- src/driver/aot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index aaead1ffc5fd..49f51f9f956b 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -412,7 +412,7 @@ pub(crate) fn run_aot( ) .0 } - CguReuse::PreLto => unreachable!(), + CguReuse::PreLto => unreachable!("LTO not yet supported"), CguReuse::PostLto => { concurrency_limiter.job_already_done(); OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) From 0b60531e42a9afcd063447bf0543d8441b0da3f6 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 17 Sep 2023 13:22:22 +0200 Subject: [PATCH 021/107] [`map_identity`]: allow closure with type annotations --- clippy_utils/src/lib.rs | 18 ++++++++++++++++-- tests/ui/map_identity.fixed | 3 +++ tests/ui/map_identity.rs | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 7e2e4f74ca1d..e22bf11bb791 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2029,6 +2029,10 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks if an expression represents the identity function /// Only examines closures and `std::convert::identity` +/// +/// Closure bindings with type annotations and `std::convert::identity` with generic args +/// are not considered identity functions because they can guide type inference, +/// and removing it may lead to compile errors. pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks if a function's body represents the identity function. Looks for bodies of the form: /// * `|x| x` @@ -2070,8 +2074,18 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } match expr.kind { - ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), - _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), + ExprKind::Closure(&Closure { body, fn_decl, .. }) + if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) => + { + is_body_identity_function(cx, cx.tcx.hir().body(body)) + }, + ExprKind::Path(QPath::Resolved(_, path)) + if path.segments.iter().all(|seg| seg.infer_args) + && let Some(did) = path.res.opt_def_id() => + { + match_def_path(cx, did, &paths::CONVERT_IDENTITY) + }, + _ => false, } } diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed index cc40b1620587..e756d9b59354 100644 --- a/tests/ui/map_identity.fixed +++ b/tests/ui/map_identity.fixed @@ -17,6 +17,9 @@ fn main() { }); let _: Result = Ok(1); let _: Result = Ok(1).map_err(|a: u32| a * 42); + // : u32 guides type inference + let _ = Ok(1).map_err(|a: u32| a); + let _ = Ok(1).map_err(std::convert::identity::); } fn not_identity(x: &u16) -> u16 { diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs index 97a91aea6dc4..74cbaade4054 100644 --- a/tests/ui/map_identity.rs +++ b/tests/ui/map_identity.rs @@ -19,6 +19,9 @@ fn main() { }); let _: Result = Ok(1).map_err(|a| a); let _: Result = Ok(1).map_err(|a: u32| a * 42); + // : u32 guides type inference + let _ = Ok(1).map_err(|a: u32| a); + let _ = Ok(1).map_err(std::convert::identity::); } fn not_identity(x: &u16) -> u16 { From bba155ea9dac4f320303696572f552e80042889c Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:39:16 +0200 Subject: [PATCH 022/107] move changed logic to into its own util function --- .../src/methods/filter_map_identity.rs | 4 +- clippy_lints/src/methods/flat_map_identity.rs | 4 +- clippy_lints/src/methods/map_identity.rs | 4 +- clippy_utils/src/lib.rs | 71 +++++++++++-------- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 3337b250c0e7..20878f1e4dfe 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,7 +9,7 @@ use rustc_span::sym; use super::FILTER_MAP_IDENTITY; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) { span_lint_and_sugg( cx, FILTER_MAP_IDENTITY, diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 84a21de0ac86..8849a4f49420 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( flat_map_arg: &'tcx hir::Expr<'_>, flat_map_span: Span, ) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) { span_lint_and_sugg( cx, FLAT_MAP_IDENTITY, diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 7be1ce483f63..57581363cfa0 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -23,7 +23,7 @@ pub(super) fn check( if is_trait_method(cx, expr, sym::Iterator) || is_type_diagnostic_item(cx, caller_ty, sym::Result) || is_type_diagnostic_item(cx, caller_ty, sym::Option); - if is_expr_identity_function(cx, map_arg); + if is_expr_untyped_identity_function(cx, map_arg); if let Some(sugg_span) = expr.span.trim_start(caller.span); then { span_lint_and_sugg( diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e22bf11bb791..dc1b5a0a3244 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2027,36 +2027,31 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use)) } -/// Checks if an expression represents the identity function -/// Only examines closures and `std::convert::identity` +/// Checks if a function's body represents the identity function. Looks for bodies of the form: +/// * `|x| x` +/// * `|x| return x` +/// * `|x| { return x }` +/// * `|x| { return x; }` /// -/// Closure bindings with type annotations and `std::convert::identity` with generic args -/// are not considered identity functions because they can guide type inference, -/// and removing it may lead to compile errors. -pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - /// Checks if a function's body represents the identity function. Looks for bodies of the form: - /// * `|x| x` - /// * `|x| return x` - /// * `|x| { return x }` - /// * `|x| { return x; }` - fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { - let id = if_chain! { - if let [param] = func.params; - if let PatKind::Binding(_, id, _, _) = param.pat.kind; - then { - id - } else { - return false; - } - }; +/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. +fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { + let id = if_chain! { + if let [param] = func.params; + if let PatKind::Binding(_, id, _, _) = param.pat.kind; + then { + id + } else { + return false; + } + }; - let mut expr = func.value; - loop { - match expr.kind { - #[rustfmt::skip] + let mut expr = func.value; + loop { + match expr.kind { + #[rustfmt::skip] ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, ) | ExprKind::Ret(Some(e)) => expr = e, - #[rustfmt::skip] + #[rustfmt::skip] ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => { if_chain! { if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind; @@ -2068,11 +2063,16 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } } }, - _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(), - } + _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(), } } +} +/// This is the same as [`is_expr_identity_function`], but does not consider closures +/// with type annotations for its bindings (or similar) as identity functions: +/// * `|x: u8| x` +/// * `std::convert::identity::` +pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(&Closure { body, fn_decl, .. }) if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) => @@ -2089,6 +2089,21 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } } +/// Checks if an expression represents the identity function +/// Only examines closures and `std::convert::identity` +/// +/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want +/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't +/// have type annotations. This is important because removing a closure with bindings can +/// remove type information that helped type inference before, which can then lead to compile +/// errors. +pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), + _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), + } +} + /// Gets the node where an expression is either used, or it's type is unified with another branch. /// Returns both the node and the `HirId` of the closest child node. pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> { From 2bf3004f333721f757640e5796dd4cde126e9a70 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Mon, 2 Oct 2023 22:18:44 -0400 Subject: [PATCH 023/107] Install `awscli` on the aarch64-apple-darwin builder Unlike the other builders, this one doesn't come with it preinstalled. --- .github/workflows/ci.yml | 9 +++++++++ src/ci/github-actions/ci.yml | 4 ++++ src/ci/scripts/install-awscli.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100755 src/ci/scripts/install-awscli.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c207e7ea115..cf4b9e9dca0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,6 +93,9 @@ jobs: - name: show the current environment run: src/ci/scripts/dump-environment.sh if: success() && !env.SKIP_JOB + - name: install awscli + run: src/ci/scripts/install-awscli.sh + if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB @@ -458,6 +461,9 @@ jobs: - name: show the current environment run: src/ci/scripts/dump-environment.sh if: success() && !env.SKIP_JOB + - name: install awscli + run: src/ci/scripts/install-awscli.sh + if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB @@ -578,6 +584,9 @@ jobs: - name: show the current environment run: src/ci/scripts/dump-environment.sh if: success() && !env.SKIP_JOB + - name: install awscli + run: src/ci/scripts/install-awscli.sh + if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 93b07350ac17..3db4dd4cdb20 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -153,6 +153,10 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/dump-environment.sh <<: *step + - name: install awscli + run: src/ci/scripts/install-awscli.sh + <<: *step + - name: install sccache run: src/ci/scripts/install-sccache.sh <<: *step diff --git a/src/ci/scripts/install-awscli.sh b/src/ci/scripts/install-awscli.sh new file mode 100755 index 000000000000..b4a239fd3bc8 --- /dev/null +++ b/src/ci/scripts/install-awscli.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# This script downloads and installs the awscli binaries directly from +# Amazon. + +set -euo pipefail +IFS=$'\n\t' + +source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" + +AWS_VERSION="2.13.25" + +# Only the macOS arm64/aarch64 GitHub Actions runner needs to have AWS +# installed; other platforms have it preinstalled. + +if isMacOS; then + platform=$(uname -m) + case $platform in + x86_64) + ;; + arm64) + file="https://awscli.amazonaws.com/AWSCLIV2-${AWS_VERSION}.pkg" + retry curl -f "${file}" -o "AWSCLIV2.pkg" + sudo installer -pkg "AWSCLIV2.pkg" -target / + ;; + *) + echo "unsupported architecture: ${platform}" + exit 1 + esac +fi From 821b03d767e7da7442c21fdc12bb4ac7d5606956 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Mon, 2 Oct 2023 20:15:54 -0400 Subject: [PATCH 024/107] Use GitHub Actions M1 builder for aarch64-apple-darwin Additionally, this enables 1. building the documentation 2. Setting `rust.lto` to `thin` to match the x86_64 build --- .github/workflows/ci.yml | 7 +++---- src/ci/github-actions/ci.yml | 21 +++++++-------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf4b9e9dca0e..9bde9c4fbffc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -348,8 +348,8 @@ jobs: os: macos-13 - name: dist-aarch64-apple env: - SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false" + SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin" + RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_13.4.1.app USE_XCODE_CLANG: 1 @@ -359,8 +359,7 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - JEMALLOC_SYS_WITH_LG_PAGE: 14 - os: macos-13 + os: macos-13-xlarge - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 3db4dd4cdb20..5136aec9896f 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -91,6 +91,10 @@ x--expand-yaml-anchors--remove: os: macos-13 # We use the standard runner for now <<: *base-job + - &job-macos-m1 + os: macos-13-xlarge + <<: *base-job + - &job-windows-8c os: windows-2019-8core-32gb <<: *base-job @@ -527,17 +531,14 @@ jobs: # This target only needs to support 11.0 and up as nothing else supports the hardware - name: dist-aarch64-apple env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --stage 2 + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin RUST_CONFIGURE_ARGS: >- - --build=x86_64-apple-darwin - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler - --disable-docs --set rust.jemalloc --set llvm.ninja=false + --set rust.lto=thin RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_13.4.1.app USE_XCODE_CLANG: 1 @@ -547,15 +548,7 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - # Corresponds to 16K page size - # - # Shouldn't be needed if jemalloc-sys is updated to - # handle this platform like iOS or if we build on - # aarch64-apple-darwin itself. - # - # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237 - JEMALLOC_SYS_WITH_LG_PAGE: 14 - <<: *job-macos-xl + <<: *job-macos-m1 ###################### # Windows Builders # From 359fa9822b4130a97197df0d9cf8a642013cd9a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 14:02:42 +1100 Subject: [PATCH 025/107] Rejig some top-level `rustc_hir_pretty` functions. There are several that are unused and can be removed. And there are some calls to `to_string`, which can be expressed more nicely as a `foo_to_string` call, and then `to_string` need not be `pub`. (This requires adding `pat_to_string`). --- clippy_lints/src/matches/match_wild_err_arm.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index de911f7a0280..a2903e52ae08 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' if is_type_diagnostic_item(cx, ex_ty, sym::Result) { for arm in arms { if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { - let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); + let path_str = rustc_hir_pretty::qpath_to_string(path); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); let mut ident_bind_name = kw::Underscore; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index e53e146ec5db..01b850cdb113 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { cx, arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), - &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), + &rustc_hir_pretty::qpath_to_string(path), "function", ); } From a53f280bfc00800f3c3224508612db9be74bd160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 8 Jan 2023 20:24:17 +0000 Subject: [PATCH 026/107] Suggest `;` after bare `match` expression E0308 Fix #72634. --- compiler/rustc_hir_typeck/src/_match.rs | 1 + .../rustc_infer/src/infer/error_reporting/mod.rs | 13 +++++++++++++ compiler/rustc_middle/src/traits/mod.rs | 1 + tests/ui/suggestions/issue-81839.stderr | 15 +++++++++++---- tests/ui/wf/wf-unsafe-trait-obj-match.stderr | 4 ++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 81fe0cc489e3..6afdafb1b73b 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -121,6 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty, prior_arm_span, scrut_span: scrut.span, + scrut_hir_id: scrut.hir_id, source: match_src, prior_arms: other_arms.clone(), opt_suggest_box_span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 12dcb7118203..aa9980a3cf0a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -775,6 +775,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ref prior_arms, opt_suggest_box_span, scrut_span, + scrut_hir_id, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -842,6 +843,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { err.subdiagnostic(subdiag); } + if let Some(hir::Node::Expr(m)) = self.tcx.hir().find_parent(scrut_hir_id) + && let Some(hir::Node::Stmt(stmt)) = self.tcx.hir().find_parent(m.hir_id) + && let hir::StmtKind::Expr(_) = stmt.kind + { + err.span_suggestion_verbose( + stmt.span.shrink_to_hi(), + "consider using a semicolon here, but this will discard any values \ + in the match arms", + ";", + Applicability::MaybeIncorrect, + ); + } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 99b750c9afc8..071937c69dd3 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -541,6 +541,7 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, pub scrut_span: Span, + pub scrut_hir_id: hir::HirId, pub source: hir::MatchSource, pub prior_arms: Vec, pub opt_suggest_box_span: Option, diff --git a/tests/ui/suggestions/issue-81839.stderr b/tests/ui/suggestions/issue-81839.stderr index 6d0a0c7b3faa..238ee637c7d4 100644 --- a/tests/ui/suggestions/issue-81839.stderr +++ b/tests/ui/suggestions/issue-81839.stderr @@ -4,15 +4,22 @@ error[E0308]: `match` arms have incompatible types LL | / match num { LL | | 1 => { LL | | cx.answer_str("hi"); - | | -------------------- - | | | | - | | | help: consider removing this semicolon - | | this is found to be of type `()` + | | -------------------- this is found to be of type `()` LL | | } LL | | _ => cx.answer_str("hi"), | | ^^^^^^^^^^^^^^^^^^^ expected `()`, found future LL | | } | |_____- `match` arms have incompatible types + | +help: consider removing this semicolon + | +LL - cx.answer_str("hi"); +LL + cx.answer_str("hi") + | +help: consider using a semicolon here, but this will discard any values in the match arms + | +LL | }; + | + error: aborting due to previous error diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr index 66504e440600..d5b23572ff57 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -11,6 +11,10 @@ LL | | } | = note: expected reference `&S` found reference `&R` +help: consider using a semicolon here, but this will discard any values in the match arms + | +LL | }; + | + error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-unsafe-trait-obj-match.rs:26:21 From b5488f98503d77740fe59546921a4ed55eeb7e9e Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 12 Oct 2023 17:49:58 +0000 Subject: [PATCH 027/107] [`manual_is_ascii_check`]: Also check for `is_ascii_hexdigt` --- clippy_lints/src/manual_is_ascii_check.rs | 24 ++++++++++++++++++++--- tests/ui/manual_is_ascii_check.fixed | 4 ++++ tests/ui/manual_is_ascii_check.rs | 4 ++++ tests/ui/manual_is_ascii_check.stderr | 22 ++++++++++++++++----- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index f264424470da..9da20a28fba5 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -15,12 +15,13 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does /// Suggests to use dedicated built-in methods, - /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range + /// `is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding + /// ascii range /// /// ### Why is this bad? /// Using the built-in functions is more readable and makes it /// clear that it's not a specific subset of characters, but all - /// ASCII (lowercase|uppercase|digit) characters. + /// ASCII (lowercase|uppercase|digit|hexdigit) characters. /// ### Example /// ```rust /// fn main() { @@ -28,6 +29,7 @@ declare_clippy_lint! { /// assert!(matches!(b'X', b'A'..=b'Z')); /// assert!(matches!('2', '0'..='9')); /// assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + /// assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F')); /// /// ('0'..='9').contains(&'0'); /// ('a'..='z').contains(&'a'); @@ -41,6 +43,7 @@ declare_clippy_lint! { /// assert!(b'X'.is_ascii_uppercase()); /// assert!('2'.is_ascii_digit()); /// assert!('x'.is_ascii_alphabetic()); + /// assert!('C'.is_ascii_hexdigit()); /// /// '0'.is_ascii_digit(); /// 'a'.is_ascii_lowercase(); @@ -75,6 +78,12 @@ enum CharRange { FullChar, /// '0..=9' Digit, + /// 'a..=f' + LowerHexLetter, + /// 'A..=F' + UpperHexLetter, + /// '0..=9' | 'a..=f' | 'A..=F' + HexDigit, Otherwise, } @@ -116,7 +125,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha CharRange::LowerChar => Some("is_ascii_lowercase"), CharRange::FullChar => Some("is_ascii_alphabetic"), CharRange::Digit => Some("is_ascii_digit"), - CharRange::Otherwise => None, + CharRange::HexDigit => Some("is_ascii_hexdigit"), + CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None, } { let default_snip = ".."; let mut app = Applicability::MachineApplicable; @@ -141,6 +151,12 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) { CharRange::FullChar + } else if ranges.len() == 3 + && ranges.contains(&CharRange::Digit) + && ranges.contains(&CharRange::LowerHexLetter) + && ranges.contains(&CharRange::UpperHexLetter) + { + CharRange::HexDigit } else { CharRange::Otherwise } @@ -156,6 +172,8 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { match (&start_lit.node, &end_lit.node) { (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar, (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar, + (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter, + (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter, (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit, _ => CharRange::Otherwise, } diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index 5be2dd280b82..9c4bd335ad8b 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -33,6 +33,7 @@ fn msrv_1_23() { assert!(matches!(b'1', b'0'..=b'9')); assert!(matches!('X', 'A'..='Z')); assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F')); } #[clippy::msrv = "1.24"] @@ -40,14 +41,17 @@ fn msrv_1_24() { assert!(b'1'.is_ascii_digit()); assert!('X'.is_ascii_uppercase()); assert!('x'.is_ascii_alphabetic()); + assert!('x'.is_ascii_hexdigit()); } #[clippy::msrv = "1.46"] fn msrv_1_46() { const FOO: bool = matches!('x', '0'..='9'); + const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); } #[clippy::msrv = "1.47"] fn msrv_1_47() { const FOO: bool = 'x'.is_ascii_digit(); + const BAR: bool = 'x'.is_ascii_hexdigit(); } diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index f9249e22a026..785943cd24d2 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -33,6 +33,7 @@ fn msrv_1_23() { assert!(matches!(b'1', b'0'..=b'9')); assert!(matches!('X', 'A'..='Z')); assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F')); } #[clippy::msrv = "1.24"] @@ -40,14 +41,17 @@ fn msrv_1_24() { assert!(matches!(b'1', b'0'..=b'9')); assert!(matches!('X', 'A'..='Z')); assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F')); } #[clippy::msrv = "1.46"] fn msrv_1_46() { const FOO: bool = matches!('x', '0'..='9'); + const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); } #[clippy::msrv = "1.47"] fn msrv_1_47() { const FOO: bool = matches!('x', '0'..='9'); + const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); } diff --git a/tests/ui/manual_is_ascii_check.stderr b/tests/ui/manual_is_ascii_check.stderr index e0fb46e59fa1..f69522c5ff84 100644 --- a/tests/ui/manual_is_ascii_check.stderr +++ b/tests/ui/manual_is_ascii_check.stderr @@ -98,28 +98,40 @@ LL | ('A'..='Z').contains(cool_letter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:40:13 + --> $DIR/manual_is_ascii_check.rs:41:13 | LL | assert!(matches!(b'1', b'0'..=b'9')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:41:13 + --> $DIR/manual_is_ascii_check.rs:42:13 | LL | assert!(matches!('X', 'A'..='Z')); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:42:13 + --> $DIR/manual_is_ascii_check.rs:43:13 | LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()` error: manual check for common ascii range - --> $DIR/manual_is_ascii_check.rs:52:23 + --> $DIR/manual_is_ascii_check.rs:44:13 + | +LL | assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()` + +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:55:23 | LL | const FOO: bool = matches!('x', '0'..='9'); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()` -error: aborting due to 20 previous errors +error: manual check for common ascii range + --> $DIR/manual_is_ascii_check.rs:56:23 + | +LL | const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()` + +error: aborting due to 22 previous errors From eb6fb18a99b54455505ea6be7f0484eb8af62189 Mon Sep 17 00:00:00 2001 From: koka Date: Fri, 13 Oct 2023 17:07:29 +0900 Subject: [PATCH 028/107] Avoid `panic!`, omit instead --- clippy_lints/src/utils/author.rs | 18 +++++++----- tests/ui/author/macro_in_closure.rs | 5 ++++ tests/ui/author/macro_in_closure.stdout | 39 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/ui/author/macro_in_closure.rs create mode 100644 tests/ui/author/macro_in_closure.stdout diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index f02c33cc6743..aecb0c6dbfa1 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -268,8 +268,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { fn qpath(&self, qpath: &Binding<&QPath<'_>>) { if let QPath::LangItem(lang_item, ..) = *qpath.value { chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))"); - } else { - chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value)); + } else if let Ok(path) = path_to_string(qpath.value) { + chain!(self, "match_qpath({qpath}, &[{}])", path); } } @@ -738,8 +738,8 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { get_attr(cx.sess(), attrs, "author").count() > 0 } -fn path_to_string(path: &QPath<'_>) -> String { - fn inner(s: &mut String, path: &QPath<'_>) { +fn path_to_string(path: &QPath<'_>) -> Result { + fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> { match *path { QPath::Resolved(_, path) => { for (i, segment) in path.segments.iter().enumerate() { @@ -751,16 +751,18 @@ fn path_to_string(path: &QPath<'_>) -> String { }, QPath::TypeRelative(ty, segment) => match &ty.kind { hir::TyKind::Path(inner_path) => { - inner(s, inner_path); + inner(s, inner_path)?; *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); }, other => write!(s, "/* unimplemented: {other:?}*/").unwrap(), }, - QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"), + QPath::LangItem(..) => return Err(()), } + + Ok(()) } let mut s = String::new(); - inner(&mut s, path); - s + inner(&mut s, path)?; + Ok(s) } diff --git a/tests/ui/author/macro_in_closure.rs b/tests/ui/author/macro_in_closure.rs new file mode 100644 index 000000000000..444e6a12165d --- /dev/null +++ b/tests/ui/author/macro_in_closure.rs @@ -0,0 +1,5 @@ +fn main() { + #[clippy::author] + let print_text = |x| println!("{}", x); + print_text("hello"); +} diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout new file mode 100644 index 000000000000..9ab71986f40f --- /dev/null +++ b/tests/ui/author/macro_in_closure.stdout @@ -0,0 +1,39 @@ +if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind + && let FnRetTy::DefaultReturn(_) = fn_decl.output + && expr = &cx.tcx.hir().body(body_id).value + && let ExprKind::Block(block, None) = expr.kind + && block.stmts.len() == 1 + && let StmtKind::Semi(e) = block.stmts[0].kind + && let ExprKind::Call(func, args) = e.kind + && let ExprKind::Path(ref qpath) = func.kind + && match_qpath(qpath, &["$crate", "io", "_print"]) + && args.len() == 1 + && let ExprKind::Call(func1, args1) = args[0].kind + && let ExprKind::Path(ref qpath1) = func1.kind + && args1.len() == 2 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::Array(elements) = inner.kind + && elements.len() == 2 + && let ExprKind::Lit(ref lit) = elements[0].kind + && let LitKind::Str(s, _) = lit.node + && s.as_str() == "" + && let ExprKind::Lit(ref lit1) = elements[1].kind + && let LitKind::Str(s1, _) = lit1.node + && s1.as_str() == "\n" + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind + && let ExprKind::Array(elements1) = inner1.kind + && elements1.len() == 1 + && let ExprKind::Call(func2, args2) = elements1[0].kind + && let ExprKind::Path(ref qpath2) = func2.kind + && args2.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind + && let ExprKind::Path(ref qpath3) = inner2.kind + && match_qpath(qpath3, &["x"]) + && block.expr.is_none() + && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind + && name.as_str() == "print_text" +{ + // report your lint here +} From 9fc717dea3718dc982e33973aa3fd78a77668733 Mon Sep 17 00:00:00 2001 From: koka Date: Fri, 13 Oct 2023 17:12:41 +0900 Subject: [PATCH 029/107] add test for macro-in-loop --- tests/ui/author/macro_in_loop.rs | 8 +++++ tests/ui/author/macro_in_loop.stdout | 48 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/ui/author/macro_in_loop.rs create mode 100644 tests/ui/author/macro_in_loop.stdout diff --git a/tests/ui/author/macro_in_loop.rs b/tests/ui/author/macro_in_loop.rs new file mode 100644 index 000000000000..8a520501f8dd --- /dev/null +++ b/tests/ui/author/macro_in_loop.rs @@ -0,0 +1,8 @@ +#![feature(stmt_expr_attributes)] + +fn main() { + #[clippy::author] + for i in 0..1 { + println!("{}", i); + } +} diff --git a/tests/ui/author/macro_in_loop.stdout b/tests/ui/author/macro_in_loop.stdout new file mode 100644 index 000000000000..bd054b6abc43 --- /dev/null +++ b/tests/ui/author/macro_in_loop.stdout @@ -0,0 +1,48 @@ +if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr) + && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind + && name.as_str() == "i" + && let ExprKind::Struct(qpath, fields, None) = arg.kind + && matches!(qpath, QPath::LangItem(LangItem::Range, _)) + && fields.len() == 2 + && fields[0].ident.as_str() == "start" + && let ExprKind::Lit(ref lit) = fields[0].expr.kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && fields[1].ident.as_str() == "end" + && let ExprKind::Lit(ref lit1) = fields[1].expr.kind + && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node + && let ExprKind::Block(block, None) = body.kind + && block.stmts.len() == 1 + && let StmtKind::Semi(e) = block.stmts[0].kind + && let ExprKind::Block(block1, None) = e.kind + && block1.stmts.len() == 1 + && let StmtKind::Semi(e1) = block1.stmts[0].kind + && let ExprKind::Call(func, args) = e1.kind + && let ExprKind::Path(ref qpath1) = func.kind + && match_qpath(qpath1, &["$crate", "io", "_print"]) + && args.len() == 1 + && let ExprKind::Call(func1, args1) = args[0].kind + && let ExprKind::Path(ref qpath2) = func1.kind + && args1.len() == 2 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::Array(elements) = inner.kind + && elements.len() == 2 + && let ExprKind::Lit(ref lit2) = elements[0].kind + && let LitKind::Str(s, _) = lit2.node + && s.as_str() == "" + && let ExprKind::Lit(ref lit3) = elements[1].kind + && let LitKind::Str(s1, _) = lit3.node + && s1.as_str() == "\n" + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind + && let ExprKind::Array(elements1) = inner1.kind + && elements1.len() == 1 + && let ExprKind::Call(func2, args2) = elements1[0].kind + && let ExprKind::Path(ref qpath3) = func2.kind + && args2.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind + && let ExprKind::Path(ref qpath4) = inner2.kind + && match_qpath(qpath4, &["i"]) + && block1.expr.is_none() + && block.expr.is_none() +{ + // report your lint here +} From d1796054fe60127b372da784d7410593f9143453 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 13 Oct 2023 10:09:58 -0300 Subject: [PATCH 030/107] Document conflicting lints --- book/src/development/adding_lints.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e001197842bd..3dc717da8713 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -30,6 +30,7 @@ because that's clearly a non-descriptive name. - [Documentation](#documentation) - [Running rustfmt](#running-rustfmt) - [Debugging](#debugging) + - [Conflicting lints](#conflicting-lints) - [PR Checklist](#pr-checklist) - [Adding configuration to a lint](#adding-configuration-to-a-lint) - [Cheat Sheet](#cheat-sheet) @@ -612,6 +613,20 @@ output in the `stdout` part. [`dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html +## Conflicting lints + +There are several lints that deal with the same pattern but suggest different approaches. In other words, some lints +may suggest modifications that go in the opposite direction to what some other lints already propose for the same +code, creating conflicting diagnostics. + +When you are creating a lint that ends up in this scenario, the following tips should be encouraged to guide +classification: + +* The only case where they should be in the same category is if that category is `restriction`. For example, +`semicolon_inside_block` and `semicolon_outside_block`. +* For all the other cases, they should be in different categories with different levels of allowance. For example, +`implicit_return` (restriction, allow) and `needless_return` (style, warn). + ## PR Checklist Before submitting your PR make sure you followed all the basic requirements: From 8c0870de7fc27ba4b0f8ea195140db33eab8d500 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 13 Oct 2023 10:31:02 -0300 Subject: [PATCH 031/107] Address comment --- book/src/development/adding_lints.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 3dc717da8713..55c0e105b307 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -627,6 +627,10 @@ classification: * For all the other cases, they should be in different categories with different levels of allowance. For example, `implicit_return` (restriction, allow) and `needless_return` (style, warn). +For lints that are in different categories, it is also recommended that at least one of them should be in the +`restriction` category. The reason for this is that the `restriction` group is the only group where we don't +recommend to enable the entire set, but cherry pick lints out of. + ## PR Checklist Before submitting your PR make sure you followed all the basic requirements: From 1ffd09af2975b940fc83ad1dc6ee17ff36e564ba Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 13 Sep 2023 16:04:42 +0000 Subject: [PATCH 032/107] Stabilize AFIT and RPITIT --- tests/ui/implied_bounds_in_impls.fixed | 1 - tests/ui/implied_bounds_in_impls.rs | 1 - tests/ui/implied_bounds_in_impls.stderr | 32 ++++++++++++------------- tests/ui/unused_async.rs | 1 - tests/ui/unused_async.stderr | 10 ++++---- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/tests/ui/implied_bounds_in_impls.fixed b/tests/ui/implied_bounds_in_impls.fixed index a50fa0ccf6e7..fa117aaddcd6 100644 --- a/tests/ui/implied_bounds_in_impls.fixed +++ b/tests/ui/implied_bounds_in_impls.fixed @@ -1,6 +1,5 @@ #![warn(clippy::implied_bounds_in_impls)] #![allow(dead_code)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/implied_bounds_in_impls.rs b/tests/ui/implied_bounds_in_impls.rs index e74ed4425b81..c96aac151a7d 100644 --- a/tests/ui/implied_bounds_in_impls.rs +++ b/tests/ui/implied_bounds_in_impls.rs @@ -1,6 +1,5 @@ #![warn(clippy::implied_bounds_in_impls)] #![allow(dead_code)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/implied_bounds_in_impls.stderr b/tests/ui/implied_bounds_in_impls.stderr index 72dc2a183a38..fb44f2aba174 100644 --- a/tests/ui/implied_bounds_in_impls.stderr +++ b/tests/ui/implied_bounds_in_impls.stderr @@ -1,5 +1,5 @@ error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:13:36 + --> $DIR/implied_bounds_in_impls.rs:12:36 | LL | fn deref_derefmut(x: T) -> impl Deref + DerefMut { | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + fn deref_derefmut(x: T) -> impl DerefMut { | error: this bound is already specified as the supertrait of `GenericSubtrait` - --> $DIR/implied_bounds_in_impls.rs:30:37 + --> $DIR/implied_bounds_in_impls.rs:29:37 | LL | fn generics_implied() -> impl GenericTrait + GenericSubtrait | ^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + fn generics_implied() -> impl GenericSubtrait | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> $DIR/implied_bounds_in_impls.rs:36:40 + --> $DIR/implied_bounds_in_impls.rs:35:40 | LL | fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + fn generics_implied_multi() -> impl GenericTrait2 + GenericSubtrait<( | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> $DIR/implied_bounds_in_impls.rs:36:60 + --> $DIR/implied_bounds_in_impls.rs:35:60 | LL | fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + fn generics_implied_multi() -> impl GenericTrait + GenericSubtrait< | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> $DIR/implied_bounds_in_impls.rs:38:44 + --> $DIR/implied_bounds_in_impls.rs:37:44 | LL | fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + fn generics_implied_multi2() -> impl GenericTrait2 + GenericSubtra | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> $DIR/implied_bounds_in_impls.rs:38:62 + --> $DIR/implied_bounds_in_impls.rs:37:62 | LL | fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + fn generics_implied_multi2() -> impl GenericTrait + GenericSubtrai | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, ()>` - --> $DIR/implied_bounds_in_impls.rs:48:28 + --> $DIR/implied_bounds_in_impls.rs:47:28 | LL | fn generics_same() -> impl GenericTrait + GenericSubtrait<(), i32, ()> {} | ^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + fn generics_same() -> impl GenericSubtrait<(), i32, ()> {} | error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:52:20 + --> $DIR/implied_bounds_in_impls.rs:51:20 | LL | fn f() -> impl Deref + DerefMut; | ^^^^^ @@ -97,7 +97,7 @@ LL + fn f() -> impl DerefMut; | error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:57:20 + --> $DIR/implied_bounds_in_impls.rs:56:20 | LL | fn f() -> impl Deref + DerefMut { | ^^^^^ @@ -109,7 +109,7 @@ LL + fn f() -> impl DerefMut { | error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:63:20 + --> $DIR/implied_bounds_in_impls.rs:62:20 | LL | fn f() -> impl Deref + DerefMut { | ^^^^^ @@ -121,7 +121,7 @@ LL + fn f() -> impl DerefMut { | error: this bound is already specified as the supertrait of `PartialOrd` - --> $DIR/implied_bounds_in_impls.rs:74:41 + --> $DIR/implied_bounds_in_impls.rs:73:41 | LL | fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {} | ^^^^^^^^^ @@ -133,7 +133,7 @@ LL + fn default_generic_param1() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `PartialOrd` - --> $DIR/implied_bounds_in_impls.rs:75:54 + --> $DIR/implied_bounds_in_impls.rs:74:54 | LL | fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {} | ^^^^^^^^^ @@ -145,7 +145,7 @@ LL + fn default_generic_param2() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `DoubleEndedIterator` - --> $DIR/implied_bounds_in_impls.rs:88:26 + --> $DIR/implied_bounds_in_impls.rs:87:26 | LL | fn my_iter() -> impl Iterator + DoubleEndedIterator { | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + fn my_iter() -> impl DoubleEndedIterator { | error: this bound is already specified as the supertrait of `Copy` - --> $DIR/implied_bounds_in_impls.rs:93:27 + --> $DIR/implied_bounds_in_impls.rs:92:27 | LL | fn f() -> impl Copy + Clone { | ^^^^^ @@ -169,7 +169,7 @@ LL + fn f() -> impl Copy { | error: this bound is already specified as the supertrait of `Trait2` - --> $DIR/implied_bounds_in_impls.rs:107:21 + --> $DIR/implied_bounds_in_impls.rs:106:21 | LL | fn f2() -> impl Trait1 + Trait2 {} | ^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + fn f2() -> impl Trait2 {} | error: this bound is already specified as the supertrait of `Trait4` - --> $DIR/implied_bounds_in_impls.rs:122:21 + --> $DIR/implied_bounds_in_impls.rs:121:21 | LL | fn f3() -> impl Trait3 + Trait4 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs index 71722e9afd0b..7ec8a3adb4cd 100644 --- a/tests/ui/unused_async.rs +++ b/tests/ui/unused_async.rs @@ -1,5 +1,4 @@ #![warn(clippy::unused_async)] -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr index 077e8cacce14..c97a76a55cbe 100644 --- a/tests/ui/unused_async.stderr +++ b/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:13:5 + --> $DIR/unused_async.rs:12:5 | LL | / async fn async_block_await() { LL | | @@ -11,7 +11,7 @@ LL | | } | = help: consider removing the `async` from this function note: `await` used in an async block, which does not require the enclosing function to be `async` - --> $DIR/unused_async.rs:16:23 + --> $DIR/unused_async.rs:15:23 | LL | ready(()).await; | ^^^^^ @@ -19,7 +19,7 @@ LL | ready(()).await; = help: to override `-D warnings` add `#[allow(clippy::unused_async)]` error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:46:5 + --> $DIR/unused_async.rs:45:5 | LL | async fn f3() {} | ^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | async fn f3() {} = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:59:1 + --> $DIR/unused_async.rs:58:1 | LL | / async fn foo() -> i32 { LL | | @@ -38,7 +38,7 @@ LL | | } = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:71:5 + --> $DIR/unused_async.rs:70:5 | LL | / async fn unused(&self) -> i32 { LL | | From abc9f0d6fb38370f689754df81f4f61bed8f0cc3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Oct 2023 12:29:13 +0000 Subject: [PATCH 033/107] Update rand test This allows removing a patch for a test that requires unwinding support --- build_system/tests.rs | 4 ++-- patches/0002-rand-Disable-failing-test.patch | 24 -------------------- 2 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 patches/0002-rand-Disable-failing-test.patch diff --git a/build_system/tests.rs b/build_system/tests.rs index 95ff6b754220..e61e947d3f97 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -104,8 +104,8 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rust-random", "rand", - "f3dd0b885c4597b9617ca79987a0dd899ab29fcb", - "3f869e4fcd602b66", + "9a02c819cc1e4ec6959ae25eafbb5cf6acb68234", + "4934f0afb1d1c2ca", "rand", ); diff --git a/patches/0002-rand-Disable-failing-test.patch b/patches/0002-rand-Disable-failing-test.patch deleted file mode 100644 index ae13ab3b0ca6..000000000000 --- a/patches/0002-rand-Disable-failing-test.patch +++ /dev/null @@ -1,24 +0,0 @@ -From a8fb97120d71252538b6b026695df40d02696bdb Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Sat, 15 Aug 2020 20:04:38 +0200 -Subject: [PATCH] [rand] Disable failing test - ---- - src/distributions/uniform.rs | 1 + - 1 file changed, 1 insertion(+), 0 deletions(-) - -diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs -index 480b859..c80bb6f 100644 ---- a/src/distributions/uniform.rs -+++ b/src/distributions/uniform.rs -@@ -1314,6 +1314,7 @@ mod tests { - not(target_arch = "wasm32"), - not(target_arch = "asmjs") - ))] -+ #[ignore] // Requires unwinding - fn test_float_assertions() { - use super::SampleUniform; - use std::panic::catch_unwind; --- -2.20.1 - From f06831441b32604edc8ae5f7fc5080ebe710a3b6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Oct 2023 12:38:18 +0000 Subject: [PATCH 034/107] Remove portable-simd custom lock file portable-simd has a Cargo.lock already checked in now. --- build_system/tests.rs | 2 +- patches/portable-simd-lock.toml | 304 -------------------------------- 2 files changed, 1 insertion(+), 305 deletions(-) delete mode 100644 patches/portable-simd-lock.toml diff --git a/build_system/tests.rs b/build_system/tests.rs index e61e947d3f97..1e24d1b113fe 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -125,7 +125,7 @@ pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( "rust-lang", "portable-simd", "4825b2a64d765317066948867e8714674419359b", - "8b188cc41f5af835", + "9e67d07c00f5fb0b", "portable-simd", ); diff --git a/patches/portable-simd-lock.toml b/patches/portable-simd-lock.toml deleted file mode 100644 index 5c9dc7b361f9..000000000000 --- a/patches/portable-simd-lock.toml +++ /dev/null @@ -1,304 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "core_simd" -version = "0.1.0" -dependencies = [ - "proptest", - "std_float", - "test_helpers", - "wasm-bindgen", - "wasm-bindgen-test", -] - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proptest" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f" -dependencies = [ - "bitflags", - "byteorder", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_xorshift" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -dependencies = [ - "rand_core", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "std_float" -version = "0.1.0" -dependencies = [ - "core_simd", -] - -[[package]] -name = "syn" -version = "2.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "test_helpers" -version = "0.1.0" -dependencies = [ - "proptest", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] From 62bf33a9c670a7cc9273d35fc52c8f0d5a0b115b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Oct 2023 12:41:44 +0000 Subject: [PATCH 035/107] Ensure we don't overwrite an existing Cargo.lock when fetching an external git repo --- build_system/prepare.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 16e7a4bafaee..c68968b4fde2 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -143,6 +143,7 @@ impl GitRepo { RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name)); let target_lockfile = download_dir.join("Cargo.lock"); if source_lockfile.exists() { + assert!(!target_lockfile.exists()); fs::copy(source_lockfile, target_lockfile).unwrap(); } else { assert!(target_lockfile.exists()); From 4a24eccfba25311b43e0a1191c8c9b3ac86b6838 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Oct 2023 13:09:06 +0000 Subject: [PATCH 036/107] Remove no longer necessary rand patch These tests got fixed fixed at some point. --- ...003-rand-Disable-rand-tests-on-mingw.patch | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 patches/0003-rand-Disable-rand-tests-on-mingw.patch diff --git a/patches/0003-rand-Disable-rand-tests-on-mingw.patch b/patches/0003-rand-Disable-rand-tests-on-mingw.patch deleted file mode 100644 index eb452c5cd377..000000000000 --- a/patches/0003-rand-Disable-rand-tests-on-mingw.patch +++ /dev/null @@ -1,47 +0,0 @@ -From eec874c889b8d24e5ad50faded24288150f057b1 Mon Sep 17 00:00:00 2001 -From: Afonso Bordado -Date: Tue, 27 Sep 2022 08:13:58 +0100 -Subject: [PATCH] Disable rand tests on mingw - ---- - rand_distr/src/pareto.rs | 2 ++ - rand_distr/tests/value_stability.rs | 4 ++++ - 2 files changed, 6 insertions(+) - -diff --git a/rand_distr/src/pareto.rs b/rand_distr/src/pareto.rs -index 217899e..9cedeb7 100644 ---- a/rand_distr/src/pareto.rs -+++ b/rand_distr/src/pareto.rs -@@ -107,6 +107,8 @@ mod tests { - } - - #[test] -+ // This is broken on x86_64-pc-windows-gnu presumably due to a broken powf implementation -+ #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)] - fn value_stability() { - fn test_samples>( - distr: D, thresh: F, expected: &[F], -diff --git a/rand_distr/tests/value_stability.rs b/rand_distr/tests/value_stability.rs -index 192ba74..0101ace 100644 ---- a/rand_distr/tests/value_stability.rs -+++ b/rand_distr/tests/value_stability.rs -@@ -72,6 +72,8 @@ fn unit_disc_stability() { - } - - #[test] -+// This is broken on x86_64-pc-windows-gnu -+#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)] - fn pareto_stability() { - test_samples(213, Pareto::new(1.0, 1.0).unwrap(), &[ - 1.0423688f32, 2.1235929, 4.132709, 1.4679428, -@@ -143,6 +145,8 @@ fn inverse_gaussian_stability() { - } - - #[test] -+// This is broken on x86_64-pc-windows-gnu -+#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)] - fn gamma_stability() { - // Gamma has 3 cases: shape == 1, shape < 1, shape > 1 - test_samples(223, Gamma::new(1.0, 5.0).unwrap(), &[ --- -2.25.1 From 5a9b81a91e9918d4464da7bb496f78d586881c46 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Oct 2023 13:37:03 +0000 Subject: [PATCH 037/107] Re-enable a bunch of fixed rustc tests --- scripts/test_rustc_tests.sh | 4 +--- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 3b2a12ec0280..e6a8dc99cbdc 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -44,10 +44,8 @@ rm tests/ui/proc-macro/allowed-signatures.rs rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs # vendor intrinsics -rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected +rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant" -rm tests/ui/simd/intrinsic/generic-bswap-byte.rs # simd_bswap not yet implemented -rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # many missing simd intrinsics # exotic linkages rm tests/ui/issues/issue-33992.rs # unsupported linkages diff --git a/src/lib.rs b/src/lib.rs index 522fe7e425b9..1161e859a3d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,7 +186,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { - vec![] + vec![] // FIXME necessary for #[cfg(target_feature] } fn print_version(&self) { From ca53d2e8bbdfc75820954ec2ad9e087e82a72142 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Oct 2023 13:46:55 +0000 Subject: [PATCH 038/107] Change producer string to have the rustc producer string as prefix This fixes the comment-section run-make test --- scripts/test_rustc_tests.sh | 2 -- src/debuginfo/mod.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index e6a8dc99cbdc..4b6d5bd97b85 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -27,8 +27,6 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # missing features # ================ -rm -r tests/run-make/comment-section # cg_clif doesn't yet write the .comment section - # requires stack unwinding # FIXME add needs-unwind to these tests rm -r tests/run-make/libtest-junit diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 9e78cc259ce1..dd0c14dae238 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -20,7 +20,7 @@ use crate::prelude::*; pub(crate) fn producer() -> String { format!( - "cg_clif (rustc {}, cranelift {})", + "rustc version {} with cranelift {}", rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), cranelift_codegen::VERSION, ) From 272c914bddac0ee83837dc19aa49ca647c8bffcd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Oct 2023 16:30:23 +0200 Subject: [PATCH 039/107] Distinguish user patterns from reconstructed witnesses --- compiler/rustc_mir_build/src/errors.rs | 4 +- .../src/thir/pattern/check_match.rs | 18 +- .../src/thir/pattern/deconstruct_pat.rs | 238 ++++++++++-------- .../src/thir/pattern/usefulness.rs | 107 ++++---- 4 files changed, 200 insertions(+), 167 deletions(-) diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 4f98932a88d4..c09dd1864185 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,6 +1,6 @@ use crate::{ fluent_generated as fluent, - thir::pattern::{deconstruct_pat::DeconstructedPat, MatchCheckCtxt}, + thir::pattern::{deconstruct_pat::WitnessPat, MatchCheckCtxt}, }; use rustc_errors::{ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, @@ -810,7 +810,7 @@ impl<'tcx> Uncovered<'tcx> { pub fn new<'p>( span: Span, cx: &MatchCheckCtxt<'p, 'tcx>, - witnesses: Vec>, + witnesses: Vec>, ) -> Self { let witness_1 = witnesses.get(0).unwrap().to_pat(cx); Self { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 93434dd3cc29..f3568b682a4b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,4 +1,4 @@ -use super::deconstruct_pat::{Constructor, DeconstructedPat}; +use super::deconstruct_pat::{Constructor, DeconstructedPat, WitnessPat}; use super::usefulness::{ compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport, }; @@ -661,8 +661,8 @@ fn report_arm_reachability<'p, 'tcx>( } } -fn collect_non_exhaustive_tys<'p, 'tcx>( - pat: &DeconstructedPat<'p, 'tcx>, +fn collect_non_exhaustive_tys<'tcx>( + pat: &WitnessPat<'tcx>, non_exhaustive_tys: &mut FxHashSet>, ) { if matches!(pat.ctor(), Constructor::NonExhaustive) { @@ -678,7 +678,7 @@ fn non_exhaustive_match<'p, 'tcx>( thir: &Thir<'tcx>, scrut_ty: Ty<'tcx>, sp: Span, - witnesses: Vec>, + witnesses: Vec>, arms: &[ArmId], expr_span: Span, ) -> ErrorGuaranteed { @@ -860,10 +860,10 @@ fn non_exhaustive_match<'p, 'tcx>( pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, - witnesses: &[DeconstructedPat<'p, 'tcx>], + witnesses: &[WitnessPat<'tcx>], ) -> String { const LIMIT: usize = 3; - let pat_to_str = |pat: &DeconstructedPat<'p, 'tcx>| pat.to_pat(cx).to_string(); + let pat_to_str = |pat: &WitnessPat<'tcx>| pat.to_pat(cx).to_string(); match witnesses { [] => bug!(), [witness] => format!("`{}`", witness.to_pat(cx)), @@ -880,7 +880,7 @@ pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( } pub(crate) fn pattern_not_covered_label( - witnesses: &[DeconstructedPat<'_, '_>], + witnesses: &[WitnessPat<'_>], joined_patterns: &str, ) -> String { format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns) @@ -891,7 +891,7 @@ fn adt_defined_here<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, err: &mut Diagnostic, ty: Ty<'tcx>, - witnesses: &[DeconstructedPat<'p, 'tcx>], + witnesses: &[WitnessPat<'tcx>], ) { let ty = ty.peel_refs(); if let ty::Adt(def, _) = ty.kind() { @@ -922,7 +922,7 @@ fn adt_defined_here<'p, 'tcx>( fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( cx: &MatchCheckCtxt<'p, 'tcx>, def: AdtDef<'tcx>, - patterns: impl Iterator>, + patterns: impl Iterator>, ) -> Vec { use Constructor::*; let mut covered = vec![]; diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a7a000ba31c6..818a8ff27c81 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1312,9 +1312,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Values and patterns can be represented as a constructor applied to some fields. This represents /// a pattern in this form. -/// This also keeps track of whether the pattern has been found reachable during analysis. For this -/// reason we should be careful not to clone patterns for which we care about that. Use -/// `clone_and_forget_reachability` if you're sure. +/// This also uses interior mutability to keep track of whether the pattern has been found reachable +/// during analysis. For this reason they cannot be cloned. +/// A `DeconstructedPat` will almost always come from user input; the only exception are some +/// `Wildcard`s introduced during specialization. pub(crate) struct DeconstructedPat<'p, 'tcx> { ctor: Constructor<'tcx>, fields: Fields<'p, 'tcx>, @@ -1337,20 +1338,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) } } - /// Construct a pattern that matches everything that starts with this constructor. - /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern - /// `Some(_)`. - pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { - let fields = Fields::wildcards(pcx, &ctor); - DeconstructedPat::new(ctor, fields, pcx.ty, pcx.span) - } - - /// Clone this value. This method emphasizes that cloning loses reachability information and - /// should be done carefully. - pub(super) fn clone_and_forget_reachability(&self) -> Self { - DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span) - } - pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self { let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); let ctor; @@ -1529,95 +1516,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { DeconstructedPat::new(ctor, fields, pat.ty, pat.span) } - pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> { - let is_wildcard = |pat: &Pat<'_>| { - matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) - }; - let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx))); - let kind = match &self.ctor { - Single | Variant(_) => match self.ty.kind() { - ty::Tuple(..) => PatKind::Leaf { - subpatterns: subpatterns - .enumerate() - .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) - .collect(), - }, - ty::Adt(adt_def, _) if adt_def.is_box() => { - // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside - // of `std`). So this branch is only reachable when the feature is enabled and - // the pattern is a box pattern. - PatKind::Deref { subpattern: subpatterns.next().unwrap() } - } - ty::Adt(adt_def, args) => { - let variant_index = self.ctor.variant_index_for_adt(*adt_def); - let variant = &adt_def.variant(variant_index); - let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant) - .zip(subpatterns) - .map(|((field, _ty), pattern)| FieldPat { field, pattern }) - .collect(); - - if adt_def.is_enum() { - PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns } - } else { - PatKind::Leaf { subpatterns } - } - } - // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should - // be careful to reconstruct the correct constant pattern here. However a string - // literal pattern will never be reported as a non-exhaustiveness witness, so we - // ignore this issue. - ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, - _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty), - }, - Slice(slice) => { - match slice.kind { - FixedLen(_) => PatKind::Slice { - prefix: subpatterns.collect(), - slice: None, - suffix: Box::new([]), - }, - VarLen(prefix, _) => { - let mut subpatterns = subpatterns.peekable(); - let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect(); - if slice.array_len.is_some() { - // Improves diagnostics a bit: if the type is a known-size array, instead - // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. - // This is incorrect if the size is not known, since `[_, ..]` captures - // arrays of lengths `>= 1` whereas `[..]` captures any length. - while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { - prefix.pop(); - } - while subpatterns.peek().is_some() - && is_wildcard(subpatterns.peek().unwrap()) - { - subpatterns.next(); - } - } - let suffix: Box<[_]> = subpatterns.collect(); - let wild = Pat::wildcard_from_ty(self.ty); - PatKind::Slice { - prefix: prefix.into_boxed_slice(), - slice: Some(Box::new(wild)), - suffix, - } - } - } - } - &Str(value) => PatKind::Constant { value }, - IntRange(range) => return range.to_pat(cx.tcx, self.ty), - Wildcard | NonExhaustive | Hidden => PatKind::Wild, - Missing { .. } => bug!( - "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, - `Missing` should have been processed in `apply_constructors`" - ), - F32Range(..) | F64Range(..) | Opaque | Or => { - bug!("can't convert to pattern: {:?}", self) - } - }; - - Pat { ty: self.ty, span: DUMMY_SP, kind } - } - pub(super) fn is_or_pat(&self) -> bool { matches!(self.ctor, Or) } @@ -1800,3 +1698,131 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { } } } + +/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics +/// purposes. As such they don't use interning and can be cloned. +#[derive(Debug, Clone)] +pub(crate) struct WitnessPat<'tcx> { + ctor: Constructor<'tcx>, + fields: Vec>, + ty: Ty<'tcx>, +} + +impl<'tcx> WitnessPat<'tcx> { + pub(super) fn new(ctor: Constructor<'tcx>, fields: Vec, ty: Ty<'tcx>) -> Self { + Self { ctor, fields, ty } + } + pub(super) fn wildcard(ty: Ty<'tcx>) -> Self { + Self::new(Wildcard, Vec::new(), ty) + } + + /// Construct a pattern that matches everything that starts with this constructor. + /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern + /// `Some(_)`. + pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, '_, 'tcx>, ctor: Constructor<'tcx>) -> Self { + // Reuse `Fields::wildcards` to get the types. + let fields = Fields::wildcards(pcx, &ctor) + .iter_patterns() + .map(|deco_pat| Self::wildcard(deco_pat.ty())) + .collect(); + Self::new(ctor, fields, pcx.ty) + } + + pub(super) fn ctor(&self) -> &Constructor<'tcx> { + &self.ctor + } + pub(super) fn ty(&self) -> Ty<'tcx> { + self.ty + } + + pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> { + let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild); + let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx))); + let kind = match &self.ctor { + Single | Variant(_) => match self.ty.kind() { + ty::Tuple(..) => PatKind::Leaf { + subpatterns: subpatterns + .enumerate() + .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) + .collect(), + }, + ty::Adt(adt_def, _) if adt_def.is_box() => { + // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside + // of `std`). So this branch is only reachable when the feature is enabled and + // the pattern is a box pattern. + PatKind::Deref { subpattern: subpatterns.next().unwrap() } + } + ty::Adt(adt_def, args) => { + let variant_index = self.ctor.variant_index_for_adt(*adt_def); + let variant = &adt_def.variant(variant_index); + let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant) + .zip(subpatterns) + .map(|((field, _ty), pattern)| FieldPat { field, pattern }) + .collect(); + + if adt_def.is_enum() { + PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns } + } else { + PatKind::Leaf { subpatterns } + } + } + // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should + // be careful to reconstruct the correct constant pattern here. However a string + // literal pattern will never be reported as a non-exhaustiveness witness, so we + // ignore this issue. + ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, + _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty), + }, + Slice(slice) => { + match slice.kind { + FixedLen(_) => PatKind::Slice { + prefix: subpatterns.collect(), + slice: None, + suffix: Box::new([]), + }, + VarLen(prefix, _) => { + let mut subpatterns = subpatterns.peekable(); + let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect(); + if slice.array_len.is_some() { + // Improves diagnostics a bit: if the type is a known-size array, instead + // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. + // This is incorrect if the size is not known, since `[_, ..]` captures + // arrays of lengths `>= 1` whereas `[..]` captures any length. + while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { + prefix.pop(); + } + while subpatterns.peek().is_some() + && is_wildcard(subpatterns.peek().unwrap()) + { + subpatterns.next(); + } + } + let suffix: Box<[_]> = subpatterns.collect(); + let wild = Pat::wildcard_from_ty(self.ty); + PatKind::Slice { + prefix: prefix.into_boxed_slice(), + slice: Some(Box::new(wild)), + suffix, + } + } + } + } + &Str(value) => PatKind::Constant { value }, + IntRange(range) => return range.to_pat(cx.tcx, self.ty), + Wildcard | NonExhaustive | Hidden => PatKind::Wild, + Missing { .. } => bug!( + "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, + `Missing` should have been processed in `apply_constructors`" + ), + F32Range(..) | F64Range(..) | Opaque | Or => { + bug!("can't convert to pattern: {:?}", self) + } + }; + + Pat { ty: self.ty, span: DUMMY_SP, kind } + } + + pub(super) fn iter_fields<'a>(&'a self) -> impl Iterator> { + self.fields.iter() + } +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 6cd73c7eaa95..e60349be3ba7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -213,7 +213,7 @@ //! or-patterns in the first column are expanded before being stored in the matrix. Specialization //! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and //! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the -//! [`Fields`] struct. +//! [`super::deconstruct_pat::Fields`] struct. //! //! //! # Computing usefulness @@ -307,7 +307,7 @@ use self::ArmType::*; use self::Usefulness::*; -use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, Fields}; +use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, WitnessPat}; use crate::errors::{NonExhaustiveOmittedPattern, Uncovered}; use rustc_data_structures::captures::Captures; @@ -322,7 +322,6 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::fmt; -use std::iter::once; pub(crate) struct MatchCheckCtxt<'p, 'tcx> { pub(crate) tcx: TyCtxt<'tcx>, @@ -555,20 +554,20 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { /// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of /// witnesses of non-exhaustiveness when there are any. /// Which variant to use is dictated by `ArmType`. -#[derive(Debug)] -enum Usefulness<'p, 'tcx> { +#[derive(Debug, Clone)] +enum Usefulness<'tcx> { /// If we don't care about witnesses, simply remember if the pattern was useful. NoWitnesses { useful: bool }, /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole /// pattern is unreachable. - WithWitnesses(Vec>), + WithWitnesses(Vec>), } -impl<'p, 'tcx> Usefulness<'p, 'tcx> { +impl<'tcx> Usefulness<'tcx> { fn new_useful(preference: ArmType) -> Self { match preference { // A single (empty) witness of reachability. - FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]), + FakeExtraWildcard => WithWitnesses(vec![WitnessStack(vec![])]), RealArm => NoWitnesses { useful: true }, } } @@ -605,8 +604,8 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { /// with the results of specializing with the other constructors. fn apply_constructor( self, - pcx: &PatCtxt<'_, 'p, 'tcx>, - matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors + pcx: &PatCtxt<'_, '_, 'tcx>, + matrix: &Matrix<'_, 'tcx>, // used to compute missing ctors ctor: &Constructor<'tcx>, ) -> Self { match self { @@ -627,25 +626,18 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { // wildcards for fields, i.e. that matches everything that can be built with it. // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get // the pattern `Some(_)`. - let new_patterns: Vec> = missing + let new_patterns: Vec> = missing .into_iter() - .map(|missing_ctor| { - DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()) - }) + .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor.clone())) .collect(); witnesses .into_iter() .flat_map(|witness| { new_patterns.iter().map(move |pat| { - Witness( - witness - .0 - .iter() - .chain(once(pat)) - .map(DeconstructedPat::clone_and_forget_reachability) - .collect(), - ) + let mut stack = witness.clone(); + stack.0.push(pat.clone()); + stack }) }) .collect() @@ -667,15 +659,17 @@ enum ArmType { RealArm, } -/// A witness of non-exhaustiveness for error reporting, represented -/// as a list of patterns (in reverse order of construction) with -/// wildcards inside to represent elements that can take any inhabitant -/// of the type as a value. +/// A witness-tuple of non-exhaustiveness for error reporting, represented as a list of patterns (in +/// reverse order of construction) with wildcards inside to represent elements that can take any +/// inhabitant of the type as a value. /// -/// A witness against a list of patterns should have the same types -/// and length as the pattern matched against. Because Rust `match` -/// is always against a single pattern, at the end the witness will -/// have length 1, but in the middle of the algorithm, it can contain +/// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we +/// are inspecting, and `WitnessStack` contains witnesses we are constructing. +/// FIXME(Nadrieril): use the same order of patterns for both +/// +/// A `WitnessStack` should have the same types and length as the `PatStacks` we are inspecting +/// (except we store the patterns in reverse order). Because Rust `match` is always against a single +/// pattern, at the end the stack will have length 1. In the middle of the algorithm, it can contain /// multiple patterns. /// /// For example, if we are constructing a witness for the match against @@ -690,23 +684,37 @@ enum ArmType { /// # } /// ``` /// -/// We'll perform the following steps: -/// 1. Start with an empty witness -/// `Witness(vec![])` -/// 2. Push a witness `true` against the `false` -/// `Witness(vec![true])` -/// 3. Push a witness `Some(_)` against the `None` -/// `Witness(vec![true, Some(_)])` -/// 4. Apply the `Pair` constructor to the witnesses -/// `Witness(vec![Pair(Some(_), true)])` +/// We'll perform the following steps (among others): +/// - Start with a matrix representing the match +/// `PatStack(vec![Pair(None, _)])` +/// `PatStack(vec![Pair(_, false)])` +/// - Specialize with `Pair` +/// `PatStack(vec![None, _])` +/// `PatStack(vec![_, false])` +/// - Specialize with `Some` +/// `PatStack(vec![_, false])` +/// - Specialize with `_` +/// `PatStack(vec![false])` +/// - Specialize with `true` +/// // no patstacks left +/// - This is a non-exhaustive match: we have the empty witness stack as a witness. +/// `WitnessStack(vec![])` +/// - Apply `true` +/// `WitnessStack(vec![true])` +/// - Apply `_` +/// `WitnessStack(vec![true, _])` +/// - Apply `Some` +/// `WitnessStack(vec![true, Some(_)])` +/// - Apply `Pair` +/// `WitnessStack(vec![Pair(Some(_), true)])` /// /// The final `Pair(Some(_), true)` is then the resulting witness. -#[derive(Debug)] -pub(crate) struct Witness<'p, 'tcx>(Vec>); +#[derive(Debug, Clone)] +pub(crate) struct WitnessStack<'tcx>(Vec>); -impl<'p, 'tcx> Witness<'p, 'tcx> { +impl<'tcx> WitnessStack<'tcx> { /// Asserts that the witness contains a single pattern, and returns it. - fn single_pattern(self) -> DeconstructedPat<'p, 'tcx> { + fn single_pattern(self) -> WitnessPat<'tcx> { assert_eq!(self.0.len(), 1); self.0.into_iter().next().unwrap() } @@ -724,13 +732,12 @@ impl<'p, 'tcx> Witness<'p, 'tcx> { /// /// left_ty: struct X { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor(mut self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self { + fn apply_constructor(mut self, pcx: &PatCtxt<'_, '_, 'tcx>, ctor: &Constructor<'tcx>) -> Self { let pat = { let len = self.0.len(); let arity = ctor.arity(pcx); - let pats = self.0.drain((len - arity)..).rev(); - let fields = Fields::from_iter(pcx.cx, pats); - DeconstructedPat::new(ctor.clone(), fields, pcx.ty, pcx.span) + let fields = self.0.drain((len - arity)..).rev().collect(); + WitnessPat::new(ctor.clone(), fields, pcx.ty) }; self.0.push(pat); @@ -770,7 +777,7 @@ fn is_useful<'p, 'tcx>( lint_root: HirId, is_under_guard: bool, is_top_level: bool, -) -> Usefulness<'p, 'tcx> { +) -> Usefulness<'tcx> { debug!(?matrix, ?v); let Matrix { patterns: rows, .. } = matrix; @@ -885,7 +892,7 @@ fn is_useful<'p, 'tcx>( // Because of how we computed `nonexhaustive_enum_missing_visible_variants`, // this will not return an empty `Vec`. .filter(|c| !(matches!(c, Constructor::NonExhaustive | Constructor::Hidden))) - .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) + .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor)) .collect::>(); // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` @@ -940,7 +947,7 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> { pub(crate) arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>, /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of /// exhaustiveness. - pub(crate) non_exhaustiveness_witnesses: Vec>, + pub(crate) non_exhaustiveness_witnesses: Vec>, } /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which From 2d45df3caa22f5aef24564ad27de866ab8b5b254 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Oct 2023 15:19:51 +0200 Subject: [PATCH 040/107] Add and prepare tests --- ...te-non_exhaustive_omitted_patterns_lint.rs | 12 +- ...on_exhaustive_omitted_patterns_lint.stderr | 53 +++++-- .../omitted-patterns.rs | 60 +++++++- .../omitted-patterns.stderr | 130 +++++++++++++----- .../stable-omitted-patterns.rs | 6 +- .../stable-omitted-patterns.stderr | 6 +- 6 files changed, 200 insertions(+), 67 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs index 9b646060adfd..240dd90f70dc 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs @@ -9,7 +9,9 @@ fn main() { enum Foo { - A, B, C, + A, + B, + C, } #[allow(non_exhaustive_omitted_patterns)] @@ -23,12 +25,14 @@ fn main() { } //~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered + #[warn(non_exhaustive_omitted_patterns)] + //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` match Foo::A { Foo::A => {} Foo::B => {} - #[warn(non_exhaustive_omitted_patterns)] _ => {} } - //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns` - //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` } diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index 1c14622d6378..22e5481929f5 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -20,7 +20,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,15 +41,26 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `non_exhaustive_omitted_patterns` lint is unstable = note: see issue #89554 for more information = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + warning: unknown lint: `non_exhaustive_omitted_patterns` --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1 | @@ -73,7 +84,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +95,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,10 +106,21 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `non_exhaustive_omitted_patterns` lint is unstable = note: see issue #89554 for more information @@ -106,18 +128,19 @@ LL | #[warn(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0004]: non-exhaustive patterns: `Foo::C` not covered - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:22:11 | LL | match Foo::A { | ^^^^^^ pattern `Foo::C` not covered | note: `Foo` defined here - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:14:9 | LL | enum Foo { | --- -LL | A, B, C, - | ^ not covered +... +LL | C, + | ^ not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -125,6 +148,6 @@ LL ~ Foo::B => {}, LL + Foo::C => todo!() | -error: aborting due to previous error; 10 warnings emitted +error: aborting due to previous error; 12 warnings emitted For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs index 3482af74752f..391e7c778757 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -13,8 +13,8 @@ use enums::{ EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, VariantNonExhaustive, }; -use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct}; use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct}; +use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct}; #[non_exhaustive] #[derive(Default)] @@ -35,10 +35,10 @@ fn main() { let enumeration = Bar::A; // Ok: this is a crate local non_exhaustive enum + #[deny(non_exhaustive_omitted_patterns)] match enumeration { Bar::A => {} Bar::B => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } @@ -51,38 +51,80 @@ fn main() { _ => {} } + #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly + #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly let x = 5; + #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit if x > 10 => {} NonExhaustiveEnum::Tuple(_) => {} NonExhaustiveEnum::Struct { .. } => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly + #[deny(non_exhaustive_omitted_patterns)] + match (non_enum, true) { + (NonExhaustiveEnum::Unit, true) => {} + (NonExhaustiveEnum::Tuple(_), false) => {} + (NonExhaustiveEnum::Struct { .. }, false) => {} + _ => {} + } + #[deny(non_exhaustive_omitted_patterns)] + match (non_enum, true) { + (NonExhaustiveEnum::Unit, true) => {} + (NonExhaustiveEnum::Tuple(_), false) => {} + _ => {} + } + //~^^ some variants are not matched explicitly + + // FIXME(Nadrieril): asymmetrical behavior + #[deny(non_exhaustive_omitted_patterns)] + match (true, non_enum) { + (true, NonExhaustiveEnum::Unit) => {} + (false, NonExhaustiveEnum::Tuple(_)) => {} + (false, NonExhaustiveEnum::Struct { .. }) => {} + _ => {} + } + //~^^ some variants are not matched explicitly + //~| some variants are not matched explicitly + #[deny(non_exhaustive_omitted_patterns)] + match (true, non_enum) { + (true, NonExhaustiveEnum::Unit) => {} + (false, NonExhaustiveEnum::Tuple(_)) => {} + _ => {} + } + //~^^ some variants are not matched explicitly + //~| some variants are not matched explicitly + + // FIXME(Nadrieril): we should detect this + #[deny(non_exhaustive_omitted_patterns)] + match Some(non_enum) { + Some(NonExhaustiveEnum::Unit) => {} + Some(NonExhaustiveEnum::Tuple(_)) => {} + _ => {} + } + // Ok: all covered and not `unreachable-patterns` #[deny(unreachable_patterns)] + #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} NonExhaustiveEnum::Struct { .. } => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } @@ -132,15 +174,19 @@ fn main() { _ => {} } //~^^ some variants are not matched explicitly + #[deny(non_exhaustive_omitted_patterns)] + match &NonExhaustiveSingleVariant::A(true) { + _ => {} + } // Ok: we don't lint on `if let` expressions #[deny(non_exhaustive_omitted_patterns)] if let NonExhaustiveEnum::Tuple(_) = non_enum {} + #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr index 923394474b26..db22aba6b8e6 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -1,5 +1,5 @@ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:102:9 + --> $DIR/omitted-patterns.rs:144:9 | LL | VariantNonExhaustive::Bar { x, .. } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed @@ -7,13 +7,13 @@ LL | VariantNonExhaustive::Bar { x, .. } => {} = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:99:12 + --> $DIR/omitted-patterns.rs:141:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:107:9 + --> $DIR/omitted-patterns.rs:149:9 | LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed @@ -21,13 +21,13 @@ LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalReco = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:106:12 + --> $DIR/omitted-patterns.rs:148:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:115:29 + --> $DIR/omitted-patterns.rs:157:29 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed @@ -35,13 +35,13 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:114:12 + --> $DIR/omitted-patterns.rs:156:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:115:9 + --> $DIR/omitted-patterns.rs:157:9 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed @@ -50,7 +50,7 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:173:9 + --> $DIR/omitted-patterns.rs:219:9 | LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed @@ -58,13 +58,13 @@ LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:172:12 + --> $DIR/omitted-patterns.rs:218:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:181:9 + --> $DIR/omitted-patterns.rs:227:9 | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed @@ -72,7 +72,7 @@ LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:180:12 + --> $DIR/omitted-patterns.rs:226:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -86,10 +86,10 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:57:16 + --> $DIR/omitted-patterns.rs:54:12 | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:65:9 @@ -100,10 +100,10 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:64:16 + --> $DIR/omitted-patterns.rs:62:12 | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:75:9 @@ -114,13 +114,73 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:74:16 + --> $DIR/omitted-patterns.rs:70:12 | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:92:32 + --> $DIR/omitted-patterns.rs:90:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:86:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:100:9 + | +LL | _ => {} + | ^ pattern `NonExhaustiveEnum::Unit` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:95:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:100:9 + | +LL | _ => {} + | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:108:9 + | +LL | _ => {} + | ^ patterns `NonExhaustiveEnum::Unit` and `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:104:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:108:9 + | +LL | _ => {} + | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:134:32 | LL | NestedNonExhaustive::A(_) => {} | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered @@ -128,13 +188,13 @@ LL | NestedNonExhaustive::A(_) => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:89:12 + --> $DIR/omitted-patterns.rs:131:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:94:9 + --> $DIR/omitted-patterns.rs:136:9 | LL | _ => {} | ^ pattern `NestedNonExhaustive::C` not covered @@ -143,7 +203,7 @@ LL | _ => {} = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:132:9 + --> $DIR/omitted-patterns.rs:174:9 | LL | _ => {} | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered @@ -151,13 +211,13 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:130:12 + --> $DIR/omitted-patterns.rs:172:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:144:9 + --> $DIR/omitted-patterns.rs:190:9 | LL | _ => {} | ^ pattern `UnstableEnum::Unstable` not covered @@ -165,13 +225,13 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:143:16 + --> $DIR/omitted-patterns.rs:186:12 | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:168:9 + --> $DIR/omitted-patterns.rs:214:9 | LL | _ => {} | ^ pattern `OnlyUnstableEnum::Unstable2` not covered @@ -179,13 +239,13 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:165:12 + --> $DIR/omitted-patterns.rs:211:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding - --> $DIR/omitted-patterns.rs:194:9 + --> $DIR/omitted-patterns.rs:240:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; | ^^^^^^^^^^^^^^^ pattern `_` not covered @@ -199,7 +259,7 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit | ++++++++++++++++ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:202:9 + --> $DIR/omitted-patterns.rs:248:9 | LL | _ => {} | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered @@ -207,11 +267,11 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:198:12 + --> $DIR/omitted-patterns.rs:244:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors; 6 warnings emitted +error: aborting due to 15 previous errors; 6 warnings emitted For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs index 82ee68687ed0..20b51a5cf3f7 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs @@ -6,20 +6,20 @@ // aux-build:unstable.rs extern crate unstable; -use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct}; +use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct}; fn main() { // OK: this matches all the stable variants + #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } + #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} - #[deny(non_exhaustive_omitted_patterns)] _ => {} } //~^^ some variants are not matched explicitly diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr index f38368590fb1..5b75cfb69fe0 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr @@ -21,10 +21,10 @@ LL | _ => {} = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/stable-omitted-patterns.rs:22:16 + --> $DIR/stable-omitted-patterns.rs:20:12 | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted From ca869e33341ced8335c1288232c847a377a8653b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 14 Oct 2023 18:25:10 +0200 Subject: [PATCH 041/107] Lint `non_exhaustive_omitted_patterns` per column --- compiler/rustc_lint_defs/src/builtin.rs | 34 ++-- .../src/thir/pattern/check_match.rs | 7 +- .../src/thir/pattern/deconstruct_pat.rs | 46 ++---- .../src/thir/pattern/usefulness.rs | 153 +++++++++++------ ...te-non_exhaustive_omitted_patterns_lint.rs | 6 +- ...on_exhaustive_omitted_patterns_lint.stderr | 70 ++++++-- .../omitted-patterns.rs | 32 ++-- .../omitted-patterns.stderr | 155 ++++++------------ .../stable-omitted-patterns.rs | 2 +- .../stable-omitted-patterns.stderr | 6 +- 10 files changed, 279 insertions(+), 232 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 69b462d32bd5..e742014b44c7 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3993,8 +3993,13 @@ declare_lint! { } declare_lint! { - /// The `non_exhaustive_omitted_patterns` lint detects when a wildcard (`_` or `..`) in a - /// pattern for a `#[non_exhaustive]` struct or enum is reachable. + /// The `non_exhaustive_omitted_patterns` lint aims to help consumers of a `#[non_exhaustive]` + /// struct or enum who want to match all of its fields/variants explicitly. + /// + /// The `#[non_exhaustive]` annotation forces matches to use wildcards, so exhaustiveness + /// checking cannot be used to ensure that all fields/variants are matched explicitly. To remedy + /// this, this allow-by-default lint warns the user when a match mentions some but not all of + /// the fields/variants of a `#[non_exhaustive]` struct or enum. /// /// ### Example /// @@ -4008,9 +4013,9 @@ declare_lint! { /// /// // in crate B /// #![feature(non_exhaustive_omitted_patterns_lint)] + /// #[warn(non_exhaustive_omitted_patterns)] /// match Bar::A { /// Bar::A => {}, - /// #[warn(non_exhaustive_omitted_patterns)] /// _ => {}, /// } /// ``` @@ -4018,29 +4023,32 @@ declare_lint! { /// This will produce: /// /// ```text - /// warning: reachable patterns not covered of non exhaustive enum + /// warning: some variants are not matched explicitly /// --> $DIR/reachable-patterns.rs:70:9 /// | - /// LL | _ => {} - /// | ^ pattern `B` not covered + /// LL | match Bar::A { + /// | ^ pattern `Bar::B` not covered /// | /// note: the lint level is defined here /// --> $DIR/reachable-patterns.rs:69:16 /// | /// LL | #[warn(non_exhaustive_omitted_patterns)] /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// = help: ensure that all possible cases are being handled by adding the suggested match arms + /// = help: ensure that all variants are matched explicitly by adding the suggested match arms /// = note: the matched value is of type `Bar` and the `non_exhaustive_omitted_patterns` attribute was found /// ``` /// + /// Warning: setting this to `deny` will make upstream non-breaking changes (adding fields or + /// variants to a `#[non_exhaustive]` struct or enum) break your crate. This goes against + /// expected semver behavior. + /// /// ### Explanation /// - /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a - /// (potentially redundant) wildcard when pattern-matching, to allow for future - /// addition of fields or variants. The `non_exhaustive_omitted_patterns` lint - /// detects when such a wildcard happens to actually catch some fields/variants. - /// In other words, when the match without the wildcard would not be exhaustive. - /// This lets the user be informed if new fields/variants were added. + /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a (potentially + /// redundant) wildcard when pattern-matching, to allow for future addition of fields or + /// variants. The `non_exhaustive_omitted_patterns` lint detects when such a wildcard happens to + /// actually catch some fields/variants. In other words, when the match without the wildcard + /// would not be exhaustive. This lets the user be informed if new fields/variants were added. pub NON_EXHAUSTIVE_OMITTED_PATTERNS, Allow, "detect when patterns of types marked `non_exhaustive` are missed", diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index f3568b682a4b..162b6fde552f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -269,7 +269,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let scrut = &self.thir[scrut]; let scrut_ty = scrut.ty; - let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty); + let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span); match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -431,7 +431,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let pattern = self.lower_pattern(&mut cx, pat); let pattern_ty = pattern.ty(); let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; - let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty); + let report = + compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty, pattern.span()); // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We // only care about exhaustiveness here. @@ -622,7 +623,7 @@ fn is_let_irrefutable<'p, 'tcx>( pat: &'p DeconstructedPat<'p, 'tcx>, ) -> bool { let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty()); + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty(), pat.span()); // Report if the pattern is unreachable, which can only occur when the type is uninhabited. // This also reports unreachable sub-patterns though, so we can't just replace it with an diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 818a8ff27c81..359e5333fb90 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -629,18 +629,11 @@ pub(super) enum Constructor<'tcx> { /// `#[doc(hidden)]` ones. Hidden, /// Fake extra constructor for constructors that are not seen in the matrix, as explained in the - /// code for [`Constructor::split`]. The carried `bool` is used for the - /// `non_exhaustive_omitted_patterns` lint. - Missing { - nonexhaustive_enum_missing_visible_variants: bool, - }, + /// code for [`Constructor::split`]. + Missing, } impl<'tcx> Constructor<'tcx> { - pub(super) fn is_wildcard(&self) -> bool { - matches!(self, Wildcard) - } - pub(super) fn is_non_exhaustive(&self) -> bool { matches!(self, NonExhaustive) } @@ -778,14 +771,8 @@ impl<'tcx> Constructor<'tcx> { let all_missing = split_set.present.is_empty(); let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); - let ctor = if all_missing && !report_when_all_missing { - Wildcard - } else { - Missing { - nonexhaustive_enum_missing_visible_variants: split_set - .nonexhaustive_enum_missing_visible_variants, - } - }; + let ctor = + if all_missing && !report_when_all_missing { Wildcard } else { Missing }; smallvec![ctor] } else { split_set.present @@ -905,11 +892,9 @@ pub(super) enum ConstructorSet { /// either fully included in or disjoint from each constructor in the column. This avoids /// non-trivial intersections like between `0..10` and `5..15`. #[derive(Debug)] -struct SplitConstructorSet<'tcx> { - present: SmallVec<[Constructor<'tcx>; 1]>, - missing: Vec>, - /// For the `non_exhaustive_omitted_patterns` lint. - nonexhaustive_enum_missing_visible_variants: bool, +pub(super) struct SplitConstructorSet<'tcx> { + pub(super) present: SmallVec<[Constructor<'tcx>; 1]>, + pub(super) missing: Vec>, } impl ConstructorSet { @@ -1039,7 +1024,7 @@ impl ConstructorSet { /// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split /// constructors to handle non-trivial intersections e.g. on ranges or slices. #[instrument(level = "debug", skip(self, pcx, ctors), ret)] - fn split<'a, 'tcx>( + pub(super) fn split<'a, 'tcx>( &self, pcx: &PatCtxt<'_, '_, 'tcx>, ctors: impl Iterator> + Clone, @@ -1051,7 +1036,6 @@ impl ConstructorSet { let mut missing = Vec::new(); // Constructors in `ctors`, except wildcards. let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard))); - let mut nonexhaustive_enum_missing_visible_variants = false; match self { ConstructorSet::Single => { if seen.next().is_none() { @@ -1063,6 +1047,7 @@ impl ConstructorSet { ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => { let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect(); let mut skipped_a_hidden_variant = false; + for variant in visible_variants { let ctor = Variant(*variant); if seen_set.contains(&variant) { @@ -1071,8 +1056,6 @@ impl ConstructorSet { missing.push(ctor); } } - nonexhaustive_enum_missing_visible_variants = - *non_exhaustive && !missing.is_empty(); for variant in hidden_variants { let ctor = Variant(*variant); @@ -1159,7 +1142,7 @@ impl ConstructorSet { ConstructorSet::Uninhabited => {} } - SplitConstructorSet { present, missing, nonexhaustive_enum_missing_visible_variants } + SplitConstructorSet { present, missing } } /// Compute the set of constructors missing from this column. @@ -1519,6 +1502,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { pub(super) fn is_or_pat(&self) -> bool { matches!(self.ctor, Or) } + pub(super) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> { + if self.is_or_pat() { + self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect() + } else { + smallvec![self] + } + } pub(super) fn ctor(&self) -> &Constructor<'tcx> { &self.ctor @@ -1704,7 +1694,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { #[derive(Debug, Clone)] pub(crate) struct WitnessPat<'tcx> { ctor: Constructor<'tcx>, - fields: Vec>, + pub(crate) fields: Vec>, ty: Ty<'tcx>, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index e60349be3ba7..a8cee5a61edb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -844,8 +844,6 @@ fn is_useful<'p, 'tcx>( } // We split the head constructor of `v`. let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - let is_non_exhaustive_and_wild = - cx.is_foreign_non_exhaustive_enum(ty) && v_ctor.is_wildcard(); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. let start_matrix = &matrix; @@ -866,50 +864,6 @@ fn is_useful<'p, 'tcx>( ) }); let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); - - // When all the conditions are met we have a match with a `non_exhaustive` enum - // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint. - // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors` - if is_non_exhaustive_and_wild - // Only emit a lint on refutable patterns. - && cx.refutable - // We check that the match has a wildcard pattern and that wildcard is useful, - // meaning there are variants that are covered by the wildcard. Without the check - // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}` - && usefulness.is_useful() && matches!(witness_preference, RealArm) - && matches!( - &ctor, - Constructor::Missing { nonexhaustive_enum_missing_visible_variants: true } - ) - { - let missing = ConstructorSet::for_ty(pcx.cx, pcx.ty) - .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // Construct for each missing constructor a "wild" version of this constructor, that - // matches everything that can be built with it. For example, if `ctor` is a - // `Constructor::Variant` for `Option::Some`, we get the pattern `Some(_)`. - let patterns = missing - .into_iter() - // Because of how we computed `nonexhaustive_enum_missing_visible_variants`, - // this will not return an empty `Vec`. - .filter(|c| !(matches!(c, Constructor::NonExhaustive | Constructor::Hidden))) - .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor)) - .collect::>(); - - // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` - // is not exhaustive enough. - // - // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. - cx.tcx.emit_spanned_lint( - NON_EXHAUSTIVE_OMITTED_PATTERNS, - lint_root, - pcx.span, - NonExhaustiveOmittedPattern { - scrut_ty: pcx.ty, - uncovered: Uncovered::new(pcx.span, pcx.cx, patterns), - }, - ); - } - ret.extend(usefulness); } } @@ -921,6 +875,80 @@ fn is_useful<'p, 'tcx>( ret } +/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned +/// in a given column. This traverses patterns column-by-column, where a column is the intuitive +/// notion of "subpatterns that inspect the same subvalue". +/// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the +/// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete). +fn collect_nonexhaustive_missing_variants<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + column: &[&DeconstructedPat<'p, 'tcx>], +) -> Vec> { + let ty = column[0].ty(); + let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false }; + + let set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column.iter().map(|p| p.ctor())); + if set.present.is_empty() { + // We can't consistently handle the case where no constructors are present (since this would + // require digging deep through any type in case there's a non_exhaustive enum somewhere), + // so for consistency we refuse to handle the top-level case, where we could handle it. + return vec![]; + } + + let mut witnesses = Vec::new(); + if cx.is_foreign_non_exhaustive_enum(ty) { + witnesses.extend( + set.missing + .into_iter() + // This will list missing visible variants. + .filter(|c| !matches!(c, Constructor::Hidden | Constructor::NonExhaustive)) + .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor)), + ) + } + + // Recurse into the fields. + for ctor in set.present { + let arity = ctor.arity(pcx); + if arity == 0 { + continue; + } + + // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These + // columns may have different lengths in the presence of or-patterns (this is why we can't + // reuse `Matrix`). + let mut specialized_columns: Vec> = (0..arity).map(|_| Vec::new()).collect(); + let relevant_patterns = column.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); + for pat in relevant_patterns { + let specialized = pat.specialize(pcx, &ctor); + for (subpat, sub_column) in specialized.iter().zip(&mut specialized_columns) { + if subpat.is_or_pat() { + sub_column.extend(subpat.iter_fields()) + } else { + sub_column.push(subpat) + } + } + } + debug_assert!( + !specialized_columns[0].is_empty(), + "ctor {ctor:?} was listed as present but isn't" + ); + + let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor); + for (i, col_i) in specialized_columns.iter().enumerate() { + // Compute witnesses for each column. + let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i.as_slice()); + // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`, + // adding enough wildcards to match `arity`. + for wit in wits_for_col_i { + let mut pat = wild_pat.clone(); + pat.fields[i] = wit; + witnesses.push(pat); + } + } + } + witnesses +} + /// The arm of a match expression. #[derive(Clone, Copy, Debug)] pub(crate) struct MatchArm<'p, 'tcx> { @@ -961,6 +989,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( arms: &[MatchArm<'p, 'tcx>], lint_root: HirId, scrut_ty: Ty<'tcx>, + scrut_span: Span, ) -> UsefulnessReport<'p, 'tcx> { let mut matrix = Matrix::empty(); let arm_usefulness: Vec<_> = arms @@ -985,9 +1014,39 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); let v = PatStack::from_pattern(wild_pattern); let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true); - let non_exhaustiveness_witnesses = match usefulness { + let non_exhaustiveness_witnesses: Vec<_> = match usefulness { WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), NoWitnesses { .. } => bug!(), }; + + // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting + // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. + if cx.refutable + && non_exhaustiveness_witnesses.is_empty() + && !matches!( + cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0, + rustc_session::lint::Level::Allow + ) + { + let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::>(); + let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); + + if !witnesses.is_empty() { + // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` + // is not exhaustive enough. + // + // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. + cx.tcx.emit_spanned_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + lint_root, + scrut_span, + NonExhaustiveOmittedPattern { + scrut_ty, + uncovered: Uncovered::new(scrut_span, cx, witnesses), + }, + ); + } + } + UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } } diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs index 240dd90f70dc..1922bfb4913e 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs @@ -3,9 +3,11 @@ #![deny(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` +//~| WARNING unknown lint: `non_exhaustive_omitted_patterns` #![allow(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` +//~| WARNING unknown lint: `non_exhaustive_omitted_patterns` fn main() { enum Foo { @@ -19,17 +21,19 @@ fn main() { //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` match Foo::A { + //~^ ERROR non-exhaustive patterns: `Foo::C` not covered Foo::A => {} Foo::B => {} } - //~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered #[warn(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` + //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` match Foo::A { Foo::A => {} Foo::B => {} diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index 22e5481929f5..eb61c4cf159a 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -10,7 +10,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)] = note: `#[warn(unknown_lints)]` on by default warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 | LL | #![allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | #[warn(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 | LL | #![allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | #[warn(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:28:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,13 +128,13 @@ LL | #[warn(non_exhaustive_omitted_patterns)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0004]: non-exhaustive patterns: `Foo::C` not covered - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:22:11 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:25:11 | LL | match Foo::A { | ^^^^^^ pattern `Foo::C` not covered | note: `Foo` defined here - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:14:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:16:9 | LL | enum Foo { | --- @@ -148,6 +148,50 @@ LL ~ Foo::B => {}, LL + Foo::C => todo!() | -error: aborting due to previous error; 12 warnings emitted +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1 + | +LL | #![deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 + | +LL | #![allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5 + | +LL | #[allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: unknown lint: `non_exhaustive_omitted_patterns` + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `non_exhaustive_omitted_patterns` lint is unstable + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to previous error; 16 warnings emitted For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs index 391e7c778757..ecfeb3f9b98b 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -53,20 +53,21 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match non_enum { + //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } - //~^^ some variants are not matched explicitly #[deny(non_exhaustive_omitted_patterns)] match non_enum { + //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} _ => {} } - //~^^ some variants are not matched explicitly let x = 5; + // We ignore the guard. #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit if x > 10 => {} @@ -74,7 +75,6 @@ fn main() { NonExhaustiveEnum::Struct { .. } => {} _ => {} } - //~^^ some variants are not matched explicitly #[deny(non_exhaustive_omitted_patterns)] match (non_enum, true) { @@ -85,13 +85,12 @@ fn main() { } #[deny(non_exhaustive_omitted_patterns)] match (non_enum, true) { + //~^ some variants are not matched explicitly (NonExhaustiveEnum::Unit, true) => {} (NonExhaustiveEnum::Tuple(_), false) => {} _ => {} } - //~^^ some variants are not matched explicitly - // FIXME(Nadrieril): asymmetrical behavior #[deny(non_exhaustive_omitted_patterns)] match (true, non_enum) { (true, NonExhaustiveEnum::Unit) => {} @@ -99,20 +98,17 @@ fn main() { (false, NonExhaustiveEnum::Struct { .. }) => {} _ => {} } - //~^^ some variants are not matched explicitly - //~| some variants are not matched explicitly #[deny(non_exhaustive_omitted_patterns)] match (true, non_enum) { + //~^ some variants are not matched explicitly (true, NonExhaustiveEnum::Unit) => {} (false, NonExhaustiveEnum::Tuple(_)) => {} _ => {} } - //~^^ some variants are not matched explicitly - //~| some variants are not matched explicitly - // FIXME(Nadrieril): we should detect this #[deny(non_exhaustive_omitted_patterns)] match Some(non_enum) { + //~^ some variants are not matched explicitly Some(NonExhaustiveEnum::Unit) => {} Some(NonExhaustiveEnum::Tuple(_)) => {} _ => {} @@ -130,13 +126,12 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match NestedNonExhaustive::B { + //~^ some variants are not matched explicitly NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} NestedNonExhaustive::A(_) => {} NestedNonExhaustive::B => {} _ => {} } - //~^^ some variants are not matched explicitly - //~^^^^^ some variants are not matched explicitly #[warn(non_exhaustive_omitted_patterns)] match VariantNonExhaustive::Baz(1, 2) { @@ -162,18 +157,20 @@ fn main() { #[warn(non_exhaustive_omitted_patterns)] let MixedVisFields { a, b, .. } = MixedVisFields::default(); - // Ok: because this only has 1 variant + // Ok: this only has 1 variant #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { NonExhaustiveSingleVariant::A(true) => {} _ => {} } + // We can't catch the case below, so for consistency we don't catch this one either. #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { _ => {} } - //~^^ some variants are not matched explicitly + // We can't catch this case, because this would require digging fully through all the values of + // any type we encounter. We need to be able to only consider present constructors. #[deny(non_exhaustive_omitted_patterns)] match &NonExhaustiveSingleVariant::A(true) { _ => {} @@ -185,11 +182,11 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { + //~^ some variants are not matched explicitly UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} _ => {} } - //~^^ some variants are not matched explicitly // Ok: the feature is on and all variants are matched #[deny(non_exhaustive_omitted_patterns)] @@ -210,10 +207,10 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match OnlyUnstableEnum::Unstable { + //~^ some variants are not matched explicitly OnlyUnstableEnum::Unstable => {} _ => {} } - //~^^ some variants are not matched explicitly #[warn(non_exhaustive_omitted_patterns)] let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); @@ -240,14 +237,13 @@ fn main() { let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; //~^ refutable pattern in local binding - // Check that matching on a reference results in a correctly spanned diagnostic #[deny(non_exhaustive_omitted_patterns)] match &non_enum { + //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } - //~^^ some variants are not matched explicitly } #[deny(non_exhaustive_omitted_patterns)] diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr index db22aba6b8e6..7db61f1241ea 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -1,5 +1,5 @@ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:144:9 + --> $DIR/omitted-patterns.rs:139:9 | LL | VariantNonExhaustive::Bar { x, .. } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed @@ -7,13 +7,13 @@ LL | VariantNonExhaustive::Bar { x, .. } => {} = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:141:12 + --> $DIR/omitted-patterns.rs:136:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:149:9 + --> $DIR/omitted-patterns.rs:144:9 | LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed @@ -21,13 +21,13 @@ LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalReco = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:148:12 + --> $DIR/omitted-patterns.rs:143:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:157:29 + --> $DIR/omitted-patterns.rs:152:29 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed @@ -35,13 +35,13 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:156:12 + --> $DIR/omitted-patterns.rs:151:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:157:9 + --> $DIR/omitted-patterns.rs:152:9 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed @@ -50,7 +50,7 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:219:9 + --> $DIR/omitted-patterns.rs:216:9 | LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed @@ -58,13 +58,13 @@ LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:218:12 + --> $DIR/omitted-patterns.rs:215:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:227:9 + --> $DIR/omitted-patterns.rs:224:9 | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed @@ -72,16 +72,16 @@ LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:226:12 + --> $DIR/omitted-patterns.rs:223:12 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:58:9 + --> $DIR/omitted-patterns.rs:55:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered +LL | match non_enum { + | ^^^^^^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found @@ -92,10 +92,10 @@ LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:65:9 + --> $DIR/omitted-patterns.rs:63:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered +LL | match non_enum { + | ^^^^^^^^ pattern `NonExhaustiveEnum::Tuple(_)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found @@ -106,27 +106,13 @@ LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:75:9 + --> $DIR/omitted-patterns.rs:87:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Unit` not covered +LL | match (non_enum, true) { + | ^^^^^^^^^^^^^^^^ pattern `(NonExhaustiveEnum::Struct { .. }, _)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:70:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:90:9 - | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + = note: the matched value is of type `(NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here --> $DIR/omitted-patterns.rs:86:12 | @@ -134,118 +120,77 @@ LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:100:9 + --> $DIR/omitted-patterns.rs:102:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Unit` not covered +LL | match (true, non_enum) { + | ^^^^^^^^^^^^^^^^ pattern `(_, NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + = note: the matched value is of type `(bool, NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:95:12 + --> $DIR/omitted-patterns.rs:101:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:100:9 + --> $DIR/omitted-patterns.rs:110:11 | -LL | _ => {} - | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered +LL | match Some(non_enum) { + | ^^^^^^^^^^^^^^ pattern `Some(NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found - -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:108:9 - | -LL | _ => {} - | ^ patterns `NonExhaustiveEnum::Unit` and `NonExhaustiveEnum::Struct { .. }` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + = note: the matched value is of type `Option` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:104:12 + --> $DIR/omitted-patterns.rs:109:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:108:9 + --> $DIR/omitted-patterns.rs:128:11 | -LL | _ => {} - | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found - -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:134:32 - | -LL | NestedNonExhaustive::A(_) => {} - | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:131:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:136:9 - | -LL | _ => {} - | ^ pattern `NestedNonExhaustive::C` not covered +LL | match NestedNonExhaustive::B { + | ^^^^^^^^^^^^^^^^^^^^^^ patterns `NestedNonExhaustive::C`, `NestedNonExhaustive::A(NonExhaustiveEnum::Tuple(_))` and `NestedNonExhaustive::A(NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found - -error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:174:9 - | -LL | _ => {} - | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered - | - = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:172:12 + --> $DIR/omitted-patterns.rs:127:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:190:9 + --> $DIR/omitted-patterns.rs:184:11 | -LL | _ => {} - | ^ pattern `UnstableEnum::Unstable` not covered +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:186:12 + --> $DIR/omitted-patterns.rs:183:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:214:9 + --> $DIR/omitted-patterns.rs:209:11 | -LL | _ => {} - | ^ pattern `OnlyUnstableEnum::Unstable2` not covered +LL | match OnlyUnstableEnum::Unstable { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `OnlyUnstableEnum::Unstable2` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:211:12 + --> $DIR/omitted-patterns.rs:208:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding - --> $DIR/omitted-patterns.rs:240:9 + --> $DIR/omitted-patterns.rs:237:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; | ^^^^^^^^^^^^^^^ pattern `_` not covered @@ -259,19 +204,19 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit | ++++++++++++++++ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:248:9 + --> $DIR/omitted-patterns.rs:241:11 | -LL | _ => {} - | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered +LL | match &non_enum { + | ^^^^^^^^^ pattern `&NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms - = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + = note: the matched value is of type `&NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:244:12 + --> $DIR/omitted-patterns.rs:240:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors; 6 warnings emitted +error: aborting due to 10 previous errors; 6 warnings emitted For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs index 20b51a5cf3f7..1828fdef9013 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs @@ -19,10 +19,10 @@ fn main() { #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { + //~^ some variants are not matched explicitly UnstableEnum::Stable => {} _ => {} } - //~^^ some variants are not matched explicitly // Ok: although this is a bit odd, we don't have anything to report // since there is no stable variants and the feature is off diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr index 5b75cfb69fe0..27939176f75e 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr @@ -13,10 +13,10 @@ LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/stable-omitted-patterns.rs:23:9 + --> $DIR/stable-omitted-patterns.rs:21:11 | -LL | _ => {} - | ^ pattern `UnstableEnum::Stable2` not covered +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Stable2` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found From 6ed04af81c3bf79ee49f88e219fd168ff51886c8 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 8 Oct 2023 21:52:16 +0200 Subject: [PATCH 042/107] Make `multiple_unsafe_ops_per_block` ignore await desugaring The await desugaring contains two calls (`Poll::new_unchecked` and `get_context`) inside a single unsafe block. That violates the lint. --- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 7 +++++-- tests/ui/multiple_unsafe_ops_per_block.rs | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index fe35126aab21..2c42a7a3676a 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { /// ### What it does @@ -64,7 +64,10 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]) impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) { + if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) + || in_external_macro(cx.tcx.sess, block.span) + || block.span.is_desugaring(DesugaringKind::Await) + { return; } let mut unsafe_ops = vec![]; diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 4ef6f0ca92f2..8afb4df20af4 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -147,4 +147,11 @@ fn _field_fn_ptr(x: unsafe fn()) { } } +// await expands to an unsafe block with several operations, but this is fine.: #11312 +async fn await_desugaring_silent() { + async fn helper() {} + + helper().await; +} + fn main() {} From ba0f7e35346b24ceca630889873a1dccc28f8ae9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Oct 2023 12:05:05 +0000 Subject: [PATCH 043/107] Install binutils on FreeBSD CI to get an assembler --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 8b4efd4e3948..aa1a2bad2cf2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -3,7 +3,7 @@ task: freebsd_instance: image: freebsd-13-2-release-amd64 setup_rust_script: - - pkg install -y git bash + - pkg install -y git bash binutils - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh --default-toolchain none -y --profile=minimal target_cache: From bb6516ace013a2ec33ca1276b029786dfbb46ee1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 16 Oct 2023 00:29:28 +0200 Subject: [PATCH 044/107] [`unnecessary_lazy_eval`]: don't emit autofix suggestion if closure has return type --- .../src/methods/unnecessary_lazy_eval.rs | 12 ++- tests/ui/unnecessary_lazy_eval.fixed | 3 + tests/ui/unnecessary_lazy_eval.rs | 3 + tests/ui/unnecessary_lazy_eval.stderr | 94 +++++++++++-------- tests/ui/unnecessary_lazy_eval_unfixable.rs | 5 + .../ui/unnecessary_lazy_eval_unfixable.stderr | 10 +- 6 files changed, 85 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 47e2e744112c..4a651396f14d 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; +use hir::FnRetTy; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -27,7 +28,7 @@ pub(super) fn check<'tcx>( let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); if is_option || is_result || is_bool { - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { + if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind { let body = cx.tcx.hir().body(body); let body_expr = &body.value; @@ -48,7 +49,14 @@ pub(super) fn check<'tcx>( .iter() // bindings are checked to be unused above .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) - { + && matches!( + fn_decl.output, + FnRetTy::DefaultReturn(_) + | FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Infer, + .. + }) + ) { Applicability::MachineApplicable } else { // replacing the lambda may break type inference diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 304e7b7fd7f6..4778eaefdbdb 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -5,6 +5,7 @@ #![allow(clippy::map_identity)] #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unit_arg)] use std::ops::Deref; @@ -76,6 +77,8 @@ fn main() { let _ = opt.ok_or(2); let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); let _ = cond.then_some(astronomers_pi); + let _ = true.then_some({}); + let _ = true.then_some({}); // Should lint - Builtin deref let r = &1; diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index ddfa6bb3ef61..d4b7fd31b1b0 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -5,6 +5,7 @@ #![allow(clippy::map_identity)] #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unit_arg)] use std::ops::Deref; @@ -76,6 +77,8 @@ fn main() { let _ = opt.ok_or_else(|| 2); let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = cond.then(|| astronomers_pi); + let _ = true.then(|| -> _ {}); + let _ = true.then(|| {}); // Should lint - Builtin deref let r = &1; diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 4f1ca3748728..1b0db4759bba 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:68:13 + --> $DIR/unnecessary_lazy_eval.rs:69:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -10,7 +10,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:70:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -18,7 +18,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:70:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -26,7 +26,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:72:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -34,7 +34,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:73:13 + --> $DIR/unnecessary_lazy_eval.rs:74:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -42,7 +42,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:74:13 + --> $DIR/unnecessary_lazy_eval.rs:75:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -50,7 +50,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:75:13 + --> $DIR/unnecessary_lazy_eval.rs:76:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -58,7 +58,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:76:13 + --> $DIR/unnecessary_lazy_eval.rs:77:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -66,7 +66,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:77:13 + --> $DIR/unnecessary_lazy_eval.rs:78:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -74,15 +74,31 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:78:13 + --> $DIR/unnecessary_lazy_eval.rs:79:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- | | | help: use `then_some(..)` instead: `then_some(astronomers_pi)` +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:80:13 + | +LL | let _ = true.then(|| -> _ {}); + | ^^^^^---------------- + | | + | help: use `then_some(..)` instead: `then_some({})` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:81:13 + | +LL | let _ = true.then(|| {}); + | ^^^^^----------- + | | + | help: use `then_some(..)` instead: `then_some({})` + error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:82:13 + --> $DIR/unnecessary_lazy_eval.rs:85:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); | ^^^^^^^^--------------------- @@ -90,7 +106,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *r); | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:84:13 + --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); | ^^^^^^^^--------------------- @@ -98,7 +114,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *b); | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:86:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | ^^^^^^^^^^^^^^^^^--------------------- @@ -106,7 +122,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:87:13 + --> $DIR/unnecessary_lazy_eval.rs:90:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | ^^^^^^^^^^^^^^^^^--------------------- @@ -114,7 +130,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:90:13 + --> $DIR/unnecessary_lazy_eval.rs:93:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -122,7 +138,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:91:13 + --> $DIR/unnecessary_lazy_eval.rs:94:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -130,7 +146,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:92:28 + --> $DIR/unnecessary_lazy_eval.rs:95:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -138,7 +154,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:93:13 + --> $DIR/unnecessary_lazy_eval.rs:96:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -146,7 +162,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:94:35 + --> $DIR/unnecessary_lazy_eval.rs:97:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -154,7 +170,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:95:28 + --> $DIR/unnecessary_lazy_eval.rs:98:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -162,7 +178,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:98:13 + --> $DIR/unnecessary_lazy_eval.rs:101:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -170,7 +186,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:99:13 + --> $DIR/unnecessary_lazy_eval.rs:102:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -178,7 +194,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:100:13 + --> $DIR/unnecessary_lazy_eval.rs:103:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -186,7 +202,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:101:13 + --> $DIR/unnecessary_lazy_eval.rs:104:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -194,7 +210,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:102:13 + --> $DIR/unnecessary_lazy_eval.rs:105:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -202,7 +218,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:132:28 + --> $DIR/unnecessary_lazy_eval.rs:135:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -210,7 +226,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:133:13 + --> $DIR/unnecessary_lazy_eval.rs:136:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -218,7 +234,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:134:13 + --> $DIR/unnecessary_lazy_eval.rs:137:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -226,7 +242,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:140:13 + --> $DIR/unnecessary_lazy_eval.rs:143:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -234,7 +250,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:141:13 + --> $DIR/unnecessary_lazy_eval.rs:144:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -242,7 +258,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:142:13 + --> $DIR/unnecessary_lazy_eval.rs:145:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -250,7 +266,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:164:35 + --> $DIR/unnecessary_lazy_eval.rs:167:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -258,7 +274,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:165:35 + --> $DIR/unnecessary_lazy_eval.rs:168:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -266,7 +282,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:166:35 + --> $DIR/unnecessary_lazy_eval.rs:169:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -274,7 +290,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:168:35 + --> $DIR/unnecessary_lazy_eval.rs:171:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -282,7 +298,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:169:35 + --> $DIR/unnecessary_lazy_eval.rs:172:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -290,7 +306,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:170:35 + --> $DIR/unnecessary_lazy_eval.rs:173:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -298,7 +314,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:171:35 + --> $DIR/unnecessary_lazy_eval.rs:174:35 | LL | let _: Result = res. | ___________________________________^ @@ -312,5 +328,5 @@ LL | | or_else(|_| Ok(ext_str.some_field)); | | | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 38 previous errors +error: aborting due to 40 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs index 33685bfb738b..412d4aaafb4a 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -25,3 +25,8 @@ fn main() { let arr = [(Some(1),)]; Some(&0).and_then(|&i| arr[i].0); } + +fn issue11672() { + // Return type annotation helps type inference and removing it can break code + let _ = true.then(|| -> &[u8] { &[] }); +} diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 27fa560d4d77..95b02be91ca8 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -25,5 +25,13 @@ LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); | | | help: use `unwrap_or(..)` instead: `unwrap_or(2)` -error: aborting due to 3 previous errors +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:31:13 + | +LL | let _ = true.then(|| -> &[u8] { &[] }); + | ^^^^^------------------------- + | | + | help: use `then_some(..)` instead: `then_some({ &[] })` + +error: aborting due to 4 previous errors From 3960bc024c8d329c3c6c3d9986c52ca7510aa1d5 Mon Sep 17 00:00:00 2001 From: Francesco Guardiani Date: Mon, 16 Oct 2023 16:56:47 +0200 Subject: [PATCH 045/107] Now `declare_interior_mutable_const` and `borrow_interior_mutable_const` respect the `ignore-interior-mutability` configuration entry changelog: Now `declare_interior_mutable_const` and `borrow_interior_mutable_const` respect the `ignore-interior-mutability` configuration entry Signed-off-by: slinkydeveloper --- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/non_copy_const.rs | 315 ++++++++++-------- .../borrow_interior_mutable_const/clippy.toml | 1 + .../borrow_interior_mutable_const/ignore.rs | 37 ++ .../clippy.toml | 1 + .../declare_interior_mutable_const/ignore.rs | 46 +++ 6 files changed, 270 insertions(+), 133 deletions(-) create mode 100644 tests/ui-toml/borrow_interior_mutable_const/clippy.toml create mode 100644 tests/ui-toml/borrow_interior_mutable_const/ignore.rs create mode 100644 tests/ui-toml/declare_interior_mutable_const/clippy.toml create mode 100644 tests/ui-toml/declare_interior_mutable_const/ignore.rs diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2d02ce8b4f0a..3f04746cbeee 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -807,7 +807,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: suppress_restriction_lint_in_const, )) }); - store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst)); + let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); + store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone)); store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit)); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 2b4e3260c56b..613afa46a912 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -5,9 +5,10 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::in_constant; use clippy_utils::macros::macro_backtrace; +use clippy_utils::{def_path_def_ids, in_constant}; use if_chain::if_chain; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -15,9 +16,10 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; +use rustc_middle::query::Key; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::VariantIdx; @@ -126,128 +128,6 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } -fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env) -} - -fn is_value_unfrozen_raw<'tcx>( - cx: &LateContext<'tcx>, - result: Result>, ErrorHandled>, - ty: Ty<'tcx>, -) -> bool { - fn inner<'tcx>(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { - 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. - ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, - // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the - // contained value. - ty::Adt(def, ..) if def.is_union() => false, - ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)), - ty::Adt(def, _) if def.is_union() => false, - 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().try_to_u32().ok().unwrap()); - fields - .iter() - .copied() - .zip( - def.variants()[variant_index] - .fields - .iter() - .map(|field| field.ty(cx.tcx, args)), - ) - .any(|(field, ty)| 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)| inner(cx, *field, ty)), - ty::Tuple(tys) => val - .unwrap_branch() - .iter() - .zip(tys) - .any(|(field, ty)| inner(cx, *field, ty)), - _ => false, - } - } - result.map_or_else( - |err| { - // Consider `TooGeneric` cases as being unfrozen. - // This causes a false positive where an assoc const whose type is unfrozen - // have a value that is a frozen variant with a generic param (an example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). - // However, it prevents a number of false negatives that is, I think, important: - // 1. assoc consts in trait defs referring to consts of themselves (an example is - // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). - // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait - // defs (i.e. without substitute for `Self`). (e.g. borrowing - // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) - // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no - // enums. (An example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). - // One might be able to prevent these FNs correctly, and replace this with `false`; - // e.g. implementing `has_frozen_variant` described above, and not running this function - // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd - // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, - // similar to 2., but with the a frozen variant) (e.g. borrowing - // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). - // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). - matches!(err, ErrorHandled::TooGeneric(..)) - }, - |val| val.map_or(true, |val| inner(cx, val, ty)), - ) -} - -fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { - let def_id = body_id.hir_id.owner.to_def_id(); - let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::new(def_id, args); - let cid = rustc_middle::mir::interpret::GlobalId { - instance, - promoted: None, - }; - let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); - let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None); - is_value_unfrozen_raw(cx, result, ty) -} - -fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { - let args = cx.typeck_results().node_args(hir_id); - - let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None); - is_value_unfrozen_raw(cx, result, ty) -} - -pub fn const_eval_resolve<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ct: ty::UnevaluatedConst<'tcx>, - span: Option, -) -> EvalToValTreeResult<'tcx> { - match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) { - Ok(Some(instance)) => { - let cid = GlobalId { - instance, - promoted: None, - }; - tcx.const_eval_global_id_for_typeck(param_env, cid, span) - }, - Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))), - Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))), - } -} - #[derive(Copy, Clone)] enum Source { Item { item: Span }, @@ -292,13 +172,178 @@ fn lint(cx: &LateContext<'_>, source: Source) { }); } -declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); +#[derive(Clone)] +pub struct NonCopyConst { + ignore_interior_mutability: Vec, + ignore_mut_def_ids: FxHashSet, +} + +impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); + +impl NonCopyConst { + pub fn new(ignore_interior_mutability: Vec) -> Self { + Self { + ignore_interior_mutability, + ignore_mut_def_ids: FxHashSet::default(), + } + } + + fn is_ty_ignored(&self, ty: Ty<'_>) -> bool { + matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + } + + fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, + // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is + // 'unfrozen'. However, this code causes a false negative in which + // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell`. + // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` + // since it works when a pointer indirection involves (`Cell<*const T>`). + // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; + // but I'm not sure whether it's a decent way, if possible. + cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env) + } + + fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { + if self.is_ty_ignored(ty) { + 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. + ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, + // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the + // 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, _) if def.is_union() => false, + 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().try_to_u32().ok().unwrap()); + fields + .iter() + .copied() + .zip( + def.variants()[variant_index] + .fields + .iter() + .map(|field| field.ty(cx.tcx, args)), + ) + .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)), + _ => false, + } + } + + fn is_value_unfrozen_raw<'tcx>( + &self, + cx: &LateContext<'tcx>, + result: Result>, ErrorHandled>, + ty: Ty<'tcx>, + ) -> bool { + result.map_or_else( + |err| { + // Consider `TooGeneric` cases as being unfrozen. + // This causes a false positive where an assoc const whose type is unfrozen + // have a value that is a frozen variant with a generic param (an example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). + // However, it prevents a number of false negatives that is, I think, important: + // 1. assoc consts in trait defs referring to consts of themselves (an example is + // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). + // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait + // defs (i.e. without substitute for `Self`). (e.g. borrowing + // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) + // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no + // enums. (An example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). + // One might be able to prevent these FNs correctly, and replace this with `false`; + // e.g. implementing `has_frozen_variant` described above, and not running this function + // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd + // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, + // similar to 2., but with the a frozen variant) (e.g. borrowing + // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). + // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). + matches!(err, ErrorHandled::TooGeneric(..)) + }, + |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)), + ) + } + + fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + let def_id = body_id.hir_id.owner.to_def_id(); + let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); + let instance = ty::Instance::new(def_id, args); + let cid = rustc_middle::mir::interpret::GlobalId { + instance, + promoted: None, + }; + let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); + let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None); + self.is_value_unfrozen_raw(cx, result, ty) + } + + fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { + let args = cx.typeck_results().node_args(hir_id); + + let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None); + self.is_value_unfrozen_raw(cx, result, ty) + } + + pub fn const_eval_resolve<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ct: ty::UnevaluatedConst<'tcx>, + span: Option, + ) -> EvalToValTreeResult<'tcx> { + match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) { + Ok(Some(instance)) => { + let cid = GlobalId { + instance, + promoted: None, + }; + tcx.const_eval_global_id_for_typeck(param_env, cid, span) + }, + Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))), + Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))), + } + } +} impl<'tcx> LateLintPass<'tcx> for NonCopyConst { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + self.ignore_mut_def_ids.clear(); + let mut path = Vec::new(); + for ty in &self.ignore_interior_mutability { + path.extend(ty.split("::")); + for id in def_path_def_ids(cx, &path[..]) { + self.ignore_mut_def_ids.insert(id); + } + path.clear(); + } + } + fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(.., body_id) = it.kind { let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); - if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + if !ignored_macro(cx, it) + && !self.is_ty_ignored(ty) + && Self::is_unfrozen(cx, ty) + && self.is_value_unfrozen_poly(cx, body_id, ty) + { lint(cx, Source::Item { item: it.span }); } } @@ -311,7 +356,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if is_unfrozen(cx, normalized) + if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) // When there's no default value, lint it only according to its type; // in other words, lint consts whose value *could* be unfrozen, not definitely is. // This feels inconsistent with how the lint treats generic types, @@ -324,7 +369,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // i.e. having an enum doesn't necessary mean a type has a frozen variant. // And, implementing it isn't a trivial task; it'll probably end up // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized)) + && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized)) { lint(cx, Source::Assoc { item: trait_item.span }); } @@ -367,8 +412,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if is_unfrozen(cx, normalized); - if is_value_unfrozen_poly(cx, *body_id, normalized); + if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized); + if self.is_value_unfrozen_poly(cx, *body_id, normalized); then { lint( cx, @@ -384,7 +429,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) { + if !self.is_ty_ignored(ty) + && Self::is_unfrozen(cx, ty) + && self.is_value_unfrozen_poly(cx, *body_id, normalized) + { lint(cx, Source::Assoc { item: impl_item.span }); } }, @@ -478,7 +526,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { + if !self.is_ty_ignored(ty) + && Self::is_unfrozen(cx, ty) + && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) + { lint(cx, Source::Expr { expr: expr.span }); } } diff --git a/tests/ui-toml/borrow_interior_mutable_const/clippy.toml b/tests/ui-toml/borrow_interior_mutable_const/clippy.toml new file mode 100644 index 000000000000..34a1036e891d --- /dev/null +++ b/tests/ui-toml/borrow_interior_mutable_const/clippy.toml @@ -0,0 +1 @@ +ignore-interior-mutability = ["borrow_interior_mutable_const_ignore::Counted"] \ No newline at end of file diff --git a/tests/ui-toml/borrow_interior_mutable_const/ignore.rs b/tests/ui-toml/borrow_interior_mutable_const/ignore.rs new file mode 100644 index 000000000000..79c7cef6ce1b --- /dev/null +++ b/tests/ui-toml/borrow_interior_mutable_const/ignore.rs @@ -0,0 +1,37 @@ +//@compile-flags: --crate-name borrow_interior_mutable_const_ignore + +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +use core::cell::Cell; +use std::cmp::{Eq, PartialEq}; +use std::collections::{HashMap, HashSet}; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; +use std::sync::atomic::{AtomicUsize, Ordering}; + +struct Counted { + count: AtomicUsize, + val: T, +} + +impl Counted { + const fn new(val: T) -> Self { + Self { + count: AtomicUsize::new(0), + val, + } + } +} + +enum OptionalCell { + Unfrozen(Counted), + Frozen, +} + +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Counted::new(true)); +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +fn main() { + let _ = &UNFROZEN_VARIANT; +} diff --git a/tests/ui-toml/declare_interior_mutable_const/clippy.toml b/tests/ui-toml/declare_interior_mutable_const/clippy.toml new file mode 100644 index 000000000000..71d13212e2a8 --- /dev/null +++ b/tests/ui-toml/declare_interior_mutable_const/clippy.toml @@ -0,0 +1 @@ +ignore-interior-mutability = ["declare_interior_mutable_const_ignore::Counted"] \ No newline at end of file diff --git a/tests/ui-toml/declare_interior_mutable_const/ignore.rs b/tests/ui-toml/declare_interior_mutable_const/ignore.rs new file mode 100644 index 000000000000..6385cf4f852f --- /dev/null +++ b/tests/ui-toml/declare_interior_mutable_const/ignore.rs @@ -0,0 +1,46 @@ +//@compile-flags: --crate-name declare_interior_mutable_const_ignore + +#![warn(clippy::declare_interior_mutable_const)] +#![allow(clippy::borrow_interior_mutable_const)] + +use core::cell::Cell; +use std::cmp::{Eq, PartialEq}; +use std::collections::{HashMap, HashSet}; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; +use std::sync::atomic::{AtomicUsize, Ordering}; + +struct Counted { + count: AtomicUsize, + val: T, +} + +impl Counted { + const fn new(val: T) -> Self { + Self { + count: AtomicUsize::new(0), + val, + } + } +} + +enum OptionalCell { + Unfrozen(Counted), + Frozen, +} + +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Counted::new(true)); +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +const fn unfrozen_variant() -> OptionalCell { + OptionalCell::Unfrozen(Counted::new(true)) +} + +const fn frozen_variant() -> OptionalCell { + OptionalCell::Frozen +} + +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); +const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); + +fn main() {} From 8c3eda36df7aa23d857a5cc4337eb53a5a922219 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 16 Oct 2023 15:22:17 -0700 Subject: [PATCH 046/107] docs: add Rust logo to more compiler crates c6e6ecb1afea9695a42d0f148ce153536b279eb5 added it to some of the compiler's crates, but avoided adding it to all of them to reduce bit-rot. This commit adds to more. --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 522fe7e425b9..8992de5a923f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![feature(rustc_private)] // Note: please avoid adding other feature gates where possible #![warn(rust_2018_idioms)] From 9ee26d078db28d39f34ab2979a393be4b43019c8 Mon Sep 17 00:00:00 2001 From: Arthur Lafrance Date: Mon, 16 Oct 2023 13:52:50 -0700 Subject: [PATCH 047/107] fix lint failures in clippy --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/manual_let_else.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 2 +- clippy_lints/src/matches/manual_utils.rs | 4 ++-- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/non_octal_unix_permissions.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 2 +- clippy_utils/src/macros.rs | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 14877385646a..5134cf66050c 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -701,7 +701,7 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { if let Some(parent) = get_parent_expr(cx, e) - && parent.span.ctxt() == e.span.ctxt() + && parent.span.eq_ctxt(e.span) { match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 6197b5b19eb4..70a467dde613 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -241,7 +241,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio }, ], _, - ) if key_span.ctxt() == expr.span.ctxt() => { + ) if key_span.eq_ctxt(expr.span) => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; let expr = ContainsExpr { negated, diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index d03480c21084..4ebf0e9667df 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -274,7 +274,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { for element in array { if_chain! { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt(); + if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span); let space_span = lhs.span.between(op.span); if let Some(space_snippet) = snippet_opt(cx, space_span); let lint_span = lhs.span.with_lo(lhs.span.hi()); diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 4e9d77ea156a..79d728a021c3 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -31,7 +31,7 @@ impl LateLintPass<'_> for UnderscoreTyped { if !in_external_macro(cx.tcx.sess, local.span); if let Some(ty) = local.ty; // Ensure that it has a type defined if let TyKind::Infer = &ty.kind; // that type is '_' - if local.span.ctxt() == ty.span.ctxt(); + if local.span.eq_ctxt(ty.span); then { // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 2117308cd400..86bbdb4ea199 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -59,7 +59,7 @@ impl<'tcx> QuestionMark { let Some(init) = local.init && local.els.is_none() && local.ty.is_none() && - init.span.ctxt() == stmt.span.ctxt() && + init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 33a052c41a38..29b935fb61a8 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -57,7 +57,7 @@ fn check_arm<'tcx>( } }, }; - if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt(); + if outer_pat.span.eq_ctxt(inner_scrutinee.span); // match expression must be a local binding // match { .. } if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)); diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index 6b611f567ae2..781ee138c76f 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -119,7 +119,7 @@ where // it's being passed by value. let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); - let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX { format!("({scrutinee_str})") } else { scrutinee_str.into() @@ -130,7 +130,7 @@ where if_chain! { if !some_expr.needs_unsafe_block; if let Some(func) = can_pass_as_func(cx, id, some_expr.expr); - if func.span.ctxt() == some_expr.expr.span.ctxt(); + if func.span.eq_ctxt(some_expr.expr.span); then { snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() } else { diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 5464e455dea4..e70a1bc98799 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( // lint, with note if neither arg is > 1 line and both map() and // unwrap_or_else() have the same span let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt(); + let same_span = map_arg.span.eq_ctxt(unwrap_arg.span); if same_span && !multiline { let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 7b0f7eaf1f06..0e834fb3ac76 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -125,7 +125,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind; if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; - if expr.span.ctxt() == inner_expr.span.ctxt(); + if expr.span.eq_ctxt(inner_expr.span); let expr_ty = cx.typeck_results().expr_ty(expr); let inner_ty = cx.typeck_results().expr_ty(inner_expr); if expr_ty == inner_ty; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index d47728f190ab..e94e45899660 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { || (path.ident.name == sym!(set_mode) && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); then { let Some(snip) = snippet_opt(cx, param.span) else { @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); if let Some(snip) = snippet_opt(cx, param.span); if !snip.starts_with("0o"); then { diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 534b2762ba76..8193057a6eb2 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { let Some(body_expr) = desugar_async_block(cx, expr) && let Some(expr) = desugar_await(peel_blocks(body_expr)) && // The await prefix must not come from a macro as its content could change in the future. - expr.span.ctxt() == body_expr.span.ctxt() && + expr.span.eq_ctxt(body_expr.span) && // An async block does not have immediate side-effects from a `.await` point-of-view. (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) && let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt()) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index db870ec4c5b6..12da29f11089 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; - if deref_target.span.ctxt() == e.span.ctxt(); + if deref_target.span.eq_ctxt(e.span); if !addrof_target.span.from_expansion(); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 8e156b8829b9..39cd289b67ad 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -33,7 +33,7 @@ impl LateLintPass<'_> for ConfusingXorAndPow { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Binary(op, left, right) = &expr.kind && op.node == BinOpKind::BitXor - && left.span.ctxt() == right.span.ctxt() + && left.span.eq_ctxt(right.span) && let ExprKind::Lit(lit_left) = &left.kind && let ExprKind::Lit(lit_right) = &right.kind && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..)) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index eaf590f6ad77..46ce4ffdce5d 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -245,7 +245,7 @@ impl<'a> PanicExpn<'a> { return None; }; let result = match name { - "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty, + "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty, "panic" | "panic_str" => Self::Str(arg), "panic_display" | "panic_cold_display" => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { From 2f461b74ffcf1359bb20755eef6d72ad95fae892 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 23 Aug 2023 15:46:58 +0200 Subject: [PATCH 048/107] [RFC 3127 - Trim Paths]: Condition remapped filepath on remap scopes --- src/common.rs | 3 ++- src/debuginfo/line_info.rs | 15 +++++++++++++-- src/debuginfo/mod.rs | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/common.rs b/src/common.rs index 8958369267e5..7a3ae6ebf52f 100644 --- a/src/common.rs +++ b/src/common.rs @@ -414,11 +414,12 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { // Note: must be kept in sync with get_caller_location from cg_ssa pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> { let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| { + use rustc_session::RemapFileNameExt; let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo()); let const_loc = fx.tcx.const_caller_location(( rustc_span::symbol::Symbol::intern( - &caller.file.name.prefer_remapped().to_string_lossy(), + &caller.file.name.for_codegen(&fx.tcx.sess).to_string_lossy(), ), caller.line as u32, caller.col_display as u32 + 1, diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index d00d19f9a80c..6230ca15d6e1 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -95,7 +95,11 @@ impl DebugContext { match &source_file.name { FileName::Real(path) => { let (dir_path, file_name) = - split_path_dir_and_file(path.remapped_path_if_available()); + split_path_dir_and_file(if self.should_remap_filepaths { + path.remapped_path_if_available() + } else { + path.local_path_if_available() + }); let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str()); let file_name = osstr_as_utf8_bytes(file_name); @@ -116,7 +120,14 @@ impl DebugContext { filename => { let dir_id = line_program.default_directory(); let dummy_file_name = LineString::new( - filename.prefer_remapped().to_string().into_bytes(), + filename + .display(if self.should_remap_filepaths { + FileNameDisplayPreference::Remapped + } else { + FileNameDisplayPreference::Local + }) + .to_string() + .into_bytes(), line_program.encoding(), line_strings, ); diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 9e78cc259ce1..84bfe15c13f6 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -31,6 +31,8 @@ pub(crate) struct DebugContext { dwarf: DwarfUnit, unit_range_list: RangeList, + + should_remap_filepaths: bool, } pub(crate) struct FunctionDebugContext { @@ -63,12 +65,18 @@ impl DebugContext { let mut dwarf = DwarfUnit::new(encoding); + let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen(); + let producer = producer(); let comp_dir = tcx .sess .opts .working_dir - .to_string_lossy(FileNameDisplayPreference::Remapped) + .to_string_lossy(if should_remap_filepaths { + FileNameDisplayPreference::Remapped + } else { + FileNameDisplayPreference::Local + }) .into_owned(); let (name, file_info) = match tcx.sess.local_crate_source_file() { Some(path) => { @@ -102,7 +110,12 @@ impl DebugContext { root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); } - DebugContext { endian, dwarf, unit_range_list: RangeList(Vec::new()) } + DebugContext { + endian, + dwarf, + unit_range_list: RangeList(Vec::new()), + should_remap_filepaths, + } } pub(crate) fn define_function( From 09535a5d303cd9a57719bf2128078edf82507d75 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 23 Aug 2023 17:58:21 +0200 Subject: [PATCH 049/107] [RFC 3127 - Trim Paths]: Fix building tools (rustdoc, clippy, ...) --- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c38a3e81b0f7..c8600badf18e 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -494,7 +494,7 @@ impl SerializableSpan { let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); Self { - path: format!("{}", loc.file.name.prefer_remapped()), + path: format!("{}", loc.file.name.prefer_remapped_unconditionaly()), line: loc.line, } } From bc97f7d0c91649a7cdedbabde0edc9e33854f6a9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 12:00:21 +0200 Subject: [PATCH 050/107] Don't emit `needless_pass_by_ref_mut` if the variable is used in an unsafe block or function --- clippy_lints/src/needless_pass_by_ref_mut.rs | 77 ++++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 212d6234bdb3..e7424ba7c6db 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor}; use rustc_hir::{ - Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath, + BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, + PatKind, QPath, }; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id); let is_async = match kind { FnKind::ItemFn(.., header) => { + if header.is_unsafe() { + // We don't check unsafe functions. + return; + } let attrs = cx.tcx.hir().attrs(hir_id); if header.abi != Abi::Rust || requires_exact_signature(attrs) { return; } header.is_async() }, - FnKind::Method(.., sig) => sig.header.is_async(), + FnKind::Method(.., sig) => { + if sig.header.is_unsafe() { + // We don't check unsafe functions. + return; + } + sig.header.is_async() + }, FnKind::Closure => return, }; @@ -304,10 +315,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { } self.aliases.insert(alias, target); } + + // The goal here is to find if the current scope is unsafe or not. It stops when it finds + // a function or an unsafe block. + fn is_in_unsafe_block(&self, item: HirId) -> bool { + let hir = self.tcx.hir(); + for (parent, node) in hir.parent_iter(item) { + if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) { + return fn_sig.header.is_unsafe(); + } else if let Node::Block(block) = node { + if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) { + return true; + } + } + } + false + } } impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { - fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + #[allow(clippy::if_same_then_else)] + fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { if let euv::Place { base: euv::PlaceBase::Local(vid) @@ -327,13 +355,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { && matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) { self.add_mutably_used_var(*vid); + } else if self.is_in_unsafe_block(id) { + // If we are in an unsafe block, any operation on this variable must not be warned + // upon! + self.add_mutably_used_var(*vid); } self.prev_bind = None; self.prev_move_to_closure.remove(vid); } } - fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) { + #[allow(clippy::if_same_then_else)] + fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) { self.prev_bind = None; if let euv::Place { base: @@ -355,6 +388,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { || (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut)) { self.add_mutably_used_var(*vid); + } else if self.is_in_unsafe_block(id) { + // If we are in an unsafe block, any operation on this variable must not be warned + // upon! + self.add_mutably_used_var(*vid); } } else if borrow == ty::ImmBorrow { // If there is an `async block`, it'll contain a call to a closure which we need to @@ -397,7 +434,21 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } - fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + fn copy(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { + if let euv::Place { + base: + euv::PlaceBase::Local(vid) + | euv::PlaceBase::Upvar(UpvarId { + var_path: UpvarPath { hir_id: vid }, + .. + }), + .. + } = &cmt.place + { + if self.is_in_unsafe_block(id) { + self.add_mutably_used_var(*vid); + } + } self.prev_bind = None; } @@ -427,8 +478,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } - fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { + fn bind(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { self.prev_bind = Some(id); + if let euv::Place { + base: + euv::PlaceBase::Local(vid) + | euv::PlaceBase::Upvar(UpvarId { + var_path: UpvarPath { hir_id: vid }, + .. + }), + .. + } = &cmt.place + { + if self.is_in_unsafe_block(id) { + self.add_mutably_used_var(*vid); + } + } } } From 80a092c6dfa046780c930cf709680d5fb7121df0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 12:01:23 +0200 Subject: [PATCH 051/107] Add test for `needless_pass_by_ref_mut` to ensure that the lint is not emitted if variable is used in an unsafe block or function --- tests/ui/needless_pass_by_ref_mut.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index 93f94b384af2..7f642e53dfb3 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -276,6 +276,18 @@ async fn _f(v: &mut Vec<()>) { _ = || || x; } +struct Data { + value: T, +} +// Unsafe functions should not warn. +unsafe fn get_mut_unchecked(ptr: &mut NonNull>) -> &mut T { + &mut (*ptr.as_ptr()).value +} +// Unsafe blocks should not warn. +fn get_mut_unchecked2(ptr: &mut NonNull>) -> &mut T { + unsafe { &mut (*ptr.as_ptr()).value } +} + fn main() { let mut u = 0; let mut v = vec![0]; From d9dc5ee072d102c6a75cdcedebc25b3babf37965 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 18 Oct 2023 13:57:19 +0200 Subject: [PATCH 052/107] AliasTy::new instead of tcx method --- clippy_utils/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2d305a63eca1..673b259523e1 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1133,7 +1133,7 @@ pub fn make_projection<'tcx>( #[cfg(debug_assertions)] assert_generic_args_match(tcx, assoc_item.def_id, args); - Some(tcx.mk_alias_ty(assoc_item.def_id, args)) + Some(ty::AliasTy::new(tcx, assoc_item.def_id, args)) } helper( tcx, From 8b02dac54244efc2968c164bff129f2a64bb845e Mon Sep 17 00:00:00 2001 From: jonboh Date: Tue, 17 Oct 2023 18:34:27 +0200 Subject: [PATCH 053/107] add lint for struct field names side effect for `enum_variants`: use .first() instead of .get(0) in enum_variants lint move to_camel_case to str_util module move module, enum and struct name repetitions check to a single file `item_name_repetitions` rename enum_variants threshold config option --- CHANGELOG.md | 2 + book/src/lint_configuration.md | 10 + clippy_lints/src/declared_lints.rs | 7 +- clippy_lints/src/functions/mod.rs | 1 + ...m_variants.rs => item_name_repetitions.rs} | 211 ++++++++--- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/only_used_in_recursion.rs | 1 + clippy_lints/src/types/mod.rs | 2 +- clippy_lints/src/utils/conf.rs | 4 + clippy_utils/src/str_utils.rs | 53 +++ .../enum_variant_names/enum_variant_names.rs | 16 - .../enum_variant_names.stderr | 18 - .../threshold0}/clippy.toml | 1 + .../threshold0/item_name_repetitions.rs} | 2 + .../threshold5}/clippy.toml | 1 + .../threshold5/item_name_repetitions.rs | 32 ++ .../threshold5/item_name_repetitions.stderr | 34 ++ .../pub_crate_missing_doc.rs | 1 + .../pub_crate_missing_doc.stderr | 14 +- .../toml_unknown_key/conf_unknown_key.stderr | 2 + tests/ui/manual_filter_map.fixed | 1 + tests/ui/manual_filter_map.rs | 1 + tests/ui/manual_filter_map.stderr | 76 ++-- tests/ui/manual_find_map.fixed | 1 + tests/ui/manual_find_map.rs | 1 + tests/ui/manual_find_map.stderr | 78 ++--- tests/ui/min_ident_chars.rs | 1 + tests/ui/min_ident_chars.stderr | 58 +-- tests/ui/misnamed_getters.fixed | 1 + tests/ui/misnamed_getters.rs | 1 + tests/ui/misnamed_getters.stderr | 36 +- tests/ui/needless_bool/fixable.fixed | 3 +- tests/ui/needless_bool/fixable.rs | 3 +- tests/ui/needless_bool/fixable.stderr | 42 +-- tests/ui/rest_pat_in_fully_bound_structs.rs | 1 + .../ui/rest_pat_in_fully_bound_structs.stderr | 6 +- tests/ui/struct_fields.rs | 331 ++++++++++++++++++ tests/ui/struct_fields.stderr | 265 ++++++++++++++ 38 files changed, 1087 insertions(+), 237 deletions(-) rename clippy_lints/src/{enum_variants.rs => item_name_repetitions.rs} (60%) delete mode 100644 tests/ui-toml/enum_variant_names/enum_variant_names.rs delete mode 100644 tests/ui-toml/enum_variant_names/enum_variant_names.stderr rename tests/ui-toml/{enum_variants_threshold0 => item_name_repetitions/threshold0}/clippy.toml (50%) rename tests/ui-toml/{enum_variants_threshold0/enum_variants_name_threshold.rs => item_name_repetitions/threshold0/item_name_repetitions.rs} (65%) rename tests/ui-toml/{enum_variant_names => item_name_repetitions/threshold5}/clippy.toml (50%) create mode 100644 tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs create mode 100644 tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr create mode 100644 tests/ui/struct_fields.rs create mode 100644 tests/ui/struct_fields.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index fef25ad8635a..26c9877dbffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5463,6 +5463,7 @@ Released 2018-09-13 [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools +[`struct_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names [`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter [`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl @@ -5625,6 +5626,7 @@ Released 2018-09-13 [`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold [`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack [`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold +[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold [`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold [`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 2c958ccbbc24..2c1ec748a4e6 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -273,6 +273,16 @@ The minimum number of enum variants for the lints about variant names to trigger * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) +## `struct-field-name-threshold` +The minimum number of struct fields for the lints about field names to trigger + +**Default Value:** `3` (`u64`) + +--- +**Affected lints:** +* [`struct_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_variant_names) + + ## `enum-variant-size-threshold` The maximum size of an enum's variant to avoid box suggestion diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 481c44031cf7..77438b27f900 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -154,9 +154,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO, crate::entry::MAP_ENTRY_INFO, crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO, - crate::enum_variants::ENUM_VARIANT_NAMES_INFO, - crate::enum_variants::MODULE_INCEPTION_INFO, - crate::enum_variants::MODULE_NAME_REPETITIONS_INFO, crate::equatable_if_let::EQUATABLE_IF_LET_INFO, crate::error_impl_error::ERROR_IMPL_ERROR_INFO, crate::escape::BOXED_LOCAL_INFO, @@ -226,6 +223,10 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, + crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO, + crate::item_name_repetitions::MODULE_INCEPTION_INFO, + crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO, + crate::item_name_repetitions::STRUCT_FIELD_NAMES_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 55ebd44a60c2..716908483e9d 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -360,6 +360,7 @@ declare_clippy_lint! { } #[derive(Copy, Clone)] +#[allow(clippy::struct_field_names)] pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/item_name_repetitions.rs similarity index 60% rename from clippy_lints/src/enum_variants.rs rename to clippy_lints/src/item_name_repetitions.rs index e332f681b6db..8b4984da3dd1 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -1,9 +1,10 @@ //! lint on enum variants that are prefixed or suffixed by the same characters use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; +use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; -use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start}; -use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant}; +use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; +use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -103,32 +104,184 @@ declare_clippy_lint! { style, "modules that have the same name as their parent module" } +declare_clippy_lint! { + /// ### What it does + /// Detects struct fields that are prefixed or suffixed + /// by the same characters or the name of the struct itself. + /// + /// ### Why is this bad? + /// Information common to all struct fields is better represented in the struct name. + /// + /// ### Limitations + /// Characters with no casing will be considered when comparing prefixes/suffixes + /// This applies to numbers and non-ascii characters without casing + /// e.g. `foo1` and `foo2` is considered to have different prefixes + /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹` + /// + /// ### Example + /// ```rust + /// struct Cake { + /// cake_sugar: u8, + /// cake_flour: u8, + /// cake_eggs: u8 + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct Cake { + /// sugar: u8, + /// flour: u8, + /// eggs: u8 + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub STRUCT_FIELD_NAMES, + pedantic, + "structs where all fields share a prefix/postfix or contain the name of the struct" +} -pub struct EnumVariantNames { +pub struct ItemNameRepetitions { modules: Vec<(Symbol, String, OwnerId)>, - threshold: u64, + enum_threshold: u64, + struct_threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool, } -impl EnumVariantNames { +impl ItemNameRepetitions { #[must_use] - pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self { + pub fn new( + enum_threshold: u64, + struct_threshold: u64, + avoid_breaking_exported_api: bool, + allow_private_module_inception: bool, + ) -> Self { Self { modules: Vec::new(), - threshold, + enum_threshold, + struct_threshold, avoid_breaking_exported_api, allow_private_module_inception, } } } -impl_lint_pass!(EnumVariantNames => [ +impl_lint_pass!(ItemNameRepetitions => [ ENUM_VARIANT_NAMES, + STRUCT_FIELD_NAMES, MODULE_NAME_REPETITIONS, MODULE_INCEPTION ]); +#[must_use] +fn have_no_extra_prefix(prefixes: &[&str]) -> bool { + prefixes.iter().all(|p| p == &"" || p == &"_") +} + +fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) { + if (fields.len() as u64) < threshold { + return; + } + + check_struct_name_repetition(cx, item, fields); + + // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them. + // this prevents linting in macros in which the location of the field identifier names differ + if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) { + return; + } + + let mut pre: Vec<&str> = match fields.first() { + Some(first_field) => first_field.ident.name.as_str().split('_').collect(), + None => return, + }; + let mut post = pre.clone(); + post.reverse(); + for field in fields { + let field_split: Vec<&str> = field.ident.name.as_str().split('_').collect(); + if field_split.len() == 1 { + return; + } + + pre = pre + .into_iter() + .zip(field_split.iter()) + .take_while(|(a, b)| &a == b) + .map(|e| e.0) + .collect(); + post = post + .into_iter() + .zip(field_split.iter().rev()) + .take_while(|(a, b)| &a == b) + .map(|e| e.0) + .collect(); + } + let prefix = pre.join("_"); + post.reverse(); + let postfix = match post.last() { + Some(&"") => post.join("_") + "_", + Some(_) | None => post.join("_"), + }; + if fields.len() > 1 { + let (what, value) = match ( + prefix.is_empty() || prefix.chars().all(|c| c == '_'), + postfix.is_empty(), + ) { + (true, true) => return, + (false, _) => ("pre", prefix), + (true, false) => ("post", postfix), + }; + span_lint_and_help( + cx, + STRUCT_FIELD_NAMES, + item.span, + &format!("all fields have the same {what}fix: `{value}`"), + None, + &format!("remove the {what}fixes"), + ); + } +} + +fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) { + let snake_name = to_snake_case(item.ident.name.as_str()); + let item_name_words: Vec<&str> = snake_name.split('_').collect(); + for field in fields { + if field.ident.span.eq_ctxt(item.ident.span) { + //consider linting only if the field identifier has the same SyntaxContext as the item(struct) + let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect(); + if field_words.len() >= item_name_words.len() { + // if the field name is shorter than the struct name it cannot contain it + if field_words.iter().zip(item_name_words.iter()).all(|(a, b)| a == b) { + span_lint_hir( + cx, + STRUCT_FIELD_NAMES, + field.hir_id, + field.span, + "field name starts with the struct's name", + ); + } + if field_words.len() > item_name_words.len() { + // lint only if the end is not covered by the start + if field_words + .iter() + .rev() + .zip(item_name_words.iter().rev()) + .all(|(a, b)| a == b) + { + span_lint_hir( + cx, + STRUCT_FIELD_NAMES, + field.hir_id, + field.span, + "field name ends with the struct's name", + ); + } + } + } + } + } +} + fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) { let name = variant.ident.name.as_str(); let item_name_chars = item_name.chars().count(); @@ -218,35 +371,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n ); } -#[must_use] -fn have_no_extra_prefix(prefixes: &[&str]) -> bool { - prefixes.iter().all(|p| p == &"" || p == &"_") -} - -#[must_use] -fn to_camel_case(item_name: &str) -> String { - let mut s = String::new(); - let mut up = true; - for c in item_name.chars() { - if c.is_uppercase() { - // we only turn snake case text into CamelCase - return item_name.to_string(); - } - if c == '_' { - up = true; - continue; - } - if up { - up = false; - s.extend(c.to_uppercase()); - } else { - s.push(c); - } - } - s -} - -impl LateLintPass<'_> for EnumVariantNames { +impl LateLintPass<'_> for ItemNameRepetitions { fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) { let last = self.modules.pop(); assert!(last.is_some()); @@ -303,9 +428,15 @@ impl LateLintPass<'_> for EnumVariantNames { } } } - if let ItemKind::Enum(ref def, _) = item.kind { - if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) { - check_variant(cx, self.threshold, def, item_name, item.span); + if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) + && span_is_local(item.span) + { + match item.kind { + ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span), + ItemKind::Struct(VariantData::Struct(fields, _), _) => { + check_fields(cx, self.struct_threshold, item, fields); + }, + _ => (), } } self.modules.push((item.ident.name, item_camel, item.owner_id)); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2d02ce8b4f0a..7b97adcf2268 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -121,7 +121,6 @@ mod empty_structs_with_brackets; mod endian_bytes; mod entry; mod enum_clike; -mod enum_variants; mod equatable_if_let; mod error_impl_error; mod escape; @@ -166,6 +165,7 @@ mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; +mod item_name_repetitions; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; @@ -852,10 +852,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let enum_variant_name_threshold = conf.enum_variant_name_threshold; + let struct_field_name_threshold = conf.struct_field_name_threshold; let allow_private_module_inception = conf.allow_private_module_inception; store.register_late_pass(move |_| { - Box::new(enum_variants::EnumVariantNames::new( + Box::new(item_name_repetitions::ItemNameRepetitions::new( enum_variant_name_threshold, + struct_field_name_threshold, avoid_breaking_exported_api, allow_private_module_inception, )) diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 3dc652f9dc02..f0f8d510c7e2 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -134,6 +134,7 @@ impl Usage { /// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the /// `DefId` of the function paired with the parameter's index. #[derive(Default)] +#[allow(clippy::struct_field_names)] struct Params { params: Vec, by_id: HirIdMap, diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 71a4b3fba1b5..788678a63b76 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -578,7 +578,7 @@ impl Types { } } -#[allow(clippy::struct_excessive_bools)] +#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)] #[derive(Clone, Copy, Default)] struct CheckTyContext { is_in_trait_impl: bool, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 23da1de77303..519e27b03674 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -360,6 +360,10 @@ define_Conf! { /// /// The minimum number of enum variants for the lints about variant names to trigger (enum_variant_name_threshold: u64 = 3), + /// Lint: STRUCT_VARIANT_NAMES. + /// + /// The minimum number of struct fields for the lints about field names to trigger + (struct_field_name_threshold: u64 = 3), /// Lint: LARGE_ENUM_VARIANT. /// /// The maximum size of an enum's variant to avoid box suggestion diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index 03a9d3c25fd9..69c25b427e1c 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -236,6 +236,59 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount { }) } +/// Returns a `snake_case` version of the input +/// ``` +/// use clippy_utils::str_utils::to_snake_case; +/// assert_eq!(to_snake_case("AbcDef"), "abc_def"); +/// assert_eq!(to_snake_case("ABCD"), "a_b_c_d"); +/// assert_eq!(to_snake_case("AbcDD"), "abc_d_d"); +/// assert_eq!(to_snake_case("Abc1DD"), "abc1_d_d"); +/// ``` +pub fn to_snake_case(name: &str) -> String { + let mut s = String::new(); + for (i, c) in name.chars().enumerate() { + if c.is_uppercase() { + // characters without capitalization are considered lowercase + if i != 0 { + s.push('_'); + } + s.extend(c.to_lowercase()); + } else { + s.push(c); + } + } + s +} +/// Returns a `CamelCase` version of the input +/// ``` +/// use clippy_utils::str_utils::to_camel_case; +/// assert_eq!(to_camel_case("abc_def"), "AbcDef"); +/// assert_eq!(to_camel_case("a_b_c_d"), "ABCD"); +/// assert_eq!(to_camel_case("abc_d_d"), "AbcDD"); +/// assert_eq!(to_camel_case("abc1_d_d"), "Abc1DD"); +/// ``` +pub fn to_camel_case(item_name: &str) -> String { + let mut s = String::new(); + let mut up = true; + for c in item_name.chars() { + if c.is_uppercase() { + // we only turn snake case text into CamelCase + return item_name.to_string(); + } + if c == '_' { + up = true; + continue; + } + if up { + up = false; + s.extend(c.to_uppercase()); + } else { + s.push(c); + } + } + s +} + #[cfg(test)] mod test { use super::*; diff --git a/tests/ui-toml/enum_variant_names/enum_variant_names.rs b/tests/ui-toml/enum_variant_names/enum_variant_names.rs deleted file mode 100644 index 8f4e178ccfe1..000000000000 --- a/tests/ui-toml/enum_variant_names/enum_variant_names.rs +++ /dev/null @@ -1,16 +0,0 @@ -enum Foo { - AFoo, - BFoo, - CFoo, - DFoo, -} -enum Foo2 { - //~^ ERROR: all variants have the same postfix - AFoo, - BFoo, - CFoo, - DFoo, - EFoo, -} - -fn main() {} diff --git a/tests/ui-toml/enum_variant_names/enum_variant_names.stderr b/tests/ui-toml/enum_variant_names/enum_variant_names.stderr deleted file mode 100644 index 11039b1db487..000000000000 --- a/tests/ui-toml/enum_variant_names/enum_variant_names.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: all variants have the same postfix: `Foo` - --> $DIR/enum_variant_names.rs:7:1 - | -LL | / enum Foo2 { -LL | | -LL | | AFoo, -LL | | BFoo, -... | -LL | | EFoo, -LL | | } - | |_^ - | - = help: remove the postfixes and use full paths to the variants instead of glob imports - = note: `-D clippy::enum-variant-names` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]` - -error: aborting due to previous error - diff --git a/tests/ui-toml/enum_variants_threshold0/clippy.toml b/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml similarity index 50% rename from tests/ui-toml/enum_variants_threshold0/clippy.toml rename to tests/ui-toml/item_name_repetitions/threshold0/clippy.toml index f85aade6ae87..d41edbaf7fa2 100644 --- a/tests/ui-toml/enum_variants_threshold0/clippy.toml +++ b/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml @@ -1 +1,2 @@ +struct-field-name-threshold = 0 enum-variant-name-threshold = 0 diff --git a/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs b/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs similarity index 65% rename from tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs rename to tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs index 6918d7528c16..b633dcbd19e4 100644 --- a/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs +++ b/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs @@ -1,3 +1,5 @@ +struct Data {} + enum Actions {} fn main() {} diff --git a/tests/ui-toml/enum_variant_names/clippy.toml b/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml similarity index 50% rename from tests/ui-toml/enum_variant_names/clippy.toml rename to tests/ui-toml/item_name_repetitions/threshold5/clippy.toml index 0ad7a9799484..028a62790792 100644 --- a/tests/ui-toml/enum_variant_names/clippy.toml +++ b/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml @@ -1 +1,2 @@ enum-variant-name-threshold = 5 +struct-field-name-threshold = 5 diff --git a/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs new file mode 100644 index 000000000000..d437311691d4 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs @@ -0,0 +1,32 @@ +#![warn(clippy::struct_field_names)] + +struct Data { + a_data: u8, + b_data: u8, + c_data: u8, + d_data: u8, +} +struct Data2 { + //~^ ERROR: all fields have the same postfix + a_data: u8, + b_data: u8, + c_data: u8, + d_data: u8, + e_data: u8, +} +enum Foo { + AFoo, + BFoo, + CFoo, + DFoo, +} +enum Foo2 { + //~^ ERROR: all variants have the same postfix + AFoo, + BFoo, + CFoo, + DFoo, + EFoo, +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr new file mode 100644 index 000000000000..33802c44bf9a --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr @@ -0,0 +1,34 @@ +error: all fields have the same postfix: `data` + --> $DIR/item_name_repetitions.rs:9:1 + | +LL | / struct Data2 { +LL | | +LL | | a_data: u8, +LL | | b_data: u8, +... | +LL | | e_data: u8, +LL | | } + | |_^ + | + = help: remove the postfixes + = note: `-D clippy::struct-field-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]` + +error: all variants have the same postfix: `Foo` + --> $DIR/item_name_repetitions.rs:23:1 + | +LL | / enum Foo2 { +LL | | +LL | | AFoo, +LL | | BFoo, +... | +LL | | EFoo, +LL | | } + | |_^ + | + = help: remove the postfixes and use full paths to the variants instead of glob imports + = note: `-D clippy::enum-variant-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs index 830d71f61dd5..cd53f5044599 100644 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs @@ -1,5 +1,6 @@ //! this is crate #![allow(missing_docs)] +#![allow(clippy::struct_field_names)] #![warn(clippy::missing_docs_in_private_items)] /// this is mod diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr index 1ecdabbc03e6..2cf20b460491 100644 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a function - --> $DIR/pub_crate_missing_doc.rs:12:5 + --> $DIR/pub_crate_missing_doc.rs:13:5 | LL | pub(crate) fn crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,25 +8,25 @@ LL | pub(crate) fn crate_no_docs() {} = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a function - --> $DIR/pub_crate_missing_doc.rs:15:5 + --> $DIR/pub_crate_missing_doc.rs:16:5 | LL | pub(super) fn super_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/pub_crate_missing_doc.rs:23:9 + --> $DIR/pub_crate_missing_doc.rs:24:9 | LL | pub(crate) fn sub_crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/pub_crate_missing_doc.rs:33:9 + --> $DIR/pub_crate_missing_doc.rs:34:9 | LL | pub(crate) crate_field_no_docs: (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct - --> $DIR/pub_crate_missing_doc.rs:39:5 + --> $DIR/pub_crate_missing_doc.rs:40:5 | LL | / pub(crate) struct CrateStructNoDocs { LL | | /// some docs @@ -38,13 +38,13 @@ LL | | } | |_____^ error: missing documentation for a struct field - --> $DIR/pub_crate_missing_doc.rs:42:9 + --> $DIR/pub_crate_missing_doc.rs:43:9 | LL | pub(crate) crate_field_no_docs: (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a type alias - --> $DIR/pub_crate_missing_doc.rs:51:1 + --> $DIR/pub_crate_missing_doc.rs:52:1 | LL | type CrateTypedefNoDocs = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 4bed5c149f51..2f9eaa5178c4 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -53,6 +53,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect single-char-binding-names-threshold stack-size-threshold standard-macro-braces + struct-field-name-threshold suppress-restriction-lint-in-const third-party too-large-for-stack @@ -126,6 +127,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect single-char-binding-names-threshold stack-size-threshold standard-macro-braces + struct-field-name-threshold suppress-restriction-lint-in-const third-party too-large-for-stack diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index 4de45e39b100..a44c46c145c6 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -2,6 +2,7 @@ #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure #![allow(clippy::useless_vec)] +#![allow(clippy::struct_field_names)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 22f316f90b6a..e72d0c4305b3 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -2,6 +2,7 @@ #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure #![allow(clippy::useless_vec)] +#![allow(clippy::struct_field_names)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index 0bfc1f5c7450..cf64bb25951a 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -1,11 +1,11 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:8:19 + --> $DIR/manual_filter_map.rs:9:19 | LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:8:30 + --> $DIR/manual_filter_map.rs:9:30 | LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^ @@ -13,31 +13,31 @@ LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap = help: to override `-D warnings` add `#[allow(clippy::manual_filter_map)]` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:11:19 + --> $DIR/manual_filter_map.rs:12:19 | LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:11:31 + --> $DIR/manual_filter_map.rs:12:31 | LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:14:19 + --> $DIR/manual_filter_map.rs:15:19 | LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:14:31 + --> $DIR/manual_filter_map.rs:15:31 | LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:17:10 + --> $DIR/manual_filter_map.rs:18:10 | LL | .filter(|&x| to_ref(to_opt(x)).is_some()) | __________^ @@ -45,13 +45,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:17:22 + --> $DIR/manual_filter_map.rs:18:22 | LL | .filter(|&x| to_ref(to_opt(x)).is_some()) | ^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:20:10 + --> $DIR/manual_filter_map.rs:21:10 | LL | .filter(|x| to_ref(to_opt(*x)).is_some()) | __________^ @@ -59,13 +59,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:20:21 + --> $DIR/manual_filter_map.rs:21:21 | LL | .filter(|x| to_ref(to_opt(*x)).is_some()) | ^^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:24:10 + --> $DIR/manual_filter_map.rs:25:10 | LL | .filter(|&x| to_ref(to_res(x)).is_ok()) | __________^ @@ -73,13 +73,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:24:22 + --> $DIR/manual_filter_map.rs:25:22 | LL | .filter(|&x| to_ref(to_res(x)).is_ok()) | ^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:27:10 + --> $DIR/manual_filter_map.rs:28:10 | LL | .filter(|x| to_ref(to_res(*x)).is_ok()) | __________^ @@ -87,13 +87,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:27:21 + --> $DIR/manual_filter_map.rs:28:21 | LL | .filter(|x| to_ref(to_res(*x)).is_ok()) | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:33:27 + --> $DIR/manual_filter_map.rs:34:27 | LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` @@ -102,79 +102,79 @@ LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap() = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:34:28 + --> $DIR/manual_filter_map.rs:35:28 | LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:35:31 + --> $DIR/manual_filter_map.rs:36:31 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:36:31 + --> $DIR/manual_filter_map.rs:37:31 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:36:41 + --> $DIR/manual_filter_map.rs:37:41 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:38:30 + --> $DIR/manual_filter_map.rs:39:30 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:39:31 + --> $DIR/manual_filter_map.rs:40:31 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:40:32 + --> $DIR/manual_filter_map.rs:41:32 | LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:41:31 + --> $DIR/manual_filter_map.rs:42:31 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:42:32 + --> $DIR/manual_filter_map.rs:43:32 | LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:43:35 + --> $DIR/manual_filter_map.rs:44:35 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:44:35 + --> $DIR/manual_filter_map.rs:45:35 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_filter_map.rs:44:45 + --> $DIR/manual_filter_map.rs:45:45 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:92:10 + --> $DIR/manual_filter_map.rs:93:10 | LL | .filter(|f| f.option_field.is_some()) | __________^ @@ -182,7 +182,7 @@ LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:97:10 + --> $DIR/manual_filter_map.rs:98:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ @@ -190,7 +190,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:102:10 + --> $DIR/manual_filter_map.rs:103:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ @@ -198,7 +198,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:107:10 + --> $DIR/manual_filter_map.rs:108:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -206,7 +206,7 @@ LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:112:10 + --> $DIR/manual_filter_map.rs:113:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -214,7 +214,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:117:10 + --> $DIR/manual_filter_map.rs:118:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -222,7 +222,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:122:10 + --> $DIR/manual_filter_map.rs:123:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -230,7 +230,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:127:10 + --> $DIR/manual_filter_map.rs:128:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -238,7 +238,7 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:132:10 + --> $DIR/manual_filter_map.rs:133:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -246,7 +246,7 @@ LL | | .map(|f| f.result_field.to_owned().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:145:27 + --> $DIR/manual_filter_map.rs:146:27 | LL | let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x { | ___________________________^ @@ -256,7 +256,7 @@ LL | | }); | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:155:10 + --> $DIR/manual_filter_map.rs:156:10 | LL | .filter(|x| matches!(x, Enum::A(_))) | __________^ diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index 0e92d25e68f1..2d9a356b9bcd 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -2,6 +2,7 @@ #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure #![allow(clippy::useless_vec)] +#![allow(clippy::struct_field_names)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index b2568c823ebc..7c5cc136695a 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -2,6 +2,7 @@ #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure #![allow(clippy::useless_vec)] +#![allow(clippy::struct_field_names)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index 0dc9ae1df035..0526382323d3 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -1,11 +1,11 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:8:19 + --> $DIR/manual_find_map.rs:9:19 | LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:8:28 + --> $DIR/manual_find_map.rs:9:28 | LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^ @@ -13,31 +13,31 @@ LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap() = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:11:19 + --> $DIR/manual_find_map.rs:12:19 | LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:11:29 + --> $DIR/manual_find_map.rs:12:29 | LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:14:19 + --> $DIR/manual_find_map.rs:15:19 | LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:14:29 + --> $DIR/manual_find_map.rs:15:29 | LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:17:10 + --> $DIR/manual_find_map.rs:18:10 | LL | .find(|&x| to_ref(to_opt(x)).is_some()) | __________^ @@ -45,13 +45,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:17:20 + --> $DIR/manual_find_map.rs:18:20 | LL | .find(|&x| to_ref(to_opt(x)).is_some()) | ^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:20:10 + --> $DIR/manual_find_map.rs:21:10 | LL | .find(|x| to_ref(to_opt(*x)).is_some()) | __________^ @@ -59,13 +59,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:20:19 + --> $DIR/manual_find_map.rs:21:19 | LL | .find(|x| to_ref(to_opt(*x)).is_some()) | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:24:10 + --> $DIR/manual_find_map.rs:25:10 | LL | .find(|&x| to_ref(to_res(x)).is_ok()) | __________^ @@ -73,13 +73,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:24:20 + --> $DIR/manual_find_map.rs:25:20 | LL | .find(|&x| to_ref(to_res(x)).is_ok()) | ^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:27:10 + --> $DIR/manual_find_map.rs:28:10 | LL | .find(|x| to_ref(to_res(*x)).is_ok()) | __________^ @@ -87,109 +87,109 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:27:19 + --> $DIR/manual_find_map.rs:28:19 | LL | .find(|x| to_ref(to_res(*x)).is_ok()) | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:33:26 + --> $DIR/manual_find_map.rs:34:26 | LL | iter::>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:34:27 + --> $DIR/manual_find_map.rs:35:27 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:35:28 + --> $DIR/manual_find_map.rs:36:28 | LL | iter::<&&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:36:27 + --> $DIR/manual_find_map.rs:37:27 | LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:37:28 + --> $DIR/manual_find_map.rs:38:28 | LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:38:31 + --> $DIR/manual_find_map.rs:39:31 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:39:31 + --> $DIR/manual_find_map.rs:40:31 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:39:41 + --> $DIR/manual_find_map.rs:40:41 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:41:30 + --> $DIR/manual_find_map.rs:42:30 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:42:31 + --> $DIR/manual_find_map.rs:43:31 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:43:32 + --> $DIR/manual_find_map.rs:44:32 | LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:44:31 + --> $DIR/manual_find_map.rs:45:31 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:45:32 + --> $DIR/manual_find_map.rs:46:32 | LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:46:35 + --> $DIR/manual_find_map.rs:47:35 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:47:35 + --> $DIR/manual_find_map.rs:48:35 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> $DIR/manual_find_map.rs:47:45 + --> $DIR/manual_find_map.rs:48:45 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:95:10 + --> $DIR/manual_find_map.rs:96:10 | LL | .find(|f| f.option_field.is_some()) | __________^ @@ -197,7 +197,7 @@ LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:100:10 + --> $DIR/manual_find_map.rs:101:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ @@ -205,7 +205,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:105:10 + --> $DIR/manual_find_map.rs:106:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ @@ -213,7 +213,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:110:10 + --> $DIR/manual_find_map.rs:111:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -221,7 +221,7 @@ LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:115:10 + --> $DIR/manual_find_map.rs:116:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -229,7 +229,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:120:10 + --> $DIR/manual_find_map.rs:121:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -237,7 +237,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:125:10 + --> $DIR/manual_find_map.rs:126:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -245,7 +245,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:130:10 + --> $DIR/manual_find_map.rs:131:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -253,7 +253,7 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:135:10 + --> $DIR/manual_find_map.rs:136:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ diff --git a/tests/ui/min_ident_chars.rs b/tests/ui/min_ident_chars.rs index 030863ca0d30..f99c35d5c57c 100644 --- a/tests/ui/min_ident_chars.rs +++ b/tests/ui/min_ident_chars.rs @@ -1,5 +1,6 @@ //@aux-build:proc_macros.rs #![allow(irrefutable_let_patterns, nonstandard_style, unused)] +#![allow(clippy::struct_field_names)] #![warn(clippy::min_ident_chars)] extern crate proc_macros; diff --git a/tests/ui/min_ident_chars.stderr b/tests/ui/min_ident_chars.stderr index 253636cf91da..e4181157ea23 100644 --- a/tests/ui/min_ident_chars.stderr +++ b/tests/ui/min_ident_chars.stderr @@ -1,5 +1,5 @@ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:8:8 + --> $DIR/min_ident_chars.rs:9:8 | LL | struct A { | ^ @@ -8,169 +8,169 @@ LL | struct A { = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]` error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:9:5 + --> $DIR/min_ident_chars.rs:10:5 | LL | a: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:11:5 + --> $DIR/min_ident_chars.rs:12:5 | LL | A: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:12:5 + --> $DIR/min_ident_chars.rs:13:5 | LL | I: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:15:8 + --> $DIR/min_ident_chars.rs:16:8 | LL | struct B(u32); | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:17:8 + --> $DIR/min_ident_chars.rs:18:8 | LL | struct O { | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:18:5 + --> $DIR/min_ident_chars.rs:19:5 | LL | o: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:23:6 + --> $DIR/min_ident_chars.rs:24:6 | LL | enum C { | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:24:5 + --> $DIR/min_ident_chars.rs:25:5 | LL | D, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:25:5 + --> $DIR/min_ident_chars.rs:26:5 | LL | E, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:26:5 + --> $DIR/min_ident_chars.rs:27:5 | LL | F, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:50:9 + --> $DIR/min_ident_chars.rs:51:9 | LL | let h = 1; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:51:9 + --> $DIR/min_ident_chars.rs:52:9 | LL | let e = 2; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:52:9 + --> $DIR/min_ident_chars.rs:53:9 | LL | let l = 3; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:53:9 + --> $DIR/min_ident_chars.rs:54:9 | LL | let l = 4; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:54:9 + --> $DIR/min_ident_chars.rs:55:9 | LL | let o = 6; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:58:10 + --> $DIR/min_ident_chars.rs:59:10 | LL | let (h, o, w) = (1, 2, 3); | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:58:13 + --> $DIR/min_ident_chars.rs:59:13 | LL | let (h, o, w) = (1, 2, 3); | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:59:10 + --> $DIR/min_ident_chars.rs:60:10 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:59:14 + --> $DIR/min_ident_chars.rs:60:14 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:59:17 + --> $DIR/min_ident_chars.rs:60:17 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:61:16 + --> $DIR/min_ident_chars.rs:62:16 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:61:19 + --> $DIR/min_ident_chars.rs:62:19 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:61:29 + --> $DIR/min_ident_chars.rs:62:29 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:65:9 + --> $DIR/min_ident_chars.rs:66:9 | LL | let o = 1; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:66:9 + --> $DIR/min_ident_chars.rs:67:9 | LL | let o = O { o }; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:80:4 + --> $DIR/min_ident_chars.rs:81:4 | LL | fn b() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:81:21 + --> $DIR/min_ident_chars.rs:82:21 | LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:81:29 + --> $DIR/min_ident_chars.rs:82:29 | LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ diff --git a/tests/ui/misnamed_getters.fixed b/tests/ui/misnamed_getters.fixed index 2a7a2067ee08..70af604b2144 100644 --- a/tests/ui/misnamed_getters.fixed +++ b/tests/ui/misnamed_getters.fixed @@ -1,4 +1,5 @@ #![allow(unused)] +#![allow(clippy::struct_field_names)] #![warn(clippy::misnamed_getters)] struct A { diff --git a/tests/ui/misnamed_getters.rs b/tests/ui/misnamed_getters.rs index 56ddc46c4d4a..23c3e7bc5cf7 100644 --- a/tests/ui/misnamed_getters.rs +++ b/tests/ui/misnamed_getters.rs @@ -1,4 +1,5 @@ #![allow(unused)] +#![allow(clippy::struct_field_names)] #![warn(clippy::misnamed_getters)] struct A { diff --git a/tests/ui/misnamed_getters.stderr b/tests/ui/misnamed_getters.stderr index aadec6549083..120a3f3112ef 100644 --- a/tests/ui/misnamed_getters.stderr +++ b/tests/ui/misnamed_getters.stderr @@ -1,5 +1,5 @@ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:11:5 + --> $DIR/misnamed_getters.rs:12:5 | LL | / fn a(&self) -> &u8 { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]` error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:16:5 + --> $DIR/misnamed_getters.rs:17:5 | LL | / fn a_mut(&mut self) -> &mut u8 { LL | | @@ -23,7 +23,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:21:5 + --> $DIR/misnamed_getters.rs:22:5 | LL | / fn b(self) -> u8 { LL | | @@ -33,7 +33,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:26:5 + --> $DIR/misnamed_getters.rs:27:5 | LL | / fn b_mut(&mut self) -> &mut u8 { LL | | @@ -43,7 +43,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:31:5 + --> $DIR/misnamed_getters.rs:32:5 | LL | / fn c(&self) -> &u8 { LL | | @@ -53,7 +53,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:36:5 + --> $DIR/misnamed_getters.rs:37:5 | LL | / fn c_mut(&mut self) -> &mut u8 { LL | | @@ -63,7 +63,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:48:5 + --> $DIR/misnamed_getters.rs:49:5 | LL | / unsafe fn a(&self) -> &u8 { LL | | @@ -73,7 +73,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:52:5 + --> $DIR/misnamed_getters.rs:53:5 | LL | / unsafe fn a_mut(&mut self) -> &mut u8 { LL | | @@ -83,7 +83,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:57:5 + --> $DIR/misnamed_getters.rs:58:5 | LL | / unsafe fn b(self) -> u8 { LL | | @@ -93,7 +93,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:62:5 + --> $DIR/misnamed_getters.rs:63:5 | LL | / unsafe fn b_mut(&mut self) -> &mut u8 { LL | | @@ -103,7 +103,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:75:5 + --> $DIR/misnamed_getters.rs:76:5 | LL | / unsafe fn a_unchecked(&self) -> &u8 { LL | | @@ -113,7 +113,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:79:5 + --> $DIR/misnamed_getters.rs:80:5 | LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { LL | | @@ -123,7 +123,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:84:5 + --> $DIR/misnamed_getters.rs:85:5 | LL | / unsafe fn b_unchecked(self) -> u8 { LL | | @@ -133,7 +133,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:89:5 + --> $DIR/misnamed_getters.rs:90:5 | LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { LL | | @@ -143,7 +143,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:122:5 + --> $DIR/misnamed_getters.rs:123:5 | LL | / fn a(&self) -> &u8 { LL | | @@ -153,7 +153,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:126:5 + --> $DIR/misnamed_getters.rs:127:5 | LL | / fn a_mut(&mut self) -> &mut u8 { LL | | @@ -163,7 +163,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:131:5 + --> $DIR/misnamed_getters.rs:132:5 | LL | / fn d(&self) -> &u8 { LL | | @@ -173,7 +173,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> $DIR/misnamed_getters.rs:135:5 + --> $DIR/misnamed_getters.rs:136:5 | LL | / fn d_mut(&mut self) -> &mut u8 { LL | | diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index c9ea831f8b2a..3059de8f89c4 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -7,7 +7,8 @@ clippy::equatable_if_let, clippy::needless_if, clippy::needless_return, - clippy::self_named_constructors + clippy::self_named_constructors, + clippy::struct_field_names )] use std::cell::Cell; diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index b83d9c3f2096..b2cbe86e2235 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -7,7 +7,8 @@ clippy::equatable_if_let, clippy::needless_if, clippy::needless_return, - clippy::self_named_constructors + clippy::self_named_constructors, + clippy::struct_field_names )] use std::cell::Cell; diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr index 2b189c898512..72b0670c95ba 100644 --- a/tests/ui/needless_bool/fixable.stderr +++ b/tests/ui/needless_bool/fixable.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:40:5 + --> $DIR/fixable.rs:41:5 | LL | / if x { LL | | true @@ -12,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:45:5 + --> $DIR/fixable.rs:46:5 | LL | / if x { LL | | false @@ -22,7 +22,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:50:5 + --> $DIR/fixable.rs:51:5 | LL | / if x && y { LL | | false @@ -32,7 +32,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:58:5 + --> $DIR/fixable.rs:59:5 | LL | / if a == b { LL | | false @@ -42,7 +42,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a != b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:63:5 + --> $DIR/fixable.rs:64:5 | LL | / if a != b { LL | | false @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a == b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:68:5 + --> $DIR/fixable.rs:69:5 | LL | / if a < b { LL | | false @@ -62,7 +62,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a >= b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:73:5 + --> $DIR/fixable.rs:74:5 | LL | / if a <= b { LL | | false @@ -72,7 +72,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a > b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:78:5 + --> $DIR/fixable.rs:79:5 | LL | / if a > b { LL | | false @@ -82,7 +82,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a <= b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:83:5 + --> $DIR/fixable.rs:84:5 | LL | / if a >= b { LL | | false @@ -92,7 +92,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:111:5 + --> $DIR/fixable.rs:112:5 | LL | / if x { LL | | return true; @@ -102,7 +102,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:119:5 + --> $DIR/fixable.rs:120:5 | LL | / if x { LL | | return false; @@ -112,7 +112,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:127:5 + --> $DIR/fixable.rs:128:5 | LL | / if x && y { LL | | return true; @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:135:5 + --> $DIR/fixable.rs:136:5 | LL | / if x && y { LL | | return false; @@ -132,7 +132,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:143:8 + --> $DIR/fixable.rs:144:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -141,25 +141,25 @@ LL | if x == true {}; = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:147:8 + --> $DIR/fixable.rs:148:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:157:8 + --> $DIR/fixable.rs:158:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:158:8 + --> $DIR/fixable.rs:159:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:167:12 + --> $DIR/fixable.rs:168:12 | LL | } else if returns_bool() { | ____________^ @@ -170,7 +170,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:180:5 + --> $DIR/fixable.rs:181:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -180,13 +180,13 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:185:30 + --> $DIR/fixable.rs:186:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:188:9 + --> $DIR/fixable.rs:189:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` diff --git a/tests/ui/rest_pat_in_fully_bound_structs.rs b/tests/ui/rest_pat_in_fully_bound_structs.rs index e25609f75601..51fe346d0926 100644 --- a/tests/ui/rest_pat_in_fully_bound_structs.rs +++ b/tests/ui/rest_pat_in_fully_bound_structs.rs @@ -1,4 +1,5 @@ #![warn(clippy::rest_pat_in_fully_bound_structs)] +#![allow(clippy::struct_field_names)] struct A { a: i32, diff --git a/tests/ui/rest_pat_in_fully_bound_structs.stderr b/tests/ui/rest_pat_in_fully_bound_structs.stderr index 2c221b4dbb2c..a62f1d0b65f3 100644 --- a/tests/ui/rest_pat_in_fully_bound_structs.stderr +++ b/tests/ui/rest_pat_in_fully_bound_structs.stderr @@ -1,5 +1,5 @@ error: unnecessary use of `..` pattern in struct binding. All fields were already bound - --> $DIR/rest_pat_in_fully_bound_structs.rs:22:9 + --> $DIR/rest_pat_in_fully_bound_structs.rs:23:9 | LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint = help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]` error: unnecessary use of `..` pattern in struct binding. All fields were already bound - --> $DIR/rest_pat_in_fully_bound_structs.rs:24:9 + --> $DIR/rest_pat_in_fully_bound_structs.rs:25:9 | LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint = help: consider removing `..` from this binding error: unnecessary use of `..` pattern in struct binding. All fields were already bound - --> $DIR/rest_pat_in_fully_bound_structs.rs:31:9 + --> $DIR/rest_pat_in_fully_bound_structs.rs:32:9 | LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/struct_fields.rs b/tests/ui/struct_fields.rs new file mode 100644 index 000000000000..8b1a1446e3c8 --- /dev/null +++ b/tests/ui/struct_fields.rs @@ -0,0 +1,331 @@ +//@aux-build:proc_macros.rs + +#![warn(clippy::struct_field_names)] +#![allow(unused)] + +#[macro_use] +extern crate proc_macros; + +struct Data1 { + field_data1: u8, + //~^ ERROR: field name ends with the struct's name + another: u8, + foo: u8, + bar: u8, +} + +struct Data2 { + another: u8, + foo: u8, + data2_field: u8, + //~^ ERROR: field name starts with the struct's name + bar: u8, +} + +struct StructData { + //~^ ERROR: all fields have the same postfix: `data` + movable_data: u8, + fixed_data: u8, + invisible_data: u8, +} + +struct DataStruct { + //~^ ERROR: all fields have the same prefix: `data` + data_movable: u8, + data_fixed: u8, + data_invisible: u8, +} + +struct DoublePrefix { + //~^ ERROR: all fields have the same prefix: `some_data` + some_data_a: bool, + some_data_b: bool, + some_data_c: bool, +} + +struct DoublePostfix { + //~^ ERROR: all fields have the same postfix: `some_data` + a_some_data: bool, + b_some_data: bool, + c_some_data: bool, +} + +#[allow(non_snake_case)] +struct NotSnakeCase { + //~^ ERROR: all fields have the same postfix: `someData` + a_someData: bool, + b_someData: bool, + c_someData: bool, +} +#[allow(non_snake_case)] +struct NotSnakeCase2 { + //~^ ERROR: all fields have the same prefix: `someData` + someData_c: bool, + someData_b: bool, + someData_a_b: bool, +} + +// no error, threshold is 3 fiels by default +struct Fooo { + foo: u8, + bar: u8, +} + +struct NonCaps { + //~^ ERROR: all fields have the same prefix: `prefix` + prefix_的: u8, + prefix_tea: u8, + prefix_cake: u8, +} + +// should not lint +#[allow(clippy::struct_field_names)] +pub mod allowed { + pub struct PubAllowed { + some_this: u8, + some_that: u8, + some_other_what: u8, + } +} + +// should not lint +struct SomeData { + foo: u8, + bar: bool, + path: u8, + answer: u8, +} + +// should not lint +pub struct NetworkLayer { + layer1: Vec, + layer2: Vec, + layer3: Vec, + layer4: Vec, +} + +//should not lint +struct North { + normal: u8, + no_left: u8, + no_right: u8, +} + +mod issue8324_from_enum_variant_names { + // 8324: enum_variant_names warns even if removing the suffix would leave an empty string + struct Phase { + pre_lookup: u8, + lookup: u8, + post_lookup: u8, + } +} + +mod issue9018_from_enum_variant_names { + struct DoLint { + //~^ ERROR: all fields have the same prefix: `_type` + _type_create: u8, + _type_read: u8, + _type_update: u8, + _type_destroy: u8, + } + + struct DoLint2 { + //~^ ERROR: all fields have the same prefix: `__type` + __type_create: u8, + __type_read: u8, + __type_update: u8, + __type_destroy: u8, + } + + struct DoLint3 { + //~^ ERROR: all fields have the same prefix: `___type` + ___type_create: u8, + ___type_read: u8, + ___type_update: u8, + ___type_destroy: u8, + } + + struct DoLint4 { + //~^ ERROR: all fields have the same postfix: `_` + create_: u8, + read_: u8, + update_: u8, + destroy_: u8, + } + + struct DoLint5 { + //~^ ERROR: all fields have the same postfix: `__` + create__: u8, + read__: u8, + update__: u8, + destroy__: u8, + } + + struct DoLint6 { + //~^ ERROR: all fields have the same postfix: `___` + create___: u8, + read___: u8, + update___: u8, + destroy___: u8, + } + + struct DoLintToo { + //~^ ERROR: all fields have the same postfix: `type` + _create_type: u8, + _update_type: u8, + _delete_type: u8, + } + + struct DoNotLint { + _foo: u8, + _bar: u8, + _baz: u8, + } + + struct DoNotLint2 { + __foo: u8, + __bar: u8, + __baz: u8, + } +} + +mod allow_attributes_on_fields { + struct Struct { + #[allow(clippy::struct_field_names)] + struct_starts_with: u8, + #[allow(clippy::struct_field_names)] + ends_with_struct: u8, + foo: u8, + } +} + +// food field should not lint +struct Foo { + food: i32, + a: i32, + b: i32, +} + +struct Proxy { + proxy: i32, + //~^ ERROR: field name starts with the struct's name + unrelated1: bool, + unrelated2: bool, +} + +// should not lint +pub struct RegexT { + __buffer: i32, + __allocated: i32, + __used: i32, +} + +mod macro_tests { + macro_rules! mk_struct { + () => { + struct MacroStruct { + some_a: i32, + some_b: i32, + some_c: i32, + } + }; + } + mk_struct!(); + //~^ ERROR: all fields have the same prefix: `some` + + macro_rules! mk_struct2 { + () => { + struct Macrobaz { + macrobaz_a: i32, + some_b: i32, + some_c: i32, + } + }; + } + mk_struct2!(); + //~^ ERROR: field name starts with the struct's name + + macro_rules! mk_struct_with_names { + ($struct_name:ident, $field:ident) => { + struct $struct_name { + $field: i32, + other_something: i32, + other_field: i32, + } + }; + } + // expands to `struct Foo { foo: i32, ... }` + mk_struct_with_names!(Foo, foo); + //~^ ERROR: field name starts with the struct's name + + // expands to a struct with all fields starting with `other` but should not + // be linted because some fields come from the macro definition and the other from the input + mk_struct_with_names!(Some, other_data); + + // should not lint when names come from different places + macro_rules! mk_struct_with_field_name { + ($field_name:ident) => { + struct Baz { + one: i32, + two: i32, + $field_name: i32, + } + }; + } + mk_struct_with_field_name!(baz_three); + + // should not lint when names come from different places + macro_rules! mk_struct_with_field_name { + ($field_name:ident) => { + struct Bazilisk { + baz_one: i32, + baz_two: i32, + $field_name: i32, + } + }; + } + mk_struct_with_field_name!(baz_three); + + macro_rules! mk_struct_full_def { + ($struct_name:ident, $field1:ident, $field2:ident, $field3:ident) => { + struct $struct_name { + $field1: i32, + $field2: i32, + $field3: i32, + } + }; + } + mk_struct_full_def!(PrefixData, some_data, some_meta, some_other); + //~^ ERROR: all fields have the same prefix: `some` +} + +// should not lint on external code +external! { + struct DataExternal { + field_data1: u8, + another: u8, + foo: u8, + bar: u8, + } + + struct NotSnakeCaseExternal { + someData_c: bool, + someData_b: bool, + someData_a_b: bool, + } + + struct DoublePrefixExternal { + some_data_a: bool, + some_data_b: bool, + some_data_c: bool, + } + + struct StructDataExternal { + movable_data: u8, + fixed_data: u8, + invisible_data: u8, + } + +} + +fn main() {} diff --git a/tests/ui/struct_fields.stderr b/tests/ui/struct_fields.stderr new file mode 100644 index 000000000000..4ca57715b185 --- /dev/null +++ b/tests/ui/struct_fields.stderr @@ -0,0 +1,265 @@ +error: field name ends with the struct's name + --> $DIR/struct_fields.rs:10:5 + | +LL | field_data1: u8, + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::struct-field-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]` + +error: field name starts with the struct's name + --> $DIR/struct_fields.rs:20:5 + | +LL | data2_field: u8, + | ^^^^^^^^^^^^^^^ + +error: all fields have the same postfix: `data` + --> $DIR/struct_fields.rs:25:1 + | +LL | / struct StructData { +LL | | +LL | | movable_data: u8, +LL | | fixed_data: u8, +LL | | invisible_data: u8, +LL | | } + | |_^ + | + = help: remove the postfixes + +error: all fields have the same prefix: `data` + --> $DIR/struct_fields.rs:32:1 + | +LL | / struct DataStruct { +LL | | +LL | | data_movable: u8, +LL | | data_fixed: u8, +LL | | data_invisible: u8, +LL | | } + | |_^ + | + = help: remove the prefixes + +error: all fields have the same prefix: `some_data` + --> $DIR/struct_fields.rs:39:1 + | +LL | / struct DoublePrefix { +LL | | +LL | | some_data_a: bool, +LL | | some_data_b: bool, +LL | | some_data_c: bool, +LL | | } + | |_^ + | + = help: remove the prefixes + +error: all fields have the same postfix: `some_data` + --> $DIR/struct_fields.rs:46:1 + | +LL | / struct DoublePostfix { +LL | | +LL | | a_some_data: bool, +LL | | b_some_data: bool, +LL | | c_some_data: bool, +LL | | } + | |_^ + | + = help: remove the postfixes + +error: all fields have the same postfix: `someData` + --> $DIR/struct_fields.rs:54:1 + | +LL | / struct NotSnakeCase { +LL | | +LL | | a_someData: bool, +LL | | b_someData: bool, +LL | | c_someData: bool, +LL | | } + | |_^ + | + = help: remove the postfixes + +error: all fields have the same prefix: `someData` + --> $DIR/struct_fields.rs:61:1 + | +LL | / struct NotSnakeCase2 { +LL | | +LL | | someData_c: bool, +LL | | someData_b: bool, +LL | | someData_a_b: bool, +LL | | } + | |_^ + | + = help: remove the prefixes + +error: all fields have the same prefix: `prefix` + --> $DIR/struct_fields.rs:74:1 + | +LL | / struct NonCaps { +LL | | +LL | | prefix_的: u8, +LL | | prefix_tea: u8, +LL | | prefix_cake: u8, +LL | | } + | |_^ + | + = help: remove the prefixes + +error: all fields have the same prefix: `_type` + --> $DIR/struct_fields.rs:124:5 + | +LL | / struct DoLint { +LL | | +LL | | _type_create: u8, +LL | | _type_read: u8, +LL | | _type_update: u8, +LL | | _type_destroy: u8, +LL | | } + | |_____^ + | + = help: remove the prefixes + +error: all fields have the same prefix: `__type` + --> $DIR/struct_fields.rs:132:5 + | +LL | / struct DoLint2 { +LL | | +LL | | __type_create: u8, +LL | | __type_read: u8, +LL | | __type_update: u8, +LL | | __type_destroy: u8, +LL | | } + | |_____^ + | + = help: remove the prefixes + +error: all fields have the same prefix: `___type` + --> $DIR/struct_fields.rs:140:5 + | +LL | / struct DoLint3 { +LL | | +LL | | ___type_create: u8, +LL | | ___type_read: u8, +LL | | ___type_update: u8, +LL | | ___type_destroy: u8, +LL | | } + | |_____^ + | + = help: remove the prefixes + +error: all fields have the same postfix: `_` + --> $DIR/struct_fields.rs:148:5 + | +LL | / struct DoLint4 { +LL | | +LL | | create_: u8, +LL | | read_: u8, +LL | | update_: u8, +LL | | destroy_: u8, +LL | | } + | |_____^ + | + = help: remove the postfixes + +error: all fields have the same postfix: `__` + --> $DIR/struct_fields.rs:156:5 + | +LL | / struct DoLint5 { +LL | | +LL | | create__: u8, +LL | | read__: u8, +LL | | update__: u8, +LL | | destroy__: u8, +LL | | } + | |_____^ + | + = help: remove the postfixes + +error: all fields have the same postfix: `___` + --> $DIR/struct_fields.rs:164:5 + | +LL | / struct DoLint6 { +LL | | +LL | | create___: u8, +LL | | read___: u8, +LL | | update___: u8, +LL | | destroy___: u8, +LL | | } + | |_____^ + | + = help: remove the postfixes + +error: all fields have the same postfix: `type` + --> $DIR/struct_fields.rs:172:5 + | +LL | / struct DoLintToo { +LL | | +LL | | _create_type: u8, +LL | | _update_type: u8, +LL | | _delete_type: u8, +LL | | } + | |_____^ + | + = help: remove the postfixes + +error: field name starts with the struct's name + --> $DIR/struct_fields.rs:210:5 + | +LL | proxy: i32, + | ^^^^^^^^^^ + +error: all fields have the same prefix: `some` + --> $DIR/struct_fields.rs:226:13 + | +LL | / struct MacroStruct { +LL | | some_a: i32, +LL | | some_b: i32, +LL | | some_c: i32, +LL | | } + | |_____________^ +... +LL | mk_struct!(); + | ------------ in this macro invocation + | + = help: remove the prefixes + = note: this error originates in the macro `mk_struct` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: field name starts with the struct's name + --> $DIR/struct_fields.rs:239:17 + | +LL | macrobaz_a: i32, + | ^^^^^^^^^^^^^^^ +... +LL | mk_struct2!(); + | ------------- in this macro invocation + | + = note: this error originates in the macro `mk_struct2` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: field name starts with the struct's name + --> $DIR/struct_fields.rs:251:17 + | +LL | $field: i32, + | ^^^^^^^^^^^ +... +LL | mk_struct_with_names!(Foo, foo); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `mk_struct_with_names` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: all fields have the same prefix: `some` + --> $DIR/struct_fields.rs:291:13 + | +LL | / struct $struct_name { +LL | | $field1: i32, +LL | | $field2: i32, +LL | | $field3: i32, +LL | | } + | |_____________^ +... +LL | mk_struct_full_def!(PrefixData, some_data, some_meta, some_other); + | ----------------------------------------------------------------- in this macro invocation + | + = help: remove the prefixes + = note: this error originates in the macro `mk_struct_full_def` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 21 previous errors + From ec2b8ab83a5260013fd491255f60b806d3fe2084 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 11:11:57 +0200 Subject: [PATCH 054/107] Fix invalid warning for closure in non-async function for `needless_pass_by_ref_mut` lint --- clippy_lints/src/needless_pass_by_ref_mut.rs | 27 ++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index e7424ba7c6db..1d5874f6feac 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -197,20 +197,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { }; let infcx = cx.tcx.infer_ctxt().build(); euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); + + let mut checked_closures = FxHashSet::default(); + + // We retrieve all the closures declared in the function because they will not be found + // by `euv::Delegate`. + let mut closures: FxHashSet = FxHashSet::default(); + for_each_expr_with_closures(cx, body, |expr| { + if let ExprKind::Closure(closure) = expr.kind { + closures.insert(closure.def_id); + } + ControlFlow::<()>::Continue(()) + }); + check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures); + if is_async { - let mut checked_closures = FxHashSet::default(); - - // We retrieve all the closures declared in the async function because they will - // not be found by `euv::Delegate`. - let mut closures: FxHashSet = FxHashSet::default(); - for_each_expr_with_closures(cx, body, |expr| { - if let ExprKind::Closure(closure) = expr.kind { - closures.insert(closure.def_id); - } - ControlFlow::<()>::Continue(()) - }); - check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures); - while !ctx.async_closures.is_empty() { let async_closures = ctx.async_closures.clone(); ctx.async_closures.clear(); From 3b4b07c5f87865b5a15286ac8f8dfaf05b92df1e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 11:12:37 +0200 Subject: [PATCH 055/107] Add test for closure in non-async function for `needless_pass_by_ref_mut` lint --- tests/ui/needless_pass_by_ref_mut.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index 7f642e53dfb3..95fe1385c062 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -288,6 +288,15 @@ fn get_mut_unchecked2(ptr: &mut NonNull>) -> &mut T { unsafe { &mut (*ptr.as_ptr()).value } } +fn set_true(b: &mut bool) { + *b = true; +} + +// Should not warn. +fn true_setter(b: &mut bool) -> impl FnOnce() + '_ { + move || set_true(b) +} + fn main() { let mut u = 0; let mut v = vec![0]; From 3e6db95e308593fac0b9f132454db44295a94b08 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 11:24:35 +0200 Subject: [PATCH 056/107] Add regression test for #11561 --- tests/ui/needless_pass_by_ref_mut.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index 95fe1385c062..ea5e74c4c006 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -297,6 +297,11 @@ fn true_setter(b: &mut bool) -> impl FnOnce() + '_ { move || set_true(b) } +// Should not warn. +fn filter_copy(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T) -> bool + '_ { + move |&item| predicate(item) +} + fn main() { let mut u = 0; let mut v = vec![0]; From 1528c1db471fa6a056177bea5ad0594e85d8d4e1 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 18 Oct 2023 18:08:41 +0000 Subject: [PATCH 057/107] Deserialize Msrv directly in Conf --- book/src/lint_configuration.md | 2 +- clippy_lints/src/lib.rs | 65 +--------- clippy_lints/src/matches/mod.rs | 3 +- clippy_lints/src/use_self.rs | 3 +- clippy_lints/src/utils/conf.rs | 111 +++++++++++------- clippy_utils/Cargo.toml | 1 + clippy_utils/src/msrvs.rs | 88 ++++++-------- src/driver.rs | 6 +- .../invalid_min_rust_version.rs | 2 +- .../invalid_min_rust_version.stderr | 6 +- 10 files changed, 118 insertions(+), 169 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 2c958ccbbc24..3d654f21de40 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -100,7 +100,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat ## `msrv` The minimum rust version that the project supports -**Default Value:** `None` (`Option`) +**Default Value:** `Msrv { stack: [] }` (`crate::Msrv`) --- **Affected lints:** diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2d02ce8b4f0a..c3be203329bd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -50,9 +50,6 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; -use std::io; -use std::path::PathBuf; - use clippy_utils::msrvs::Msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; @@ -362,7 +359,6 @@ mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` use crate::utils::conf::metadata::get_configuration_metadata; -use crate::utils::conf::TryConf; pub use crate::utils::conf::{lookup_conf_file, Conf}; use crate::utils::FindAll; @@ -374,65 +370,13 @@ use crate::utils::FindAll; /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. - let msrv = Msrv::read(&conf.msrv, sess); - let msrv = move || msrv.clone(); + let msrv = || conf.msrv.clone(); store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() })); } -#[doc(hidden)] -pub fn read_conf(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { - if let Ok((_, warnings)) = path { - for warning in warnings { - sess.warn(warning.clone()); - } - } - let file_name = match path { - Ok((Some(path), _)) => path, - Ok((None, _)) => return Conf::default(), - Err(error) => { - sess.err(format!("error finding Clippy's configuration file: {error}")); - return Conf::default(); - }, - }; - - let TryConf { conf, errors, warnings } = utils::conf::read(sess, file_name); - // all conf errors are non-fatal, we just use the default conf in case of error - for error in errors { - if let Some(span) = error.span { - sess.span_err( - span, - format!("error reading Clippy's configuration file: {}", error.message), - ); - } else { - sess.err(format!( - "error reading Clippy's configuration file `{}`: {}", - file_name.display(), - error.message - )); - } - } - - for warning in warnings { - if let Some(span) = warning.span { - sess.span_warn( - span, - format!("error reading Clippy's configuration file: {}", warning.message), - ); - } else { - sess.warn(format!( - "error reading Clippy's configuration file `{}`: {}", - file_name.display(), - warning.message - )); - } - } - - conf -} - #[derive(Default)] struct RegistrationGroups { all: Vec, @@ -558,7 +502,7 @@ fn register_categories(store: &mut rustc_lint::LintStore) { /// /// Used in `./src/driver.rs`. #[expect(clippy::too_many_lines)] -pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) { register_removed_non_tool_lints(store); register_categories(store); @@ -660,8 +604,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); - let msrv = Msrv::read(&conf.msrv, sess); - let msrv = move || msrv.clone(); + let msrv = || conf.msrv.clone(); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index a23000e5fe15..b5ab94b3a2f8 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -967,7 +967,6 @@ declare_clippy_lint! { "checks for unnecessary guards in match expressions" } -#[derive(Default)] pub struct Matches { msrv: Msrv, infallible_destructuring_match_linted: bool, @@ -978,7 +977,7 @@ impl Matches { pub fn new(msrv: Msrv) -> Self { Self { msrv, - ..Matches::default() + infallible_destructuring_match_linted: false, } } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 50231d930d0e..f10ed4b3d419 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -54,7 +54,6 @@ declare_clippy_lint! { "unnecessary structure name repetition whereas `Self` is applicable" } -#[derive(Default)] pub struct UseSelf { msrv: Msrv, stack: Vec, @@ -65,7 +64,7 @@ impl UseSelf { pub fn new(msrv: Msrv) -> Self { Self { msrv, - ..Self::default() + stack: Vec::new(), } } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 23da1de77303..0075f611eb75 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -8,8 +8,9 @@ use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor}; use serde::Deserialize; use std::fmt::{Debug, Display, Formatter}; use std::ops::Range; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::str::FromStr; +use std::sync::OnceLock; use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] @@ -78,62 +79,35 @@ pub struct TryConf { impl TryConf { fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self { - ConfError::from_toml(file, error).into() - } -} - -impl From for TryConf { - fn from(value: ConfError) -> Self { Self { conf: Conf::default(), - errors: vec![value], + errors: vec![ConfError::from_toml(file, error)], warnings: vec![], } } } -impl From for TryConf { - fn from(value: io::Error) -> Self { - ConfError::from(value).into() - } -} - #[derive(Debug)] pub struct ConfError { pub message: String, - pub span: Option, + pub span: Span, } impl ConfError { fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self { - if let Some(span) = error.span() { - Self::spanned(file, error.message(), span) - } else { - Self { - message: error.message().to_string(), - span: None, - } - } + let span = error.span().unwrap_or(0..file.source_len.0 as usize); + Self::spanned(file, error.message(), span) } fn spanned(file: &SourceFile, message: impl Into, span: Range) -> Self { Self { message: message.into(), - span: Some(Span::new( + span: Span::new( file.start_pos + BytePos::from_usize(span.start), file.start_pos + BytePos::from_usize(span.end), SyntaxContext::root(), None, - )), - } - } -} - -impl From for ConfError { - fn from(value: io::Error) -> Self { - Self { - message: value.to_string(), - span: None, + ), } } } @@ -297,7 +271,7 @@ define_Conf! { /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. /// /// The minimum rust version that the project supports - (msrv: Option = None), + (msrv: crate::Msrv = crate::Msrv::empty()), /// DEPRECATED LINT: BLACKLISTED_NAME. /// /// Use the Disallowed Names lint instead @@ -641,15 +615,8 @@ pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { } } -/// Read the `toml` configuration file. -/// -/// In case of error, the function tries to continue as much as possible. -pub fn read(sess: &Session, path: &Path) -> TryConf { - let file = match sess.source_map().load_file(path) { - Err(e) => return e.into(), - Ok(file) => file, - }; - match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(&file)) { +fn deserialize(file: &SourceFile) -> TryConf { + match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); @@ -662,7 +629,7 @@ pub fn read(sess: &Session, path: &Path) -> TryConf { conf }, - Err(e) => TryConf::from_toml_error(&file, &e), + Err(e) => TryConf::from_toml_error(file, &e), } } @@ -672,6 +639,60 @@ fn extend_vec_if_indicator_present(vec: &mut Vec, default: &[&str]) { } } +impl Conf { + pub fn read(sess: &Session, path: &io::Result<(Option, Vec)>) -> &'static Conf { + static CONF: OnceLock = OnceLock::new(); + CONF.get_or_init(|| Conf::read_inner(sess, path)) + } + + fn read_inner(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { + match path { + Ok((_, warnings)) => { + for warning in warnings { + sess.warn(warning.clone()); + } + }, + Err(error) => { + sess.err(format!("error finding Clippy's configuration file: {error}")); + }, + } + + let TryConf { + mut conf, + errors, + warnings, + } = match path { + Ok((Some(path), _)) => match sess.source_map().load_file(path) { + Ok(file) => deserialize(&file), + Err(error) => { + sess.err(format!("failed to read `{}`: {error}", path.display())); + TryConf::default() + }, + }, + _ => TryConf::default(), + }; + + conf.msrv.read_cargo(sess); + + // all conf errors are non-fatal, we just use the default conf in case of error + for error in errors { + sess.span_err( + error.span, + format!("error reading Clippy's configuration file: {}", error.message), + ); + } + + for warning in warnings { + sess.span_warn( + warning.span, + format!("error reading Clippy's configuration file: {}", warning.message), + ); + } + + conf + } +} + const SEPARATOR_WIDTH: usize = 4; #[derive(Debug)] diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 8522493f67b3..90091ca927ae 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -9,6 +9,7 @@ arrayvec = { version = "0.7", default-features = false } if_chain = "1.0" itertools = "0.10.1" rustc-semver = "1.1" +serde = { version = "1.0" } [features] deny-warnings = [] diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index df839c2106f1..c6a48874e09b 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -1,9 +1,7 @@ -use std::sync::OnceLock; - use rustc_ast::Attribute; use rustc_semver::RustcVersion; use rustc_session::Session; -use rustc_span::Span; +use serde::Deserialize; use crate::attrs::get_unique_attr; @@ -53,65 +51,45 @@ msrv_aliases! { 1,15,0 { MAYBE_BOUND_IN_WHERE } } -fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { - if let Ok(version) = RustcVersion::parse(msrv) { - return Some(version); - } else if let Some(sess) = sess { - if let Some(span) = span { - sess.span_err(span, format!("`{msrv}` is not a valid Rust version")); - } - } - None -} - /// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct Msrv { stack: Vec, } +impl<'de> Deserialize<'de> for Msrv { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let v = String::deserialize(deserializer)?; + RustcVersion::parse(&v) + .map(|v| Msrv { stack: vec![v] }) + .map_err(|_| serde::de::Error::custom("not a valid Rust version")) + } +} + impl Msrv { - fn new(initial: Option) -> Self { - Self { - stack: Vec::from_iter(initial), - } + pub fn empty() -> Msrv { + Msrv { stack: Vec::new() } } - fn read_inner(conf_msrv: &Option, sess: &Session) -> Self { + pub fn read_cargo(&mut self, sess: &Session) { let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") .ok() - .and_then(|v| parse_msrv(&v, None, None)); - let clippy_msrv = conf_msrv.as_ref().and_then(|s| { - parse_msrv(s, None, None).or_else(|| { - sess.err(format!( - "error reading Clippy's configuration file. `{s}` is not a valid Rust version" - )); - None - }) - }); + .and_then(|v| RustcVersion::parse(&v).ok()); - // if both files have an msrv, let's compare them and emit a warning if they differ - if let Some(cargo_msrv) = cargo_msrv - && let Some(clippy_msrv) = clippy_msrv - && clippy_msrv != cargo_msrv - { - sess.warn(format!( - "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" - )); + match (self.current(), cargo_msrv) { + (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv], + (Some(clippy_msrv), Some(cargo_msrv)) => { + if clippy_msrv != cargo_msrv { + sess.warn(format!( + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" + )); + } + }, + _ => {}, } - - Self::new(clippy_msrv.or(cargo_msrv)) - } - - /// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version` - /// field in `Cargo.toml` - /// - /// Returns a `&'static Msrv` as `Copy` types are more easily passed to the - /// `register_{late,early}_pass` callbacks - pub fn read(conf_msrv: &Option, sess: &Session) -> &'static Self { - static PARSED: OnceLock = OnceLock::new(); - - PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess)) } pub fn current(&self) -> Option { @@ -125,10 +103,14 @@ impl Msrv { fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option { if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") { if let Some(msrv) = msrv_attr.value_str() { - return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span)); - } + if let Ok(version) = RustcVersion::parse(msrv.as_str()) { + return Some(version); + } - sess.span_err(msrv_attr.span, "bad clippy attribute"); + sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version")); + } else { + sess.span_err(msrv_attr.span, "bad clippy attribute"); + } } None diff --git a/src/driver.rs b/src/driver.rs index d47767faed9e..0e81419f1fa3 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -147,9 +147,9 @@ impl rustc_driver::Callbacks for ClippyCallbacks { (previous)(sess, lint_store); } - let conf = clippy_lints::read_conf(sess, &conf_path); - clippy_lints::register_plugins(lint_store, sess, &conf); - clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf); + let conf = clippy_lints::Conf::read(sess, &conf_path); + clippy_lints::register_plugins(lint_store, sess, conf); + clippy_lints::register_pre_expansion_lints(lint_store, conf); clippy_lints::register_renamed(lint_store); })); diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs index 03fa719975b6..85e2fb8c797f 100644 --- a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs @@ -1,4 +1,4 @@ -//@error-in-other-file: `invalid.version` is not a valid Rust version +//@error-in-other-file: not a valid Rust version #![allow(clippy::redundant_clone)] diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr index e9d8fd2e0f52..f127c2408f90 100644 --- a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version +error: error reading Clippy's configuration file: not a valid Rust version + --> $DIR/$DIR/clippy.toml:1:8 + | +LL | msrv = "invalid.version" + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error From a07c032e96bdf12747cb0431fe2bfbd9db3fb0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 18 Oct 2023 22:10:48 +0000 Subject: [PATCH 058/107] Tweak wording of type errors involving type params Fix #78206. --- tests/ui/builtin_type_shadow.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/builtin_type_shadow.stderr b/tests/ui/builtin_type_shadow.stderr index cb8462182b89..e051c00eb8d2 100644 --- a/tests/ui/builtin_type_shadow.stderr +++ b/tests/ui/builtin_type_shadow.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | fn foo(a: u32) -> u32 { | --- --- expected `u32` because of return type | | - | this type parameter + | expected this type parameter LL | 42 | ^^ expected type parameter `u32`, found integer | From e8d4fb8aaafa598d3021f2378705f780ee173458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 18 Oct 2023 22:54:35 +0000 Subject: [PATCH 059/107] Suggest relaxing implicit `type Assoc: Sized;` bound Fix #85378. --- .../src/traits/error_reporting/suggestions.rs | 23 +++++++++++++++++++ .../assoc_type_bounds_implicit_sized.fixed | 10 ++++++++ .../assoc_type_bounds_implicit_sized.rs | 10 ++++++++ .../assoc_type_bounds_implicit_sized.stderr | 20 ++++++++++++++++ .../assoc_type_bounds_sized_used.stderr | 4 ++++ 5 files changed, 67 insertions(+) create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 78f7f915f726..8f1ebc24b945 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2652,6 +2652,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Check for foreign traits being reachable. self.tcx.visible_parent_map(()).get(&def_id).is_some() }; + if Some(def_id) == self.tcx.lang_items().sized_trait() + && let Some(hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Type(bounds, None), + .. + })) = tcx.hir().get_if_local(item_def_id) + // Do not suggest relaxing if there is an explicit `Sized` obligation. + && !bounds.iter() + .filter_map(|bound| bound.trait_ref()) + .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait()) + { + let (span, separator) = if let [.., last] = bounds { + (last.span().shrink_to_hi(), " +") + } else { + (ident.span.shrink_to_hi(), ":") + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{separator} ?Sized"), + Applicability::MachineApplicable, + ); + } if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed new file mode 100644 index 000000000000..45c7e07a2647 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed @@ -0,0 +1,10 @@ +// run-rustfix +trait TraitWithAType { + type Item: ?Sized; +} +trait Trait {} +struct A {} +impl TraitWithAType for A { + type Item = dyn Trait; //~ ERROR E0277 +} +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs new file mode 100644 index 000000000000..c3e958f49839 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs @@ -0,0 +1,10 @@ +// run-rustfix +trait TraitWithAType { + type Item; +} +trait Trait {} +struct A {} +impl TraitWithAType for A { + type Item = dyn Trait; //~ ERROR E0277 +} +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr new file mode 100644 index 000000000000..110e71507337 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time + --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17 + | +LL | type Item = dyn Trait; + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` +note: required by a bound in `TraitWithAType::Item` + --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5 + | +LL | type Item; + | ^^^^^^^^^^ required by this bound in `TraitWithAType::Item` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Item: ?Sized; + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr index 224d33fb2da1..b67a1244ecea 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr @@ -33,6 +33,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` LL - fn bop() { LL + fn bop() { | +help: consider relaxing the implicit `Sized` restriction + | +LL | type Bar: Default + ?Sized + | ++++++++ error: aborting due to 2 previous errors From 8a45eed31c90ca9f0795d1743c706222f990c975 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 19 Oct 2023 08:39:28 +0300 Subject: [PATCH 060/107] fix bootstrap paths in triagebot.toml Signed-off-by: onur-ozkan --- triagebot.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index fbdc28787ff0..893908eb7e3d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -23,10 +23,10 @@ allow-unauthenticated = [ "needs-triage", ] -[review-submitted] -# This label is added when a "request changes" review is submitted. -reviewed_label = "S-waiting-on-author" -# These labels are removed when a "request changes" review is submitted. +[review-submitted] +# This label is added when a "request changes" review is submitted. +reviewed_label = "S-waiting-on-author" +# These labels are removed when a "request changes" review is submitted. review_labels = ["S-waiting-on-review"] [review-requested] @@ -586,17 +586,17 @@ message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x message = "Third-party dependency whitelist may have been modified! You must ensure that any new dependencies have compatible licenses before merging." cc = ["@davidtwco", "@wesleywiser"] -[mentions."src/bootstrap/config.rs"] -message = "This PR changes `src/bootstrap/config.rs`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/lib.rs` and `change-id` in `config.example.toml`." +[mentions."src/bootstrap/src/core/config"] +message = "This PR modifies `src/bootstrap/src/core/config`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`." [mentions."config.example.toml"] -message = "This PR changes `config.example.toml`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/lib.rs` and `change-id` in `config.example.toml`." +message = "This PR changes `config.example.toml`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`." [mentions."src/bootstrap/defaults/config.compiler.toml"] message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appropriate, please also update `config.codegen.toml` so the defaults are in sync." [mentions."src/bootstrap/defaults/config.codegen.toml"] message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync." -[mentions."src/bootstrap/llvm.rs"] +[mentions."src/bootstrap/src/core/build_steps/llvm.rs"] message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." [mentions."tests/ui/deriving/deriving-all-codegen.stdout"] From 0c55576a06a948f7bad9249c63688caed080a79d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 19 Oct 2023 08:39:55 +0300 Subject: [PATCH 061/107] trigger the triagebot for modifications to bootstrap/defaults Signed-off-by: onur-ozkan --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 893908eb7e3d..e3c4233c843b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -588,6 +588,8 @@ cc = ["@davidtwco", "@wesleywiser"] [mentions."src/bootstrap/src/core/config"] message = "This PR modifies `src/bootstrap/src/core/config`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`." +[mentions."src/bootstrap/defaults"] +message = "This PR modifies `src/bootstrap/defaults`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`." [mentions."config.example.toml"] message = "This PR changes `config.example.toml`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`." From 8ff2954150d96e1765cd695352948538c2ee9b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 19 Oct 2023 09:16:55 +0200 Subject: [PATCH 062/107] Fix x64_64-gnu-llvm-15 CI tests There were two command chains separated by `&&` in the script, and since `set -e` doesn't exit for chained commands, if the first chain has failed, the command would happily continue forward, ignoring any test failures. --- .../host-x86_64/x86_64-gnu-llvm-15/script.sh | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh index 918b19612ae4..7d40db2ee234 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh @@ -4,34 +4,34 @@ set -ex # Only run the stage 1 tests on merges, not on PR CI jobs. if [[ -z "${PR_CI_JOB}" ]]; then - ../x.py --stage 1 test --skip src/tools/tidy && \ - # Run the `mir-opt` tests again but this time for a 32-bit target. - # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have - # both 32-bit and 64-bit outputs updated by the PR author, before - # the PR is approved and tested for merging. - # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, - # despite having different output on 32-bit vs 64-bit targets. - ../x.py --stage 1 test tests/mir-opt \ - --host='' --target=i686-unknown-linux-gnu && \ - # Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0 - # compiler, and is sensitive to the addition of new flags. - ../x.py --stage 1 test tests/ui-fulldeps + ../x.py --stage 1 test --skip src/tools/tidy + + # Run the `mir-opt` tests again but this time for a 32-bit target. + # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have + # both 32-bit and 64-bit outputs updated by the PR author, before + # the PR is approved and tested for merging. + # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, + # despite having different output on 32-bit vs 64-bit targets. + ../x.py --stage 1 test tests/mir-opt --host='' --target=i686-unknown-linux-gnu + + # Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0 + # compiler, and is sensitive to the addition of new flags. + ../x.py --stage 1 test tests/ui-fulldeps fi # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. -../x.py --stage 2 test --skip src/tools/tidy && \ - # Run the `mir-opt` tests again but this time for a 32-bit target. - # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have - # both 32-bit and 64-bit outputs updated by the PR author, before - # the PR is approved and tested for merging. - # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, - # despite having different output on 32-bit vs 64-bit targets. - ../x --stage 2 test tests/mir-opt \ - --host='' --target=i686-unknown-linux-gnu && \ - # Run the UI test suite again, but in `--pass=check` mode - # - # This is intended to make sure that both `--pass=check` continues to - # work. - # - ../x.ps1 --stage 2 test tests/ui --pass=check \ - --host='' --target=i686-unknown-linux-gnu +../x.py --stage 2 test --skip src/tools/tidy + +# Run the `mir-opt` tests again but this time for a 32-bit target. +# This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have +# both 32-bit and 64-bit outputs updated by the PR author, before +# the PR is approved and tested for merging. +# It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, +# despite having different output on 32-bit vs 64-bit targets. +../x --stage 2 test tests/mir-opt --host='' --target=i686-unknown-linux-gnu + +# Run the UI test suite again, but in `--pass=check` mode +# +# This is intended to make sure that both `--pass=check` continues to +# work. +../x.ps1 --stage 2 test tests/ui --pass=check --host='' --target=i686-unknown-linux-gnu From c2524bc6899a1a7feebda032dd26f751504e94e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 19 Oct 2023 09:52:29 +0200 Subject: [PATCH 063/107] Fix `span_use_eq_ctxt` test The stage0 compiler does not know about the lint yet, so ignore the test on stage1. --- tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs | 2 ++ tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs index 39980ee7c672..aeb68bf05e1e 100644 --- a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs +++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs @@ -1,4 +1,6 @@ // Test the `rustc::span_use_eq_ctxt` internal lint +// #[cfg(bootstrap)] +// ignore-stage1 // compile-flags: -Z unstable-options #![feature(rustc_private)] diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr index b33f62125454..3d8a7dd1ec05 100644 --- a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr +++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr @@ -1,11 +1,11 @@ error: use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` - --> $DIR/span_use_eq_ctxt.rs:12:5 + --> $DIR/span_use_eq_ctxt.rs:14:5 | LL | s.ctxt() == t.ctxt() | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/span_use_eq_ctxt.rs:5:9 + --> $DIR/span_use_eq_ctxt.rs:7:9 | LL | #![deny(rustc::span_use_eq_ctxt)] | ^^^^^^^^^^^^^^^^^^^^^^^ From bdc597d512b080ddc7bb8c1eef938e002686243e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:39:40 +0000 Subject: [PATCH 064/107] Rustup to rustc 1.75.0-nightly (0039d739d 2023-10-18) --- patches/stdlib-lock.toml | 5 ++--- rust-toolchain | 2 +- src/lib.rs | 6 +++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/patches/stdlib-lock.toml b/patches/stdlib-lock.toml index de89c4f5eff8..f10b4d6b9d4f 100644 --- a/patches/stdlib-lock.toml +++ b/patches/stdlib-lock.toml @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" dependencies = [ "rustc-std-workspace-core", ] @@ -361,7 +361,6 @@ version = "0.0.0" dependencies = [ "addr2line", "alloc", - "cc", "cfg-if", "compiler_builtins", "core", diff --git a/rust-toolchain b/rust-toolchain index 86ef127badd4..8d6188f8dc42 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-09" +channel = "nightly-2023-10-19" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/src/lib.rs b/src/lib.rs index e4847bcb1783..148193b5a975 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ -#![cfg_attr(not(bootstrap), allow(internal_features))] -#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] -#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(all(doc, not(bootstrap)), allow(internal_features))] +#![cfg_attr(all(doc, not(bootstrap)), feature(rustdoc_internals))] +#![cfg_attr(all(doc, not(bootstrap)), doc(rust_logo))] #![feature(rustc_private)] // Note: please avoid adding other feature gates where possible #![warn(rust_2018_idioms)] From b97201088788c11b66e711d1e9cfa480c947f3d3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:44:27 +0000 Subject: [PATCH 065/107] Fix CG_CLIF_DISABLE_INCR_CACHE --- src/driver/aot.rs | 48 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 49f51f9f956b..6aabc40e4a65 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -394,28 +394,32 @@ pub(crate) fn run_aot( let modules = tcx.sess.time("codegen mono items", || { cgus.iter() .enumerate() - .map(|(i, cgu)| match cgu_reuse[i] { - CguReuse::No => { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( - dep_node, - tcx, - ( - backend_config.clone(), - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.sess.diagnostic()), - ), - module_codegen, - Some(rustc_middle::dep_graph::hash_result), - ) - .0 - } - CguReuse::PreLto => unreachable!("LTO not yet supported"), - CguReuse::PostLto => { - concurrency_limiter.job_already_done(); - OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) + .map(|(i, cgu)| { + let cgu_reuse = + if backend_config.disable_incr_cache { CguReuse::No } else { cgu_reuse[i] }; + match cgu_reuse { + CguReuse::No => { + let dep_node = cgu.codegen_dep_node(tcx); + tcx.dep_graph + .with_task( + dep_node, + tcx, + ( + backend_config.clone(), + global_asm_config.clone(), + cgu.name(), + concurrency_limiter.acquire(tcx.sess.diagnostic()), + ), + module_codegen, + Some(rustc_middle::dep_graph::hash_result), + ) + .0 + } + CguReuse::PreLto => unreachable!("LTO not yet supported"), + CguReuse::PostLto => { + concurrency_limiter.job_already_done(); + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) + } } }) .collect::>() From 49987faf873790c39f981275708fa4dca8836ef3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:20:25 +0000 Subject: [PATCH 066/107] Fix rustc test suite --- scripts/test_rustc_tests.sh | 1 - src/driver/aot.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 4b6d5bd97b85..68d4a29bab4f 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -122,7 +122,6 @@ rm tests/ui/typeck/issue-46112.rs # same rm tests/ui/consts/const_cmp_type_id.rs # same rm tests/ui/consts/issue-73976-monomorphic.rs # same rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same -rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs # same rm tests/ui/consts/issue-94675.rs # same rm tests/ui/associated-types/issue-85103-layout-debug.rs # same diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 6aabc40e4a65..d3a7decc5430 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -415,8 +415,7 @@ pub(crate) fn run_aot( ) .0 } - CguReuse::PreLto => unreachable!("LTO not yet supported"), - CguReuse::PostLto => { + CguReuse::PreLto | CguReuse::PostLto => { concurrency_limiter.job_already_done(); OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) } From d7256a6a0d81a6c6cd182aab22e724f43e702a0c Mon Sep 17 00:00:00 2001 From: Claes Gill Date: Thu, 19 Oct 2023 22:32:11 +0200 Subject: [PATCH 067/107] Updated README with expandable table of content. --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index f0c45f341d81..a88ee4b8bf06 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,20 @@ standard library, and documentation. If you wish to _contribute_ to the compiler, you should read [CONTRIBUTING.md](CONTRIBUTING.md) instead. +
+Table of content + +- [Quick Start](#quick-start) +- [Installing from Source](#installing-from-source) +- [Building Documentation](#building-documentation) +- [Notes](#notes) +- [Getting Help](#getting-help) +- [Contributing](#contributing) +- [License](#license) +- [Trademark](#trademark) + +
+ ## Quick Start Read ["Installation"] from [The Book]. From 63790138761f3c77389df5521dd2f40ee0be2982 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 19 Oct 2023 20:18:51 -0300 Subject: [PATCH 068/107] Initiate the inner usage of `cfg_match` --- Cargo.lock | 2 -- compiler/rustc_data_structures/Cargo.toml | 1 - compiler/rustc_data_structures/src/flock.rs | 13 ++++--- compiler/rustc_data_structures/src/lib.rs | 35 ++++++++++--------- compiler/rustc_data_structures/src/marker.rs | 31 +++++++--------- .../rustc_data_structures/src/profiling.rs | 13 ++++--- compiler/rustc_data_structures/src/sync.rs | 7 ++-- compiler/rustc_span/Cargo.toml | 1 - .../rustc_span/src/analyze_source_file.rs | 8 ++--- compiler/rustc_span/src/lib.rs | 27 +++++++------- 10 files changed, 70 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa2f9c4147e3..55d6146395f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3664,7 +3664,6 @@ version = "0.0.0" dependencies = [ "arrayvec", "bitflags 1.3.2", - "cfg-if", "elsa", "ena", "indexmap 2.0.0", @@ -4496,7 +4495,6 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ - "cfg-if", "indexmap 2.0.0", "md-5", "rustc_arena", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index f77bd53e76c6..dce4e199e17e 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" [dependencies] arrayvec = { version = "0.7", default-features = false } bitflags = "1.2.1" -cfg-if = "1.0" ena = "0.14.2" indexmap = { version = "2.0.0" } jobserver_crate = { version = "0.1.13", package = "jobserver" } diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index efdb44248d1d..008565e4c7b9 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -4,17 +4,20 @@ //! green/native threading. This is just a bare-bones enough solution for //! librustdoc, it is not production quality at all. -cfg_if! { - if #[cfg(target_os = "linux")] { +cfg_match! { + cfg(target_os = "linux") => { mod linux; use linux as imp; - } else if #[cfg(unix)] { + } + cfg(unix) => { mod unix; use unix as imp; - } else if #[cfg(windows)] { + } + cfg(windows) => { mod windows; use self::windows as imp; - } else { + } + _ => { mod unsupported; use unsupported as imp; } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 9511f1700e10..5d7f385c6e4a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,43 +6,44 @@ //! //! This API is completely unstable and subject to change. +// tidy-alphabetical-start +#![allow(internal_features)] +#![allow(rustc::default_hash_types)] +#![allow(rustc::potential_query_instability)] #![cfg_attr(not(bootstrap), doc(rust_logo))] #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![deny(rustc::diagnostic_outside_of_impl)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(unsafe_op_in_unsafe_fn)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(allocator_api)] #![feature(array_windows)] #![feature(auto_traits)] #![feature(cell_leak)] +#![feature(cfg_match)] #![feature(core_intrinsics)] #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] +#![feature(lazy_cell)] +#![feature(lint_reasons)] +#![feature(macro_metavar_expr)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] -#![feature(never_type)] -#![feature(type_alias_impl_trait)] -#![feature(lazy_cell)] -#![feature(rustc_attrs)] #![feature(negative_impls)] +#![feature(never_type)] +#![feature(ptr_alignment_type)] +#![feature(rustc_attrs)] +#![feature(strict_provenance)] #![feature(test)] #![feature(thread_id_value)] -#![feature(allocator_api)] -#![feature(lint_reasons)] +#![feature(type_alias_impl_trait)] #![feature(unwrap_infallible)] -#![feature(strict_provenance)] -#![feature(ptr_alignment_type)] -#![feature(macro_metavar_expr)] -#![allow(rustc::default_hash_types)] -#![allow(rustc::potential_query_instability)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] -#![allow(internal_features)] -#![deny(unsafe_op_in_unsafe_fn)] +// tidy-alphabetical-end #[macro_use] extern crate tracing; #[macro_use] -extern crate cfg_if; -#[macro_use] extern crate rustc_macros; use std::fmt; diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index b067f9d4502d..a8c442377fbc 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,11 +1,12 @@ -cfg_if!( - if #[cfg(not(parallel_compiler))] { +cfg_match! { + cfg(not(parallel_compiler)) => { pub auto trait DynSend {} pub auto trait DynSync {} impl DynSend for T {} impl DynSync for T {} - } else { + } + _ => { #[rustc_on_unimplemented( message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`" @@ -48,13 +49,10 @@ cfg_if!( [std::io::StdoutLock<'_>] [std::io::StderrLock<'_>] ); - cfg_if!( - // Consistent with `std` - // `os_imp::Env` is `!Send` in these platforms - if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { - impl !DynSend for std::env::VarsOs {} - } - ); + + #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] + // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms + impl !DynSend for std::env::VarsOs {} macro_rules! already_send { ($([$ty: ty])*) => { @@ -123,13 +121,10 @@ cfg_if!( [std::sync::mpsc::Receiver where T] [std::sync::mpsc::Sender where T] ); - cfg_if!( - // Consistent with `std` - // `os_imp::Env` is `!Sync` in these platforms - if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { - impl !DynSync for std::env::VarsOs {} - } - ); + + #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] + // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms + impl !DynSync for std::env::VarsOs {} macro_rules! already_sync { ($([$ty: ty])*) => { @@ -183,7 +178,7 @@ cfg_if!( [thin_vec::ThinVec where T: DynSync] ); } -); +} pub fn assert_dyn_sync() {} pub fn assert_dyn_send() {} diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index e688feb5fe17..ef7375a73206 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -859,8 +859,8 @@ fn get_thread_id() -> u32 { } // Memory reporting -cfg_if! { - if #[cfg(windows)] { +cfg_match! { + cfg(windows) => { pub fn get_resident_set_size() -> Option { use std::mem; @@ -885,7 +885,8 @@ cfg_if! { Some(pmc.WorkingSetSize) } - } else if #[cfg(target_os = "macos")] { + } + cfg(target_os = "macos") => { pub fn get_resident_set_size() -> Option { use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO}; use std::mem; @@ -903,7 +904,8 @@ cfg_if! { } } } - } else if #[cfg(unix)] { + } + cfg(unix) => { pub fn get_resident_set_size() -> Option { let field = 1; let contents = fs::read("/proc/self/statm").ok()?; @@ -912,7 +914,8 @@ cfg_if! { let npages = s.parse::().ok()?; Some(npages * 4096) } - } else { + } + _ => { pub fn get_resident_set_size() -> Option { None } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index cca043ba0d18..62fff604f813 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -109,8 +109,8 @@ mod mode { pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; -cfg_if! { - if #[cfg(not(parallel_compiler))] { +cfg_match! { + cfg(not(parallel_compiler)) => { use std::ops::Add; use std::cell::Cell; @@ -251,7 +251,8 @@ cfg_if! { MTLock(self.0.clone()) } } - } else { + } + _ => { pub use std::marker::Send as Send; pub use std::marker::Sync as Sync; diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index ee93f74e750d..31c2a56faa53 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -13,7 +13,6 @@ rustc_index = { path = "../rustc_index" } rustc_arena = { path = "../rustc_arena" } scoped-tls = "1.0" unicode-width = "0.1.4" -cfg-if = "1.0" tracing = "0.1" sha1 = "0.10.0" sha2 = "0.10.1" diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 450d5455ff93..7da7dc610ecf 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -33,8 +33,8 @@ pub fn analyze_source_file( (lines, multi_byte_chars, non_narrow_chars) } -cfg_if::cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { +cfg_match! { + cfg(any(target_arch = "x86", target_arch = "x86_64")) => { fn analyze_source_file_dispatch(src: &str, lines: &mut Vec, multi_byte_chars: &mut Vec, @@ -172,8 +172,8 @@ cfg_if::cfg_if! { non_narrow_chars); } } - } else { - + } + _ => { // The target (or compiler version) does not support SSE2 ... fn analyze_source_file_dispatch(src: &str, lines: &mut Vec, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e62efab5793f..661dfa64d33f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -13,21 +13,24 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +// tidy-alphabetical-start +#![allow(internal_features)] #![cfg_attr(not(bootstrap), doc(rust_logo))] #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] -#![feature(array_windows)] -#![feature(if_let_guard)] -#![feature(negative_impls)] -#![feature(min_specialization)] -#![feature(rustc_attrs)] -#![feature(let_chains)] -#![feature(round_char_boundary)] -#![feature(read_buf)] -#![feature(new_uninit)] -#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -#![allow(internal_features)] +#![deny(rustc::untranslatable_diagnostic)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] +#![feature(cfg_match)] +#![feature(if_let_guard)] +#![feature(let_chains)] +#![feature(min_specialization)] +#![feature(negative_impls)] +#![feature(new_uninit)] +#![feature(read_buf)] +#![feature(round_char_boundary)] +#![feature(rustc_attrs)] +// tidy-alphabetical-end #[macro_use] extern crate rustc_macros; From 6ed2a76bcc2a963c28080d6ee3ad928ec9367a03 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 19 Oct 2023 17:06:53 -0700 Subject: [PATCH 069/107] Add stable Instance::body() and RustcInternal trait The `Instance::body()` returns a monomorphized body. For that, we had to implement visitor that monomorphize types and constants. We are also introducing the RustcInternal trait that will allow us to convert back from Stable to Internal. Note that this trait is not yet visible for our users as it depends on Tables. We should probably add a new trait that can be exposed. --- .../rustc_smir/src/rustc_internal/internal.rs | 61 +++++++++++++++++++ compiler/rustc_smir/src/rustc_internal/mod.rs | 10 +++ compiler/rustc_smir/src/rustc_smir/builder.rs | 55 +++++++++++++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 22 +++++-- compiler/stable_mir/src/error.rs | 7 +++ compiler/stable_mir/src/lib.rs | 4 ++ compiler/stable_mir/src/mir/body.rs | 27 +++++++- compiler/stable_mir/src/mir/mono.rs | 11 +++- compiler/stable_mir/src/ty.rs | 2 + .../{instance.rs => check_instance.rs} | 26 +++++++- 10 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_smir/src/rustc_internal/internal.rs create mode 100644 compiler/rustc_smir/src/rustc_smir/builder.rs rename tests/ui-fulldeps/stable-mir/{instance.rs => check_instance.rs} (73%) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs new file mode 100644 index 000000000000..f42a97393206 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -0,0 +1,61 @@ +//! Module containing the translation from stable mir constructs to the rustc counterpart. +//! +//! This module will only include a few constructs to allow users to invoke internal rustc APIs +//! due to incomplete stable coverage. + +// Prefer importing stable_mir over internal rustc constructs to make this file more readable. +use crate::rustc_smir::{MaybeStable, Tables}; +use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; +use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty}; +use stable_mir::DefId; + +use super::RustcInternal; + +impl<'tcx> RustcInternal<'tcx> for DefId { + type T = rustc_span::def_id::DefId; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.def_ids[*self] + } +} + +impl<'tcx> RustcInternal<'tcx> for GenericArgs { + type T = rustc_ty::GenericArgsRef<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables))) + } +} + +impl<'tcx> RustcInternal<'tcx> for GenericArgKind { + type T = rustc_ty::GenericArg<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + GenericArgKind::Lifetime(reg) => reg.internal(tables).into(), + GenericArgKind::Type(ty) => ty.internal(tables).into(), + GenericArgKind::Const(cnst) => cnst.internal(tables).into(), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Region { + type T = rustc_ty::Region<'tcx>; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + todo!() + } +} + +impl<'tcx> RustcInternal<'tcx> for Ty { + type T = InternalTy<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match tables.types[self.0] { + MaybeStable::Stable(_) => todo!(), + MaybeStable::Rustc(ty) => ty, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Const { + type T = rustc_ty::Const<'tcx>; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + todo!() + } +} diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 5ea805e5739b..473a59f750a7 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -20,6 +20,8 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::{ControlFlow, Index}; +mod internal; + impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -231,3 +233,11 @@ impl Index { + type T; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T; +} diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs new file mode 100644 index 000000000000..8ff3958da7bd --- /dev/null +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -0,0 +1,55 @@ +//! Logic required to produce a monomorphic stable body. +//! +//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a +//! monomorphic body using internal representation. +//! After that, we convert the internal representation into a stable one. +use crate::rustc_smir::{Stable, Tables}; +use rustc_middle::mir; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +/// Builds a monomorphic body for a given instance. +pub struct BodyBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, +} + +impl<'tcx> BodyBuilder<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { + BodyBuilder { tcx, instance } + } + + pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body { + let mut body = self.tcx.instance_mir(self.instance.def).clone(); + let generics = self.tcx.generics_of(self.instance.def_id()); + if generics.requires_monomorphization(self.tcx) { + self.visit_body(&mut body); + } + body.stable(tables) + } + + fn monomorphize(&self, value: T) -> T + where + T: ty::TypeFoldable>, + { + self.instance.instantiate_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(value), + ) + } +} + +impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { + fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) { + *ct = self.monomorphize(*ct); + } + + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: mir::visit::TyContext) { + *ty = self.monomorphize(*ty); + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 94dc15b4767c..604dc3582b53 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,7 +7,7 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. -use crate::rustc_internal::IndexMap; +use crate::rustc_internal::{IndexMap, RustcInternal}; use crate::rustc_smir::hir::def::DefKind; use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region}; use rustc_hir as hir; @@ -26,6 +26,7 @@ use stable_mir::{self, opaque, Context, Filename}; use tracing::debug; mod alloc; +mod builder; impl<'tcx> Context for Tables<'tcx> { fn local_crate(&self) -> stable_mir::Crate { @@ -171,8 +172,9 @@ impl<'tcx> Context for Tables<'tcx> { } } - fn instance_body(&mut self, _def: InstanceDef) -> Body { - todo!("Monomorphize the body") + fn instance_body(&mut self, def: InstanceDef) -> Body { + let instance = self.instances[def]; + builder::BodyBuilder::new(self.tcx, instance).build(self) } fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty { @@ -195,9 +197,21 @@ impl<'tcx> Context for Tables<'tcx> { let def_id = self[def_id]; let generics = self.tcx.generics_of(def_id); let result = generics.requires_monomorphization(self.tcx); - println!("req {result}: {def_id:?}"); result } + + fn resolve_instance( + &mut self, + def: stable_mir::ty::FnDef, + args: &stable_mir::ty::GenericArgs, + ) -> Option { + let def_id = def.0.internal(self); + let args_ref = args.internal(self); + match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + Ok(Some(instance)) => Some(instance.stable(self)), + Ok(None) | Err(_) => None, + } + } } #[derive(Clone)] diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 12ac8f1ca65a..199106914562 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -4,6 +4,7 @@ //! - [CompilerError]: This represents errors that can be raised when invoking the compiler. //! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. +use std::convert::From; use std::fmt::{Debug, Display, Formatter}; use std::{error, fmt}; @@ -31,6 +32,12 @@ impl Error { } } +impl From<&str> for Error { + fn from(value: &str) -> Self { + Self(value.into()) + } +} + impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 59af3f64ad34..be5ccac78c7c 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -39,6 +39,7 @@ pub mod visitor; pub use error::*; use mir::mono::Instance; +use ty::{FnDef, GenericArgs}; /// Use String for now but we should replace it. pub type Symbol = String; @@ -233,6 +234,9 @@ pub trait Context { /// Item requires monomorphization. fn requires_monomorphization(&self, def_id: DefId) -> bool; + + /// Resolve an instance from the given function definition and generic arguments. + fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 72f026ee8de0..46fa8f4d922a 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -5,9 +5,11 @@ use crate::{ty::Ty, Span}; #[derive(Clone, Debug)] pub struct Body { pub blocks: Vec, - pub locals: Vec, + pub locals: LocalDecls, } +type LocalDecls = Vec; + #[derive(Clone, Debug)] pub struct LocalDecl { pub ty: Ty, @@ -344,6 +346,7 @@ pub enum Operand { #[derive(Clone, Debug)] pub struct Place { pub local: Local, + /// projection out of a place (access a field, deref a pointer, etc) pub projection: String, } @@ -462,3 +465,25 @@ pub enum NullOp { /// Returns the offset of a field. OffsetOf(Vec), } + +impl Operand { + pub fn ty(&self, locals: &LocalDecls) -> Ty { + match self { + Operand::Copy(place) | Operand::Move(place) => place.ty(locals), + Operand::Constant(c) => c.ty(), + } + } +} + +impl Constant { + pub fn ty(&self) -> Ty { + self.literal.ty + } +} + +impl Place { + pub fn ty(&self, locals: &LocalDecls) -> Ty { + let _start_ty = locals[self.local].ty; + todo!("Implement projection") + } +} diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index d8e8ccb04548..997576fc7cbf 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::mir::Body; -use crate::ty::{IndexedVal, Ty}; +use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, Opaque}; use std::fmt::Debug; @@ -41,6 +41,15 @@ impl Instance { pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) } + + /// Resolve an instance starting from a function definition and generic arguments. + pub fn resolve(def: FnDef, args: &GenericArgs) -> Result { + with(|context| { + context.resolve_instance(def, args).ok_or_else(|| { + crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`")) + }) + }) + } } /// Try to convert a crate item into an instance. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 003045a4696d..440c9a1f031c 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -225,6 +225,8 @@ pub struct ImplDef(pub DefId); #[derive(Clone, PartialEq, Eq, Debug)] pub struct RegionDef(pub DefId); +/// A list of generic arguments. +/// The second field is for internal usage to allow retrieving the internal representation. #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); diff --git a/tests/ui-fulldeps/stable-mir/instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs similarity index 73% rename from tests/ui-fulldeps/stable-mir/instance.rs rename to tests/ui-fulldeps/stable-mir/check_instance.rs index fe06d9b5cc96..288c163a6a3f 100644 --- a/tests/ui-fulldeps/stable-mir/instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -15,7 +15,8 @@ extern crate rustc_smir; extern crate stable_mir; use rustc_middle::ty::TyCtxt; - +use mir::{mono::Instance, TerminatorKind::*}; +use stable_mir::ty::{TyKind, RigidTy}; use stable_mir::*; use rustc_smir::rustc_internal; use std::io::Write; @@ -43,9 +44,28 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // For all generic items, try_from should fail. assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err())); + for instance in instances { + test_body(instance.body()) + } ControlFlow::Continue(()) } +/// Inspect the instance body +fn test_body(body: mir::Body) { + for term in body.blocks.iter().map(|bb| &bb.terminator) { + match &term.kind { + Call{ func, .. } => { + let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() }; + let RigidTy::FnDef(def, args) = ty else { unreachable!() }; + let result = Instance::resolve(def, &args); + assert!(result.is_ok()); + } + Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */} + _ => { unreachable!("Unexpected terminator {term:?}") } + } + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. @@ -56,6 +76,7 @@ fn main() { generate_input(&path).unwrap(); let args = vec![ "rustc".to_string(), + "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), @@ -78,6 +99,9 @@ fn generate_input(path: &str) -> std::io::Result<()> { }} pub fn monomorphic() {{ + let v = vec![10]; + let dup = ty_param(&v); + assert_eq!(v, dup); }} pub mod foo {{ From 35f03b763eb40a10bfad50285c9b1128fec6d96a Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Fri, 20 Oct 2023 14:52:56 +0200 Subject: [PATCH 070/107] Move `invalid-llvm-passes` test to `invalid-compile-flags` folder Nowadays there is an `invalid-compile-flags` folder, thus move this one there. Signed-off-by: Miguel Ojeda --- .../ui/{invalid => invalid-compile-flags}/invalid-llvm-passes.rs | 0 .../{invalid => invalid-compile-flags}/invalid-llvm-passes.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{invalid => invalid-compile-flags}/invalid-llvm-passes.rs (100%) rename tests/ui/{invalid => invalid-compile-flags}/invalid-llvm-passes.stderr (100%) diff --git a/tests/ui/invalid/invalid-llvm-passes.rs b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs similarity index 100% rename from tests/ui/invalid/invalid-llvm-passes.rs rename to tests/ui/invalid-compile-flags/invalid-llvm-passes.rs diff --git a/tests/ui/invalid/invalid-llvm-passes.stderr b/tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr similarity index 100% rename from tests/ui/invalid/invalid-llvm-passes.stderr rename to tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr From 9a963e80260f8fc26c502e30ffca43661e454ad0 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sat, 5 Aug 2023 16:15:05 +0100 Subject: [PATCH 071/107] std: freebsd build update. since freebsd 11 had been removed, minimum is now 12. --- library/std/build.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 046ac488b1ff..2521ad8efc06 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -4,10 +4,8 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); if target.contains("freebsd") { - if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() { - println!("cargo:rustc-cfg=freebsd12"); - } else if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() { - println!("cargo:rustc-cfg=freebsd12"); + println!("cargo:rustc-cfg=freebsd12"); + if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() { println!("cargo:rustc-cfg=freebsd13"); } } else if target.contains("linux") From 6e643e12bb7b0381052696bfe1f7ecbd47769904 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 20 Oct 2023 08:23:16 -0700 Subject: [PATCH 072/107] Remove obsolete comment --- compiler/stable_mir/src/ty.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 440c9a1f031c..d4a9b318cfc4 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -226,7 +226,6 @@ pub struct ImplDef(pub DefId); pub struct RegionDef(pub DefId); /// A list of generic arguments. -/// The second field is for internal usage to allow retrieving the internal representation. #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); From b0d17f35d98c5cafd43a673c70f8ab5d393c31a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Oct 2023 22:34:45 +0000 Subject: [PATCH 073/107] Typo suggestion to change bindings with leading underscore When encountering a binding that isn't found but has a typo suggestion for a binding with a leading underscore, suggest changing the binding definition instead of the use place. Fix #60164. --- compiler/rustc_resolve/src/diagnostics.rs | 17 +++++++++++++++-- .../ui/suggestions/silenced-binding-typo.fixed | 5 +++++ tests/ui/suggestions/silenced-binding-typo.rs | 5 +++++ .../ui/suggestions/silenced-binding-typo.stderr | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/ui/suggestions/silenced-binding-typo.fixed create mode 100644 tests/ui/suggestions/silenced-binding-typo.rs create mode 100644 tests/ui/suggestions/silenced-binding-typo.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 925ee615b095..4ad838e5aed2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1511,9 +1511,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ), ); } + + let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && let Some(span) = suggestion.span + && let Some(candidate) = suggestion.candidate.as_str().strip_prefix("_") + && snippet == candidate + { + // When the suggested binding change would be from `x` to `_x`, suggest changing the + // original binding definition instead. (#60164) + (span, snippet, ", consider changing it") + } else { + (span, suggestion.candidate.to_string(), "") + }; let msg = match suggestion.target { SuggestionTarget::SimilarlyNamed => format!( - "{} {} with a similar name exists", + "{} {} with a similar name exists{post}", suggestion.res.article(), suggestion.res.descr() ), @@ -1521,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("maybe you meant this {}", suggestion.res.descr()) } }; - err.span_suggestion(span, msg, suggestion.candidate, Applicability::MaybeIncorrect); + err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); true } diff --git a/tests/ui/suggestions/silenced-binding-typo.fixed b/tests/ui/suggestions/silenced-binding-typo.fixed new file mode 100644 index 000000000000..e0f9e31bef31 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.fixed @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let x = 42; //~ HELP + let _y = x; //~ ERROR +} diff --git a/tests/ui/suggestions/silenced-binding-typo.rs b/tests/ui/suggestions/silenced-binding-typo.rs new file mode 100644 index 000000000000..6cadd5a93a75 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.rs @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _x = 42; //~ HELP + let _y = x; //~ ERROR +} diff --git a/tests/ui/suggestions/silenced-binding-typo.stderr b/tests/ui/suggestions/silenced-binding-typo.stderr new file mode 100644 index 000000000000..9c0e6e265690 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/silenced-binding-typo.rs:4:14 + | +LL | let _y = x; + | ^ + | +help: a local variable with a similar name exists, consider changing it + | +LL | let x = 42; + | ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 14e66dbf5d9e78b780dce80c7f42b881bcfed85d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:14:52 +0000 Subject: [PATCH 074/107] Update Cranelift to 0.101.0 --- Cargo.lock | 52 ++++++++++++++++++++++++++-------------------------- Cargo.toml | 12 ++++++------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c324421be9c..8079913cb0ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b9d1a9e776c27ad55d7792a380785d1fe8c2d7b099eed8dbd8f4af2b598192" +checksum = "8e5e1df0da8488dd03b34afc134ba84b754d61862cc465932a9e5d07952f661e" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5528483314c2dd5da438576cd8a9d0b3cedad66fb8a4727f90cd319a81950038" +checksum = "77a17ca4e699a0aaf49a0c88f6311a864f321048aa63f6b787cab20eb5f93f10" dependencies = [ "bumpalo", "cranelift-bforest", @@ -75,39 +75,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f46a8318163f7682e35b8730ba93c1b586a2da8ce12a0ed545efc1218550f70" +checksum = "022f2793cdade1d37a1f755ac42938a3f832f533eac6cafc8b26b209544c3c06" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d1239cfd50eecfaed468d46943f8650e32969591868ad50111613704da6c70" +checksum = "a4d72dbb83c2ad788dec4ad0843070973cb48c35a3ca19b1e7437ac40834fd9c" [[package]] name = "cranelift-control" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc530560c8f16cc1d4dd7ea000c56f519c60d1a914977abe849ce555c35a61d" +checksum = "ae07cf26dcc90d546826d747ac63b6c40c916f34b03e92a6ae0422c28d771b8a" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f333fa641a9ad2bff0b107767dcb972c18c2bfab7969805a1d7e42449ccb0408" +checksum = "c2fe6b7e49820893691aea497f36257e9d6f52061d8c4758d61d802d5f101a3d" [[package]] name = "cranelift-frontend" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abf6563015a80f03f8bc4df307d0a81363f4eb73108df3a34f6e66fb6d5307" +checksum = "44f497576ca3674581581601b6a55ccc1b43447217648c880e5bce70db3cf659" dependencies = [ "cranelift-codegen", "log", @@ -117,15 +117,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb29d0edc8a5c029ed0f7ca77501f272738e3c410020b4a00f42ffe8ad2a8aa" +checksum = "b96aa02eac00fffee13b0cd37d17874ccdb3d5458983041accd825ef78ce6454" [[package]] name = "cranelift-jit" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16e8c5e212b1e63658aada17553497e7a259acab61f044d1f185527efa609fb" +checksum = "b1d6e0e308c873eefc185745a6b21daec2a10f7554c9fb67e334c2d7d756d979" dependencies = [ "anyhow", "cranelift-codegen", @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b5fd273e1a959e920c7a9d790b1646d31acc8782bb549bad5ab85dd2fc9aa7" +checksum = "c1aa8ebb06eced4e478c3f94f1d65d4e7c93493f4640057912b27a3e34b84841" dependencies = [ "anyhow", "cranelift-codegen", @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006056a7fa920870bad06bf8e1b3033d70cbb7ee625b035efa9d90882a931868" +checksum = "2870170ca44054b202c737626607b87be6e35655084bd94a6ff807a5812ba7df" dependencies = [ "cranelift-codegen", "libc", @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.100.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8be1b0e7720f30fec31be0c0b0b23caef2a73fa751190c6a251c1362e8f8c9" +checksum = "20647761742d17dabac8205da958910ede78599550e06418a16711a3ee2fc897" dependencies = [ "anyhow", "cranelift-codegen", @@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "13.0.0" +version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ff5f3707a5e3797deeeeac6ac26b2e1dd32dbc06693c0ab52e8ac4d18ec706" +checksum = "a3a5dda53ad6993f9b0a2d65fb49e0348a7232a27a8794064122870d6ee19eb2" dependencies = [ "cfg-if", "libc", diff --git a/Cargo.toml b/Cargo.toml index 28a37b7995b7..5ad5e0e8140c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.100", features = ["unwind", "all-arch"] } -cranelift-frontend = { version = "0.100" } -cranelift-module = { version = "0.100" } -cranelift-native = { version = "0.100" } -cranelift-jit = { version = "0.100", optional = true } -cranelift-object = { version = "0.100" } +cranelift-codegen = { version = "0.101", features = ["unwind", "all-arch"] } +cranelift-frontend = { version = "0.101" } +cranelift-module = { version = "0.101" } +cranelift-native = { version = "0.101" } +cranelift-jit = { version = "0.101", optional = true } +cranelift-object = { version = "0.101" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } From 88bccf454fb488e516e0e408c139f1525e5298e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 18:50:25 +0000 Subject: [PATCH 075/107] Mention `into_iter` on borrow errors suggestions when appropriate If we encounter a borrow error on `vec![1, 2, 3].iter()`, suggest `into_iter`. Fix #68445. --- .../src/diagnostics/conflict_errors.rs | 22 +++++++++++++++++++ .../lifetimes/borrowck-let-suggestion.stderr | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 20a4402f6f69..36f3c939d558 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2263,6 +2263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { current: usize, found: usize, prop_expr: Option<&'tcx hir::Expr<'tcx>>, + call: Option<&'tcx hir::Expr<'tcx>>, } impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { @@ -2272,6 +2273,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.current -= 1; } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind { + if self.span == rcvr.span.source_callsite() { + self.call = Some(expr); + } + } if self.span == expr.span.source_callsite() { self.found = self.current; if self.prop_expr.is_none() { @@ -2295,6 +2301,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { current: 0, found: 0, prop_expr: None, + call: None, }; visitor.visit_stmt(stmt); @@ -2316,6 +2323,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { + if let Some(call) = visitor.call + && let hir::ExprKind::MethodCall(path, _, [], _) = call.kind + && path.ident.name == sym::iter + && let Some(ty) = expr_ty + { + err.span_suggestion_verbose( + path.ident.span, + format!( + "consider consuming the `{ty}` when turning it into an \ + `Iterator`", + ), + "into_iter".to_string(), + Applicability::MaybeIncorrect, + ); + } if !is_format_arguments_item { let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); err.multipart_suggestion_verbose( diff --git a/tests/ui/lifetimes/borrowck-let-suggestion.stderr b/tests/ui/lifetimes/borrowck-let-suggestion.stderr index da0078698ae3..621196647644 100644 --- a/tests/ui/lifetimes/borrowck-let-suggestion.stderr +++ b/tests/ui/lifetimes/borrowck-let-suggestion.stderr @@ -10,6 +10,10 @@ LL | x.use_mut(); | - borrow later used here | = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider consuming the `Vec` when turning it into an `Iterator` + | +LL | let mut x = vec![1].into_iter(); + | ~~~~~~~~~ help: consider using a `let` binding to create a longer lived value | LL ~ let binding = vec![1]; From 8e264ab07af022a42e912d47ced44c37711b0f3a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 19 Oct 2023 16:06:43 +0000 Subject: [PATCH 076/107] s/Generator/Coroutine/ --- example/std_example.rs | 2 +- scripts/test_rustc_tests.sh | 2 +- src/base.rs | 2 +- src/constant.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/std_example.rs b/example/std_example.rs index 490cc2404f62..edebc3d4c4d3 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -12,7 +12,7 @@ use std::arch::x86_64::*; use std::hint::black_box; use std::io::Write; -use std::ops::Generator; +use std::ops::Coroutine; fn main() { println!("{:?}", std::env::args().collect::>()); diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 3b2a12ec0280..c83efa51e9ea 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -157,7 +157,7 @@ rm -r tests/run-make/compressed-debuginfo rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported -rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug with Generator's +rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug with Coroutine's # bugs in the test suite # ====================== diff --git a/src/base.rs b/src/base.rs index ac7389792c80..80e7c5bd9edb 100644 --- a/src/base.rs +++ b/src/base.rs @@ -478,7 +478,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { TerminatorKind::Yield { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop => { + | TerminatorKind::CoroutineDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { diff --git a/src/constant.rs b/src/constant.rs index 1cb6fa077231..b0853d30e03b 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -510,7 +510,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | TerminatorKind::Drop { .. } | TerminatorKind::Assert { .. } => {} TerminatorKind::Yield { .. } - | TerminatorKind::GeneratorDrop + | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => unreachable!(), TerminatorKind::InlineAsm { .. } => return None, From 868e513935876bb9de4ce7e10d9d77ca5612b4a1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 19 Oct 2023 16:06:43 +0000 Subject: [PATCH 077/107] s/Generator/Coroutine/ --- clippy_lints/src/async_yields_async.rs | 6 +++--- clippy_lints/src/await_holding_invalid.rs | 10 +++++----- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 ++-- clippy_lints/src/needless_question_mark.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 4 ++-- clippy_lints/src/unused_async.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 9464694a3b55..99daec560e75 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; +use rustc_hir::{AsyncCoroutineKind, Body, BodyId, ExprKind, CoroutineKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,10 +45,10 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use AsyncGeneratorKind::{Block, Closure}; + use AsyncCoroutineKind::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure)) = body.generator_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index accff9b0a34c..65d131c5751a 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{AsyncGeneratorKind, Body, GeneratorKind}; +use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::GeneratorLayout; +use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; @@ -195,8 +195,8 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use AsyncGeneratorKind::{Block, Closure, Fn}; - if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind { + use AsyncCoroutineKind::{Block, Closure, Fn}; + if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.generator_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) { self.check_interior_types(cx, generator_layout); @@ -206,7 +206,7 @@ impl LateLintPass<'_> for AwaitHolding { } impl AwaitHolding { - fn check_interior_types(&self, cx: &LateContext<'_>, generator: &GeneratorLayout<'_>) { + fn check_interior_types(&self, cx: &LateContext<'_>, generator: &CoroutineLayout<'_>) { for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { let await_points = || { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5134cf66050c..efe82036dc80 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -842,8 +842,8 @@ impl TyCoercionStability { | ty::Adt(..) | ty::Foreign(_) | ty::FnDef(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) | ty::Closure(..) | ty::Never | ty::Tuple(_) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index e789e0da6797..ca9defc2bf35 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -436,7 +436,7 @@ fn lint_for_missing_headers( let body = cx.tcx.hir().body(body_id); let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); - if let ty::Generator(_, subs, _) = ret_ty.kind(); + if let ty::Coroutine(_, subs, _) = ret_ty.kind(); if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); then { span_lint( diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 19f1e08b57ad..90096f0f506d 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// It checks for the size of a `Future` created by `async fn` or `async {}`. /// /// ### Why is this bad? - /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`, + /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Coroutine`, /// large size of a `Future` may cause stack overflows. /// /// ### Example diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 577bc1d661db..499763347517 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, + AsyncCoroutineKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, CoroutineKind, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); + if closure_body.generator_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); then { return Some(closure_body); } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 0e834fb3ac76..f2c823323bbb 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath}; +use rustc_hir::{AsyncCoroutineKind, Block, Body, Expr, ExprKind, CoroutineKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.generator_kind { if let ExprKind::Block( Block { expr: diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 8193057a6eb2..59aecd232783 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource}; +use rustc_hir::{AsyncCoroutineKind, Closure, Expr, ExprKind, CoroutineKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.generator_kind, Some(GeneratorKind::Async(AsyncGeneratorKind::Block))) + matches!(body.generator_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) { cx .typeck_results() diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index bc7c3897a6e8..5e1ba1b0dc06 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.generator_kind, Some(rustc_hir::GeneratorKind::Async(_))); + let is_async_block = matches!(b.generator_kind, Some(rustc_hir::CoroutineKind::Async(_))); if is_async_block { self.async_depth += 1; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 55f9cb27ad4d..0d8fd9d2adf1 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -305,7 +305,7 @@ fn check_terminator<'tcx>( Ok(()) }, TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) }, TerminatorKind::Call { From 4519e6895797adc6e3e9dc616fb0cf0e8ee3ec2e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 19 Oct 2023 21:46:28 +0000 Subject: [PATCH 078/107] s/generator/coroutine/ --- example/std_example.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/std_example.rs b/example/std_example.rs index edebc3d4c4d3..9bd2ab5c638c 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -1,7 +1,7 @@ #![feature( core_intrinsics, - generators, - generator_trait, + coroutines, + coroutine_trait, is_sorted, repr_simd, tuple_trait, From d9259fdedd96d03a9226e899a853c97d391eb94d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 19 Oct 2023 21:46:28 +0000 Subject: [PATCH 079/107] s/generator/coroutine/ --- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 14 +++++++------- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 4 ++-- clippy_lints/src/unused_async.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- tests/ui/crashes/ice-5238.rs | 2 +- tests/ui/large_futures.fixed | 2 +- tests/ui/large_futures.rs | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 99daec560e75..96a90d599aba 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { use AsyncCoroutineKind::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Async(Block | Closure)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 65d131c5751a..60f9bbd7458b 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -196,25 +196,25 @@ impl LateLintPass<'_> for AwaitHolding { fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { use AsyncCoroutineKind::{Block, Closure, Fn}; - if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) { - self.check_interior_types(cx, generator_layout); + if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { + self.check_interior_types(cx, coroutine_layout); } } } } impl AwaitHolding { - fn check_interior_types(&self, cx: &LateContext<'_>, generator: &CoroutineLayout<'_>) { - for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() { + fn check_interior_types(&self, cx: &LateContext<'_>, coroutine: &CoroutineLayout<'_>) { + for (ty_index, ty_cause) in coroutine.field_tys.iter_enumerated() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { let await_points = || { - generator + coroutine .variant_source_info .iter_enumerated() .filter_map(|(variant, source_info)| { - generator.variant_fields[variant] + coroutine.variant_fields[variant] .raw .contains(&ty_index) .then_some(source_info.span) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index ca9defc2bf35..fc9b381664a3 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -437,7 +437,7 @@ fn lint_for_missing_headers( let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); if let ty::Coroutine(_, subs, _) = ret_ty.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); + if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result); then { span_lint( cx, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 499763347517..914ceca2995d 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.generator_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); + if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); then { return Some(closure_body); } diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 674d34517481..b44a2716dde1 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( if_chain! { if !expr.span.from_expansion(); if let ExprKind::Closure(c) = m_arg.kind; - if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); + if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index f2c823323bbb..d267b3de7f25 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 59aecd232783..b8f787e1f1fb 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.generator_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) + matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) { cx .typeck_results() diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f42836611ca5..c18237e887db 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // without this check, we'd end up linting twice. && !matches!(recv.kind, hir::ExprKind::Call(..)) && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) - && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth) + && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth) { span_lint_and_then( cx, @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { let mut applicability = Applicability::MachineApplicable; let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); - if generator_kind.is_async() + if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { let async_closure_body = cx.tcx.hir().body(closure.body); diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 5e1ba1b0dc06..3649f8792ae5 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.generator_kind, Some(rustc_hir::CoroutineKind::Async(_))); + let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_))); if is_async_block { self.async_depth += 1; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 0d8fd9d2adf1..f6096ea546da 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -306,7 +306,7 @@ fn check_terminator<'tcx>( }, TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { - Err((span, "const fn generators are unstable".into())) + Err((span, "const fn coroutines are unstable".into())) }, TerminatorKind::Call { func, diff --git a/tests/ui/crashes/ice-5238.rs b/tests/ui/crashes/ice-5238.rs index 989eb6d44855..b1fc3fb9d251 100644 --- a/tests/ui/crashes/ice-5238.rs +++ b/tests/ui/crashes/ice-5238.rs @@ -1,6 +1,6 @@ // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 -#![feature(generators, generator_trait)] +#![feature(coroutines, coroutine_trait)] fn main() { let _ = || { diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index 4c192d1c8d1b..aa8c3021b970 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 557d89a9cf99..fc6ea458d3db 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] From 939a224ce39fbc422e14d8255616fc587b845b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 22:11:01 +0000 Subject: [PATCH 080/107] Point at assoc fn definition on type param divergence When the number of type parameters in the associated function of an impl and its trait differ, we now *always* point at the trait one, even if it comes from a foreign crate. When it is local, we point at the specific params, when it is foreign, we point at the whole associated item. Fix #69944. --- .../src/check/compare_impl_item.rs | 24 ++++--------------- tests/ui/typeck/issue-36708.stderr | 7 +++++- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index a1470cc69c30..74e2b157dd0a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1557,38 +1557,24 @@ fn compare_number_of_generics<'tcx>( DiagnosticId::Error("E0049".into()), ); - let mut suffix = None; - + let msg = + format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); if let Some(spans) = trait_spans { let mut spans = spans.iter(); if let Some(span) = spans.next() { - err.span_label( - *span, - format!( - "expected {} {} parameter{}", - trait_count, - kind, - pluralize!(trait_count), - ), - ); + err.span_label(*span, msg); } for span in spans { err.span_label(*span, ""); } } else { - suffix = Some(format!(", expected {trait_count}")); + err.span_label(tcx.def_span(trait_.def_id), msg); } if let Some(span) = span { err.span_label( span, - format!( - "found {} {} parameter{}{}", - impl_count, - kind, - pluralize!(impl_count), - suffix.unwrap_or_default(), - ), + format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),), ); } diff --git a/tests/ui/typeck/issue-36708.stderr b/tests/ui/typeck/issue-36708.stderr index 140f19f1ff77..f1e0f4719281 100644 --- a/tests/ui/typeck/issue-36708.stderr +++ b/tests/ui/typeck/issue-36708.stderr @@ -2,7 +2,12 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 --> $DIR/issue-36708.rs:8:12 | LL | fn foo() {} - | ^ found 1 type parameter, expected 0 + | ^ found 1 type parameter + | + ::: $DIR/auxiliary/issue-36708.rs:4:5 + | +LL | fn foo(); + | --------- expected 0 type parameters error: aborting due to previous error From f4791420abb907471e693ed7de5e7763f412c6cc Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 20 Oct 2023 15:12:02 +0100 Subject: [PATCH 081/107] changes from feedback --- library/std/build.rs | 8 ++------ library/std/src/os/freebsd/fs.rs | 10 ---------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 2521ad8efc06..ad0a82eab8ca 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -3,15 +3,11 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - if target.contains("freebsd") { - println!("cargo:rustc-cfg=freebsd12"); - if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() { - println!("cargo:rustc-cfg=freebsd13"); - } - } else if target.contains("linux") + if target.contains("linux") || target.contains("netbsd") || target.contains("dragonfly") || target.contains("openbsd") + || target.contains("freebsd") || target.contains("solaris") || target.contains("illumos") || target.contains("apple-darwin") diff --git a/library/std/src/os/freebsd/fs.rs b/library/std/src/os/freebsd/fs.rs index 8db3a950c40f..5689a82e00a3 100644 --- a/library/std/src/os/freebsd/fs.rs +++ b/library/std/src/os/freebsd/fs.rs @@ -76,12 +76,7 @@ impl MetadataExt for Metadata { fn as_raw_stat(&self) -> &raw::stat { // The methods below use libc::stat, so they work fine when libc is built with FreeBSD 12 ABI. // This method would just return nonsense. - #[cfg(freebsd12)] panic!("as_raw_stat not supported with FreeBSD 12 ABI"); - #[cfg(not(freebsd12))] - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) - } } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 @@ -143,12 +138,7 @@ impl MetadataExt for Metadata { fn st_flags(&self) -> u32 { self.as_inner().as_inner().st_flags as u32 } - #[cfg(freebsd12)] fn st_lspare(&self) -> u32 { panic!("st_lspare not supported with FreeBSD 12 ABI"); } - #[cfg(not(freebsd12))] - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } } From dca42959bc4c71243674efe943e85f91f41aeb6a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 18:41:10 +1100 Subject: [PATCH 082/107] coverage: Add a test showing the inconsistent handling of function signatures --- tests/coverage-map/fn_sig_into_try.cov-map | 53 +++++++++++++++++++++ tests/coverage-map/fn_sig_into_try.rs | 41 ++++++++++++++++ tests/run-coverage/fn_sig_into_try.coverage | 45 +++++++++++++++++ tests/run-coverage/fn_sig_into_try.rs | 41 ++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 tests/coverage-map/fn_sig_into_try.cov-map create mode 100644 tests/coverage-map/fn_sig_into_try.rs create mode 100644 tests/run-coverage/fn_sig_into_try.coverage create mode 100644 tests/run-coverage/fn_sig_into_try.rs diff --git a/tests/coverage-map/fn_sig_into_try.cov-map b/tests/coverage-map/fn_sig_into_try.cov-map new file mode 100644 index 000000000000..5727ff4ce85e --- /dev/null +++ b/tests/coverage-map/fn_sig_into_try.cov-map @@ -0,0 +1,53 @@ +Function name: fn_sig_into_try::a +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2) + +Function name: fn_sig_into_try::b +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 12, 05, 00, 0f, 00, 00, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 18, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 15) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: fn_sig_into_try::c +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 00, 17, 00, 00, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 24, 13) to (start + 0, 23) +- Code(Zero) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: fn_sig_into_try::d +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1c, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 28, 1) to (start + 3, 15) +- Code(Zero) at (prev + 3, 15) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage-map/fn_sig_into_try.rs b/tests/coverage-map/fn_sig_into_try.rs new file mode 100644 index 000000000000..92850c8a188f --- /dev/null +++ b/tests/coverage-map/fn_sig_into_try.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +// compile-flags: --edition=2021 + +// Regression test for inconsistent handling of function signature spans that +// are followed by code using the `?` operator. +// +// For each of these similar functions, the line containing the function +// signature should be handled in the same way. + +fn a() -> Option +{ + Some(7i32); + Some(0) +} + +fn b() -> Option +{ + Some(7i32)?; + Some(0) +} + +fn c() -> Option +{ + let _ = Some(7i32)?; + Some(0) +} + +fn d() -> Option +{ + let _: () = (); + Some(7i32)?; + Some(0) +} + +#[coverage(off)] +fn main() { + a(); + b(); + c(); + d(); +} diff --git a/tests/run-coverage/fn_sig_into_try.coverage b/tests/run-coverage/fn_sig_into_try.coverage new file mode 100644 index 000000000000..86defeeb9dae --- /dev/null +++ b/tests/run-coverage/fn_sig_into_try.coverage @@ -0,0 +1,45 @@ + LL| |#![feature(coverage_attribute)] + LL| |// compile-flags: --edition=2021 + LL| | + LL| |// Regression test for inconsistent handling of function signature spans that + LL| |// are followed by code using the `?` operator. + LL| |// + LL| |// For each of these similar functions, the line containing the function + LL| |// signature should be handled in the same way. + LL| | + LL| 1|fn a() -> Option + LL| 1|{ + LL| 1| Some(7i32); + LL| 1| Some(0) + LL| 1|} + LL| | + LL| |fn b() -> Option + LL| |{ + LL| 1| Some(7i32)?; + ^0 + LL| 1| Some(0) + LL| 1|} + LL| | + LL| |fn c() -> Option + LL| |{ + LL| 1| let _ = Some(7i32)?; + ^0 + LL| 1| Some(0) + LL| 1|} + LL| | + LL| 1|fn d() -> Option + LL| 1|{ + LL| 1| let _: () = (); + LL| 1| Some(7i32)?; + ^0 + LL| 1| Some(0) + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | a(); + LL| | b(); + LL| | c(); + LL| | d(); + LL| |} + diff --git a/tests/run-coverage/fn_sig_into_try.rs b/tests/run-coverage/fn_sig_into_try.rs new file mode 100644 index 000000000000..92850c8a188f --- /dev/null +++ b/tests/run-coverage/fn_sig_into_try.rs @@ -0,0 +1,41 @@ +#![feature(coverage_attribute)] +// compile-flags: --edition=2021 + +// Regression test for inconsistent handling of function signature spans that +// are followed by code using the `?` operator. +// +// For each of these similar functions, the line containing the function +// signature should be handled in the same way. + +fn a() -> Option +{ + Some(7i32); + Some(0) +} + +fn b() -> Option +{ + Some(7i32)?; + Some(0) +} + +fn c() -> Option +{ + let _ = Some(7i32)?; + Some(0) +} + +fn d() -> Option +{ + let _: () = (); + Some(7i32)?; + Some(0) +} + +#[coverage(off)] +fn main() { + a(); + b(); + c(); + d(); +} From a17ff82aaec7a693c1cfe50bfc221dac4b06f8ad Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 18:58:35 +1100 Subject: [PATCH 083/107] coverage: Handle fn signature spans more consistently near `?` --- compiler/rustc_mir_transform/src/coverage/spans.rs | 2 +- tests/coverage-map/fn_sig_into_try.cov-map | 12 ++++++------ tests/coverage-map/status-quo/inline-dead.cov-map | 14 ++++++++------ tests/coverage-map/status-quo/issue-84561.cov-map | 6 +++--- tests/run-coverage/fn_sig_into_try.coverage | 8 ++++---- tests/run-coverage/issue-84561.coverage | 2 +- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 3f7ba5725104..9718ffb3e5bc 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -80,7 +80,7 @@ impl CoverageSpan { expn_span: fn_sig_span, current_macro_or_none: Default::default(), bcb: START_BCB, - merged_spans: vec![], + merged_spans: vec![fn_sig_span], is_closure: false, } } diff --git a/tests/coverage-map/fn_sig_into_try.cov-map b/tests/coverage-map/fn_sig_into_try.cov-map index 5727ff4ce85e..4672e7c1ce90 100644 --- a/tests/coverage-map/fn_sig_into_try.cov-map +++ b/tests/coverage-map/fn_sig_into_try.cov-map @@ -7,30 +7,30 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2) Function name: fn_sig_into_try::b -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 12, 05, 00, 0f, 00, 00, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 10, 01, 02, 0f, 00, 02, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 18, 5) to (start + 0, 15) -- Code(Zero) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) +- Code(Zero) at (prev + 2, 15) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) = (c1 + (c0 - c1)) Function name: fn_sig_into_try::c -Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 00, 17, 00, 00, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 01, 02, 17, 00, 02, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 13) to (start + 0, 23) -- Code(Zero) at (prev + 0, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 23) +- Code(Zero) at (prev + 2, 23) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) diff --git a/tests/coverage-map/status-quo/inline-dead.cov-map b/tests/coverage-map/status-quo/inline-dead.cov-map index 483f7ef79c63..06b64da5723b 100644 --- a/tests/coverage-map/status-quo/inline-dead.cov-map +++ b/tests/coverage-map/status-quo/inline-dead.cov-map @@ -31,13 +31,15 @@ Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 7, 6) to (start + 2, 2) Function name: inline_dead::main::{closure#0} -Raw bytes (16): 0x[01, 01, 01, 01, 05, 02, 00, 09, 0d, 00, 0e, 03, 02, 05, 00, 06] +Raw bytes (23): 0x[01, 01, 02, 09, 06, 01, 05, 03, 01, 07, 17, 00, 18, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 2 -- Code(Zero) at (prev + 9, 13) to (start + 0, 14) +Number of expressions: 2 +- expression 0 operands: lhs = Counter(2), rhs = Expression(1, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24) +- Code(Zero) at (prev + 2, 13) to (start + 0, 14) - Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6) - = (c0 + c1) + = (c2 + (c0 - c1)) diff --git a/tests/coverage-map/status-quo/issue-84561.cov-map b/tests/coverage-map/status-quo/issue-84561.cov-map index 01fa7ec573c5..76340b1a78c7 100644 --- a/tests/coverage-map/status-quo/issue-84561.cov-map +++ b/tests/coverage-map/status-quo/issue-84561.cov-map @@ -7,15 +7,15 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19) Function name: ::fmt -Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 89, 01, 09, 00, 25, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 88, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 137, 9) to (start + 0, 37) -- Code(Counter(1)) at (prev + 0, 37) to (start + 0, 38) +- Code(Counter(0)) at (prev + 136, 5) to (start + 1, 37) +- Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6) diff --git a/tests/run-coverage/fn_sig_into_try.coverage b/tests/run-coverage/fn_sig_into_try.coverage index 86defeeb9dae..f1ddb1da7802 100644 --- a/tests/run-coverage/fn_sig_into_try.coverage +++ b/tests/run-coverage/fn_sig_into_try.coverage @@ -13,15 +13,15 @@ LL| 1| Some(0) LL| 1|} LL| | - LL| |fn b() -> Option - LL| |{ + LL| 1|fn b() -> Option + LL| 1|{ LL| 1| Some(7i32)?; ^0 LL| 1| Some(0) LL| 1|} LL| | - LL| |fn c() -> Option - LL| |{ + LL| 1|fn c() -> Option + LL| 1|{ LL| 1| let _ = Some(7i32)?; ^0 LL| 1| Some(0) diff --git a/tests/run-coverage/issue-84561.coverage b/tests/run-coverage/issue-84561.coverage index 222f877d36aa..e693866e2776 100644 --- a/tests/run-coverage/issue-84561.coverage +++ b/tests/run-coverage/issue-84561.coverage @@ -135,7 +135,7 @@ LL| 0|} LL| | LL| |impl std::fmt::Debug for Foo { - LL| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + LL| 7| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { LL| 7| write!(f, "try and succeed")?; ^0 LL| 7| Ok(()) From e16494469e7f5ad770c40d8c86cca5a2a02ebf01 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 23:02:22 +1100 Subject: [PATCH 084/107] coverage: Don't create an intermediate vec for each BCB's initial spans --- .../src/coverage/spans/from_mir.rs | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 02e2cf6b05e3..66620b1db2ac 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::captures::Captures; use rustc_middle::mir::{ self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, }; @@ -12,7 +13,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( body_span: Span, basic_coverage_blocks: &CoverageGraph, ) -> Vec { - let mut initial_spans = Vec::::with_capacity(mir_body.basic_blocks.len() * 2); + let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2); for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); } @@ -50,34 +51,30 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple // `Statement`s and/or `Terminator`s.) -fn bcb_to_initial_coverage_spans( - mir_body: &mir::Body<'_>, +fn bcb_to_initial_coverage_spans<'a, 'tcx>( + mir_body: &'a mir::Body<'tcx>, body_span: Span, bcb: BasicCoverageBlock, - bcb_data: &BasicCoverageBlockData, -) -> Vec { - bcb_data - .basic_blocks - .iter() - .flat_map(|&bb| { - let data = &mir_body[bb]; - data.statements - .iter() - .filter_map(move |statement| { - filtered_statement_span(statement).map(|span| { - CoverageSpan::for_statement( - statement, - function_source_span(span, body_span), - span, - bcb, - ) - }) + bcb_data: &'a BasicCoverageBlockData, +) -> impl Iterator + Captures<'a> + Captures<'tcx> { + bcb_data.basic_blocks.iter().flat_map(move |&bb| { + let data = &mir_body[bb]; + data.statements + .iter() + .filter_map(move |statement| { + filtered_statement_span(statement).map(|span| { + CoverageSpan::for_statement( + statement, + function_source_span(span, body_span), + span, + bcb, + ) }) - .chain(filtered_terminator_span(data.terminator()).map(|span| { - CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) - })) - }) - .collect() + }) + .chain(filtered_terminator_span(data.terminator()).map(|span| { + CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) + })) + }) } /// If the MIR `Statement` has a span contributive to computing coverage spans, From 319693a927f3cc7759586fcc3ae3fd740598c309 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 17 Oct 2023 21:22:02 +1100 Subject: [PATCH 085/107] coverage: Simplify initial creation of coverage spans --- .../rustc_mir_transform/src/coverage/spans.rs | 33 ++------------ .../src/coverage/spans/from_mir.rs | 44 ++++++++++++------- 2 files changed, 32 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 9718ffb3e5bc..f4016fb3fc05 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -2,7 +2,7 @@ use std::cell::OnceCell; use rustc_data_structures::graph::WithNumNodes; use rustc_index::IndexVec; -use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind}; +use rustc_middle::mir; use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP}; use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; @@ -75,29 +75,15 @@ struct CoverageSpan { impl CoverageSpan { pub fn for_fn_sig(fn_sig_span: Span) -> Self { - Self { - span: fn_sig_span, - expn_span: fn_sig_span, - current_macro_or_none: Default::default(), - bcb: START_BCB, - merged_spans: vec![fn_sig_span], - is_closure: false, - } + Self::new(fn_sig_span, fn_sig_span, START_BCB, false) } - pub fn for_statement( - statement: &Statement<'_>, + pub(super) fn new( span: Span, expn_span: Span, bcb: BasicCoverageBlock, + is_closure: bool, ) -> Self { - let is_closure = match statement.kind { - StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => { - matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _)) - } - _ => false, - }; - Self { span, expn_span, @@ -108,17 +94,6 @@ impl CoverageSpan { } } - pub fn for_terminator(span: Span, expn_span: Span, bcb: BasicCoverageBlock) -> Self { - Self { - span, - expn_span, - current_macro_or_none: Default::default(), - bcb, - merged_spans: vec![span], - is_closure: false, - } - } - pub fn merge_from(&mut self, mut other: CoverageSpan) { debug_assert!(self.is_mergeable(&other)); self.span = self.span.to(other.span); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 66620b1db2ac..6189e5379ea0 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,6 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_middle::mir::{ - self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, + self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_span::Span; @@ -59,24 +60,35 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( ) -> impl Iterator + Captures<'a> + Captures<'tcx> { bcb_data.basic_blocks.iter().flat_map(move |&bb| { let data = &mir_body[bb]; - data.statements - .iter() - .filter_map(move |statement| { - filtered_statement_span(statement).map(|span| { - CoverageSpan::for_statement( - statement, - function_source_span(span, body_span), - span, - bcb, - ) - }) - }) - .chain(filtered_terminator_span(data.terminator()).map(|span| { - CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) - })) + + let statement_spans = data.statements.iter().filter_map(move |statement| { + let expn_span = filtered_statement_span(statement)?; + let span = function_source_span(expn_span, body_span); + + Some(CoverageSpan::new(span, expn_span, bcb, is_closure(statement))) + }); + + let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { + let expn_span = filtered_terminator_span(terminator)?; + let span = function_source_span(expn_span, body_span); + + Some(CoverageSpan::new(span, expn_span, bcb, false)) + }); + + statement_spans.chain(terminator_span) }) } +fn is_closure(statement: &Statement<'_>) -> bool { + match statement.kind { + StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { + AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _) => true, + _ => false, + }, + _ => false, + } +} + /// If the MIR `Statement` has a span contributive to computing coverage spans, /// return it; otherwise return `None`. fn filtered_statement_span(statement: &Statement<'_>) -> Option { From e964ea5bf575d68f164d02e4d1aa45b5bf924c0d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 24 Sep 2023 21:06:39 +1000 Subject: [PATCH 086/107] coverage: Emit mappings for unused functions without generating stubs --- .../src/coverageinfo/mapgen.rs | 35 +++++++-- .../src/coverageinfo/mod.rs | 76 ++----------------- 2 files changed, 37 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index f75add90aa2c..4f12f4af175d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -4,7 +4,7 @@ use crate::coverageinfo::ffi::CounterMappingRegion; use crate::coverageinfo::map_data::FunctionCoverage; use crate::llvm; -use rustc_codegen_ssa::traits::ConstMethods; +use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -94,8 +94,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // Generate the LLVM IR representation of the coverage map and store it in a well-known global let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val); + let mut unused_function_names = Vec::new(); + let covfun_section_name = coverageinfo::covfun_section_name(cx); for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data { + if !is_used { + unused_function_names.push(mangled_function_name); + } + save_function_record( cx, &covfun_section_name, @@ -107,6 +113,25 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { ); } + // For unused functions, we need to take their mangled names and store them + // in a specially-named global array. LLVM's `InstrProfiling` pass will + // detect this global and include those names in its `__llvm_prf_names` + // section. (See `llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp`.) + if !unused_function_names.is_empty() { + assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); + + let name_globals = unused_function_names + .into_iter() + .map(|mangled_function_name| cx.const_str(mangled_function_name).0) + .collect::>(); + let initializer = cx.const_array(cx.type_ptr(), &name_globals); + + let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), "__llvm_coverage_names"); + llvm::set_global_constant(array, true); + llvm::set_linkage(array, llvm::Linkage::InternalLinkage); + llvm::set_initializer(array, initializer); + } + // Save the coverage data value to LLVM IR coverageinfo::save_cov_data_to_mod(cx, cov_data_val); } @@ -290,10 +315,10 @@ fn save_function_record( /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query /// `codegened_and_inlined_items`). /// -/// These unused functions are then codegen'd in one of the CGUs which is marked as the -/// "code coverage dead code cgu" during the partitioning process. This prevents us from generating -/// code regions for the same function more than once which can lead to linker errors regarding -/// duplicate symbols. +/// These unused functions don't need to be codegenned, but we do need to add them to the function +/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them. +/// We also end up adding their symbol names to a special global array that LLVM will include in +/// its embedded coverage data. fn add_unused_functions(cx: &CodegenCx<'_, '_>) { assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 204a73b788a6..5a5f6eb89f61 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -1,6 +1,5 @@ use crate::llvm; -use crate::abi::Abi; use crate::builder::Builder; use crate::common::CodegenCx; use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion}; @@ -12,17 +11,13 @@ use rustc_codegen_ssa::traits::{ StaticMethods, }; use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_llvm::RustString; use rustc_middle::bug; -use rustc_middle::mir::coverage::{CounterId, CoverageKind, FunctionCoverageInfo}; +use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo}; use rustc_middle::mir::Coverage; -use rustc_middle::ty; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::Instance; -use rustc_middle::ty::Ty; +use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt}; use std::cell::RefCell; @@ -30,8 +25,6 @@ pub(crate) mod ffi; pub(crate) mod map_data; pub mod mapgen; -const UNUSED_FUNCTION_COUNTER_ID: CounterId = CounterId::START; - const VAR_ALIGN_BYTES: usize = 8; /// A context object for maintaining all state needed by the coverageinfo module. @@ -77,22 +70,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } } - /// Functions with MIR-based coverage are normally codegenned _only_ if - /// called. LLVM coverage tools typically expect every function to be - /// defined (even if unused), with at least one call to LLVM intrinsic - /// `instrprof.increment`. - /// - /// Codegen a small function that will never be called, with one counter - /// that will never be incremented. - /// - /// For used/called functions, the coverageinfo was already added to the - /// `function_coverage_map` (keyed by function `Instance`) during codegen. - /// But in this case, since the unused function was _not_ previously - /// codegenned, collect the function coverage info from MIR and add an - /// "unused" entry to the function coverage map. fn define_unused_fn(&self, def_id: DefId, function_coverage_info: &'tcx FunctionCoverageInfo) { - let instance = declare_unused_fn(self, def_id); - codegen_unused_fn_and_counter(self, instance); + let instance = declare_unused_fn(self.tcx, def_id); add_unused_function_coverage(self, instance, function_coverage_info); } } @@ -159,10 +138,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } } -fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx> { - let tcx = cx.tcx; - - let instance = Instance::new( +fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { + Instance::new( def_id, GenericArgs::for_item(tcx, def_id, |param, _| { if let ty::GenericParamDefKind::Lifetime = param.kind { @@ -171,46 +148,7 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance< tcx.mk_param_from_def(param) } }), - ); - - let llfn = cx.declare_fn( - tcx.symbol_name(instance).name, - cx.fn_abi_of_fn_ptr( - ty::Binder::dummy(tcx.mk_fn_sig( - [Ty::new_unit(tcx)], - Ty::new_unit(tcx), - false, - hir::Unsafety::Unsafe, - Abi::Rust, - )), - ty::List::empty(), - ), - None, - ); - - llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage); - llvm::set_visibility(llfn, llvm::Visibility::Default); - - assert!(cx.instances.borrow_mut().insert(instance, llfn).is_none()); - - instance -} - -fn codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) { - let llfn = cx.get_fn(instance); - let llbb = Builder::append_block(cx, llfn, "unused_function"); - let mut bx = Builder::build(cx, llbb); - let fn_name = bx.get_pgo_func_name_var(instance); - let hash = bx.const_u64(0); - let num_counters = bx.const_u32(1); - let index = bx.const_u32(u32::from(UNUSED_FUNCTION_COUNTER_ID)); - debug!( - "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, - index={:?}) for unused function: {:?}", - fn_name, hash, num_counters, index, instance - ); - bx.instrprof_increment(fn_name, hash, num_counters, index); - bx.ret_void(); + ) } fn add_unused_function_coverage<'tcx>( From cdeeffde64b100ceb135135aef6879241ab6682f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 24 Sep 2023 22:26:12 +1000 Subject: [PATCH 087/107] coverage: Move unused-function helpers closer to where they are used --- .../src/coverageinfo/mapgen.rs | 43 ++++++++++++++++--- .../src/coverageinfo/mod.rs | 39 +---------------- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 4f12f4af175d..4653849a29d5 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -10,6 +10,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::bug; +use rustc_middle::mir; use rustc_middle::mir::coverage::CodeRegion; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; @@ -351,17 +352,47 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { let codegenned_def_ids = tcx.codegened_and_inlined_items(()); - for non_codegenned_def_id in - eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) - { + // For each `DefId` that should have coverage instrumentation but wasn't + // codegenned, add it to the function coverage map as an unused function. + for def_id in eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) { // Skip any function that didn't have coverage data added to it by the // coverage instrumentor. - let body = tcx.instance_mir(ty::InstanceDef::Item(non_codegenned_def_id)); + let body = tcx.instance_mir(ty::InstanceDef::Item(def_id)); let Some(function_coverage_info) = body.function_coverage_info.as_deref() else { continue; }; - debug!("generating unused fn: {:?}", non_codegenned_def_id); - cx.define_unused_fn(non_codegenned_def_id, function_coverage_info); + debug!("generating unused fn: {def_id:?}"); + let instance = declare_unused_fn(tcx, def_id); + add_unused_function_coverage(cx, instance, function_coverage_info); + } +} + +fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Instance<'tcx> { + ty::Instance::new( + def_id, + ty::GenericArgs::for_item(tcx, def_id, |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }), + ) +} + +fn add_unused_function_coverage<'tcx>( + cx: &CodegenCx<'_, 'tcx>, + instance: ty::Instance<'tcx>, + function_coverage_info: &'tcx mir::coverage::FunctionCoverageInfo, +) { + // An unused function's mappings will automatically be rewritten to map to + // zero, because none of its counters/expressions are marked as seen. + let function_coverage = FunctionCoverage::unused(instance, function_coverage_info); + + if let Some(coverage_context) = cx.coverage_context() { + coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage); + } else { + bug!("Could not get the `coverage_context`"); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 5a5f6eb89f61..cf7c7e6be60f 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -11,13 +11,12 @@ use rustc_codegen_ssa::traits::{ StaticMethods, }; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; use rustc_llvm::RustString; use rustc_middle::bug; -use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo}; +use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::Coverage; use rustc_middle::ty::layout::HasTyCtxt; -use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt}; +use rustc_middle::ty::Instance; use std::cell::RefCell; @@ -69,11 +68,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { bug!("Could not get the `coverage_context`"); } } - - fn define_unused_fn(&self, def_id: DefId, function_coverage_info: &'tcx FunctionCoverageInfo) { - let instance = declare_unused_fn(self.tcx, def_id); - add_unused_function_coverage(self, instance, function_coverage_info); - } } impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { @@ -138,35 +132,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } } -fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new( - def_id, - GenericArgs::for_item(tcx, def_id, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), - ) -} - -fn add_unused_function_coverage<'tcx>( - cx: &CodegenCx<'_, 'tcx>, - instance: Instance<'tcx>, - function_coverage_info: &'tcx FunctionCoverageInfo, -) { - // An unused function's mappings will automatically be rewritten to map to - // zero, because none of its counters/expressions are marked as seen. - let function_coverage = FunctionCoverage::unused(instance, function_coverage_info); - - if let Some(coverage_context) = cx.coverage_context() { - coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage); - } else { - bug!("Could not get the `coverage_context`"); - } -} - /// Calls llvm::createPGOFuncNameVar() with the given function instance's /// mangled function name. The LLVM API returns an llvm::GlobalVariable /// containing the function name, with the specific variable name and linkage From 6f1ca8d9ebca7960408584b3b325dca50fcb781d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 28 Sep 2023 15:37:44 +1000 Subject: [PATCH 088/107] coverage: Change query `codegened_and_inlined_items` to a plain function This query has a name that sounds general-purpose, but in fact it has coverage-specific semantics, and (fortunately) is only used by coverage code. Because it is only ever called once (from one designated CGU), it doesn't need to be a query, and we can change it to a regular function instead. --- .../src/coverageinfo/mapgen.rs | 37 +++++++++++++++++-- compiler/rustc_middle/src/query/mod.rs | 6 --- .../rustc_monomorphize/src/partitioning.rs | 31 ---------------- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 4653849a29d5..2f825b801acd 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -13,6 +13,7 @@ use rustc_middle::bug; use rustc_middle::mir; use rustc_middle::mir::coverage::CodeRegion; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefIdSet; use rustc_span::Symbol; /// Generates and exports the Coverage Map. @@ -313,8 +314,7 @@ fn save_function_record( /// `-Clink-dead-code` will not generate code for unused generic functions.) /// /// We can find the unused functions (including generic functions) by the set difference of all MIR -/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query -/// `codegened_and_inlined_items`). +/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`codegenned_and_inlined_items`). /// /// These unused functions don't need to be codegenned, but we do need to add them to the function /// coverage map (in a single designated CGU) so that we still emit coverage mappings for them. @@ -350,7 +350,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { }) .collect(); - let codegenned_def_ids = tcx.codegened_and_inlined_items(()); + let codegenned_def_ids = codegenned_and_inlined_items(tcx); // For each `DefId` that should have coverage instrumentation but wasn't // codegenned, add it to the function coverage map as an unused function. @@ -368,6 +368,37 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { } } +/// All items participating in code generation together with (instrumented) +/// items inlined into them. +fn codegenned_and_inlined_items(tcx: TyCtxt<'_>) -> DefIdSet { + let (items, cgus) = tcx.collect_and_partition_mono_items(()); + let mut visited = DefIdSet::default(); + let mut result = items.clone(); + + for cgu in cgus { + for item in cgu.items().keys() { + if let mir::mono::MonoItem::Fn(ref instance) = item { + let did = instance.def_id(); + if !visited.insert(did) { + continue; + } + let body = tcx.instance_mir(instance.def); + for block in body.basic_blocks.iter() { + for statement in &block.statements { + let mir::StatementKind::Coverage(_) = statement.kind else { continue }; + let scope = statement.source_info.scope; + if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { + result.insert(inlined.def_id()); + } + } + } + } + } + } + + result +} + fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Instance<'tcx> { ty::Instance::new( def_id, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b5f873c9257f..cd5206a837ff 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1882,12 +1882,6 @@ rustc_queries! { desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) } } - /// All items participating in code generation together with items inlined into them. - query codegened_and_inlined_items(_: ()) -> &'tcx DefIdSet { - eval_always - desc { "collecting codegened and inlined items" } - } - query codegen_unit(sym: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "getting codegen unit `{sym}`" } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 1d8cbe0e21b7..4009e2892406 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -105,7 +105,6 @@ use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; -use rustc_middle::mir; use rustc_middle::mir::mono::{ CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData, Visibility, @@ -1279,38 +1278,8 @@ fn dump_mono_items_stats<'tcx>( Ok(()) } -fn codegened_and_inlined_items(tcx: TyCtxt<'_>, (): ()) -> &DefIdSet { - let (items, cgus) = tcx.collect_and_partition_mono_items(()); - let mut visited = DefIdSet::default(); - let mut result = items.clone(); - - for cgu in cgus { - for item in cgu.items().keys() { - if let MonoItem::Fn(ref instance) = item { - let did = instance.def_id(); - if !visited.insert(did) { - continue; - } - let body = tcx.instance_mir(instance.def); - for block in body.basic_blocks.iter() { - for statement in &block.statements { - let mir::StatementKind::Coverage(_) = statement.kind else { continue }; - let scope = statement.source_info.scope; - if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { - result.insert(inlined.def_id()); - } - } - } - } - } - } - - tcx.arena.alloc(result) -} - pub fn provide(providers: &mut Providers) { providers.collect_and_partition_mono_items = collect_and_partition_mono_items; - providers.codegened_and_inlined_items = codegened_and_inlined_items; providers.is_codegened_item = |tcx, def_id| { let (all_mono_items, _) = tcx.collect_and_partition_mono_items(()); From ff02d9200ca36be1b8db857c286312f2a52d40f6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 22 Sep 2023 17:36:01 +1000 Subject: [PATCH 089/107] coverage: Simplify the injection of coverage statements --- .../src/coverage/counters.rs | 26 +-- .../rustc_mir_transform/src/coverage/mod.rs | 193 +++++++----------- .../rustc_mir_transform/src/coverage/spans.rs | 9 +- 3 files changed, 86 insertions(+), 142 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index a83ccf8fc3c2..d07f59bc72af 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -169,22 +169,22 @@ impl CoverageCounters { self.bcb_counters[bcb].as_ref() } - pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option { - self.bcb_counters[bcb].take() - } - - pub(super) fn drain_bcb_counters( - &mut self, - ) -> impl Iterator + '_ { + pub(super) fn bcb_node_counters( + &self, + ) -> impl Iterator { self.bcb_counters - .iter_enumerated_mut() - .filter_map(|(bcb, counter)| Some((bcb, counter.take()?))) + .iter_enumerated() + .filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?))) } - pub(super) fn drain_bcb_edge_counters( - &mut self, - ) -> impl Iterator + '_ { - self.bcb_edge_counters.drain() + /// For each edge in the BCB graph that has an associated counter, yields + /// that edge's *from* and *to* nodes, and its counter. + pub(super) fn bcb_edge_counters( + &self, + ) -> impl Iterator { + self.bcb_edge_counters + .iter() + .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind)) } pub(super) fn take_expressions(&mut self) -> IndexVec { diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 6fdaff6b4c02..c9b36ba25ac3 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -8,7 +8,7 @@ mod spans; mod tests; use self::counters::{BcbCounter, CoverageCounters}; -use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use self::graph::CoverageGraph; use self::spans::CoverageSpans; use crate::MirPass; @@ -104,7 +104,6 @@ struct Instrumentor<'a, 'tcx> { function_source_hash: u64, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, - mappings: Vec, } impl<'a, 'tcx> Instrumentor<'a, 'tcx> { @@ -145,7 +144,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { function_source_hash, basic_coverage_blocks, coverage_counters, - mappings: Vec::new(), } } @@ -168,148 +166,99 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); - let result = self - .coverage_counters - .make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans); + self.coverage_counters + .make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans) + .unwrap_or_else(|e| { + bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) + }); - if let Ok(()) = result { - //////////////////////////////////////////////////// - // Remove the counter or edge counter from of each coverage cpan's associated - // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR. - // - // `Coverage` statements injected from coverage spans will include the code regions - // (source code start and end positions) to be counted by the associated counter. - // - // These coverage-span-associated counters are removed from their associated - // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph` - // are indirect counters (to be injected next, without associated code regions). - self.inject_coverage_span_counters(&coverage_spans); - - //////////////////////////////////////////////////// - // For any remaining `BasicCoverageBlock` counters (that were not associated with - // any coverage span), inject `Coverage` statements (_without_ code region spans) - // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on - // are in fact counted, even though they don't directly contribute to counting - // their own independent code region's coverage. - self.inject_indirect_counters(); - }; - - if let Err(e) = result { - bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) - }; + let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans); self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: self.function_source_hash, num_counters: self.coverage_counters.num_counters(), expressions: self.coverage_counters.take_expressions(), - mappings: std::mem::take(&mut self.mappings), + mappings, })); } - /// Injects a single [`StatementKind::Coverage`] for each BCB that has one - /// or more coverage spans. - fn inject_coverage_span_counters(&mut self, coverage_spans: &CoverageSpans) { - let tcx = self.tcx; - let source_map = tcx.sess.source_map(); + /// For each [`BcbCounter`] associated with a BCB node or BCB edge, create + /// any corresponding mappings (for BCB nodes only), and inject any necessary + /// coverage statements into MIR. + fn create_mappings_and_inject_coverage_statements( + &mut self, + coverage_spans: &CoverageSpans, + ) -> Vec { + let source_map = self.tcx.sess.source_map(); let body_span = self.body_span; use rustc_session::RemapFileNameExt; let file_name = Symbol::intern(&self.source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); - for (bcb, spans) in coverage_spans.bcbs_with_coverage_spans() { - let counter_kind = self.coverage_counters.take_bcb_counter(bcb).unwrap_or_else(|| { - bug!("Every BasicCoverageBlock should have a Counter or Expression"); - }); + let mut mappings = Vec::new(); - let term = counter_kind.as_term(); - self.mappings.extend(spans.iter().map(|&span| { - let code_region = make_code_region(source_map, file_name, span, body_span); - Mapping { code_region, term } - })); + // Process the counters and spans associated with BCB nodes. + for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() { + let spans = coverage_spans.spans_for_bcb(bcb); + let has_mappings = !spans.is_empty(); - inject_statement( - self.mir_body, - self.make_mir_coverage_kind(&counter_kind), - self.bcb_leader_bb(bcb), - ); - } - } + // If this BCB has any coverage spans, add corresponding mappings to + // the mappings table. + if has_mappings { + let term = counter_kind.as_term(); + mappings.extend(spans.iter().map(|&span| { + let code_region = make_code_region(source_map, file_name, span, body_span); + Mapping { code_region, term } + })); + } - /// At this point, any BCB with coverage counters has already had its counter injected - /// into MIR, and had its counter removed from `coverage_counters` (via `take_counter()`). - /// - /// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not - /// associated with a coverage span, should only exist if the counter is an `Expression` - /// dependency (one of the expression operands). Collect them, and inject the additional - /// counters into the MIR, without a reportable coverage span. - fn inject_indirect_counters(&mut self) { - let mut bcb_counters_without_direct_coverage_spans = Vec::new(); - for (target_bcb, counter_kind) in self.coverage_counters.drain_bcb_counters() { - bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind)); - } - for ((from_bcb, target_bcb), counter_kind) in - self.coverage_counters.drain_bcb_edge_counters() - { - bcb_counters_without_direct_coverage_spans.push(( - Some(from_bcb), - target_bcb, - counter_kind, - )); - } - - for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans - { - match counter_kind { - BcbCounter::Counter { .. } => { - let inject_to_bb = if let Some(from_bcb) = edge_from_bcb { - // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in - // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the - // `target_bcb`; also called the `leader_bb`). - let from_bb = self.bcb_last_bb(from_bcb); - let to_bb = self.bcb_leader_bb(target_bcb); - - let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); - debug!( - "Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \ - BasicBlock {:?}, for unclaimed edge counter {:?}", - edge_from_bcb, from_bb, target_bcb, to_bb, new_bb, counter_kind, - ); - new_bb - } else { - let target_bb = self.bcb_last_bb(target_bcb); - debug!( - "{:?} ({:?}) gets a new Coverage statement for unclaimed counter {:?}", - target_bcb, target_bb, counter_kind, - ); - target_bb - }; - - inject_statement( - self.mir_body, - self.make_mir_coverage_kind(&counter_kind), - inject_to_bb, - ); - } - // Experessions with no associated spans don't need to inject a statement. - BcbCounter::Expression { .. } => {} + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // The only purpose of expression-used statements is to detect + // when a mapping is unreachable, so we only inject them for + // expressions with one or more mappings. + BcbCounter::Expression { .. } => has_mappings, + }; + if do_inject { + inject_statement( + self.mir_body, + self.make_mir_coverage_kind(counter_kind), + self.basic_coverage_blocks[bcb].leader_bb(), + ); } } - } - #[inline] - fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { - self.bcb_data(bcb).leader_bb() - } + // Process the counters associated with BCB edges. + for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() { + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // BCB-edge expressions never have mappings, so they never need + // a corresponding statement. + BcbCounter::Expression { .. } => false, + }; + if !do_inject { + continue; + } - #[inline] - fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { - self.bcb_data(bcb).last_bb() - } + // We need to inject a coverage statement into a new BB between the + // last BB of `from_bcb` and the first BB of `to_bcb`. + let from_bb = self.basic_coverage_blocks[from_bcb].last_bb(); + let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb(); - #[inline] - fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData { - &self.basic_coverage_blocks[bcb] + let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); + debug!( + "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ + requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}", + ); + + // Inject a counter into the newly-created BB. + inject_statement(self.mir_body, self.make_mir_coverage_kind(&counter_kind), new_bb); + } + + mappings } fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 3f7ba5725104..dde16cbd782e 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -41,13 +41,8 @@ impl CoverageSpans { !self.bcb_to_spans[bcb].is_empty() } - pub(super) fn bcbs_with_coverage_spans( - &self, - ) -> impl Iterator { - self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| { - // Only yield BCBs that have at least one coverage span. - (!spans.is_empty()).then_some((bcb, spans.as_slice())) - }) + pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] { + &self.bcb_to_spans[bcb] } } From ccc4638d734c745a5ec16fdcce33aac4e8c3b1c0 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sat, 21 Oct 2023 13:16:09 +0200 Subject: [PATCH 090/107] fix spans for removing `.await` on `for` expressions --- .../src/traits/error_reporting/suggestions.rs | 2 +- tests/ui/async-await/unnecessary-await.rs | 5 +++++ tests/ui/async-await/unnecessary-await.stderr | 15 ++++++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 12a88ac32392..78b466907b32 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1644,7 +1644,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter` if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1) - && let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span) + && let Some(expr_span) = expr.span.find_ancestor_inside_same_ctxt(await_expr.span) { let removal_span = self .tcx diff --git a/tests/ui/async-await/unnecessary-await.rs b/tests/ui/async-await/unnecessary-await.rs index cd1e28714322..93b68f018e4c 100644 --- a/tests/ui/async-await/unnecessary-await.rs +++ b/tests/ui/async-await/unnecessary-await.rs @@ -31,4 +31,9 @@ async fn with_macros() { f!(()); } +// Regression test for issue #117014. +async fn desugaring_span_ctxt() { + for x in [] {}.await //~ ERROR `()` is not a future +} + fn main() {} diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr index 9a2a035b2dd0..620370a6113a 100644 --- a/tests/ui/async-await/unnecessary-await.stderr +++ b/tests/ui/async-await/unnecessary-await.stderr @@ -49,6 +49,19 @@ LL | f!(()); = note: required for `()` to implement `IntoFuture` = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0277]: `()` is not a future + --> $DIR/unnecessary-await.rs:36:20 + | +LL | for x in [] {}.await + | -^^^^^ + | || + | |`()` is not a future + | help: remove the `.await` + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required for `()` to implement `IntoFuture` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. From 2f74b68617793eff1db966949d3187b831f2c933 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Oct 2023 11:30:57 +0000 Subject: [PATCH 091/107] Rustup to rustc 1.75.0-nightly (249624b50 2023-10-20) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 8d6188f8dc42..3735ac1c17b1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-19" +channel = "nightly-2023-10-21" components = ["rust-src", "rustc-dev", "llvm-tools"] From a585cda701581a16894858dc088eacd5a02fc78b Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 21 Oct 2023 13:41:57 +0200 Subject: [PATCH 092/107] Bump nightly version -> 2023-10-21 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index fe2c77ab47f0..7c5b5e97a5c7 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-06" +channel = "nightly-2023-10-21" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From b8b55fe316e24db2c124207429c79ef0ccf41218 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 21 Oct 2023 14:16:27 +0200 Subject: [PATCH 093/107] Update Cargo.lock (ui_test update) --- Cargo.lock | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 232c9c9441fb..dd9e8fffca51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -564,7 +564,7 @@ dependencies = [ "tester", "tokio", "toml 0.7.5", - "ui_test 0.20.0", + "ui_test", "walkdir", ] @@ -614,6 +614,7 @@ dependencies = [ "if_chain", "itertools", "rustc-semver", + "serde", ] [[package]] @@ -2511,7 +2512,7 @@ dependencies = [ "rustc_version", "serde", "smallvec", - "ui_test 0.21.2", + "ui_test", ] [[package]] @@ -5740,33 +5741,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" -[[package]] -name = "ui_test" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd8fb9b15c8332cf51bfc2dc4830063b2446a9c9d732421b56f2478024a3971" -dependencies = [ - "annotate-snippets", - "anyhow", - "bstr", - "cargo-platform", - "cargo_metadata 0.15.4", - "color-eyre", - "colored", - "comma", - "crossbeam-channel", - "indicatif", - "lazy_static", - "levenshtein", - "prettydiff", - "regex", - "rustc_version", - "rustfix", - "serde", - "serde_json", - "tempfile", -] - [[package]] name = "ui_test" version = "0.21.2" From 31daed1b64352348498302154740eb64c485047a Mon Sep 17 00:00:00 2001 From: dirreke Date: Sat, 21 Oct 2023 23:42:09 +0800 Subject: [PATCH 094/107] update the registers of csky --- compiler/rustc_target/src/asm/csky.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs index 6f0e7f799495..db3d8106040b 100644 --- a/compiler/rustc_target/src/asm/csky.rs +++ b/compiler/rustc_target/src/asm/csky.rs @@ -64,9 +64,9 @@ def_regs! { r20: reg = ["r20","t4"],// feature high-register r21: reg = ["r21","t5"],// feature high-register r22: reg = ["r22","t6"],// feature high-register - r23: reg = ["r23","t7", "fp"],// feature high-register - r24: reg = ["r24","t8", "sop"],// feature high-register - r25: reg = ["r25","t9","tp", "bsp"],// feature high-register + r23: reg = ["r23","t7"],// feature high-register + r24: reg = ["r24","t8"],// feature high-register + r25: reg = ["r25","t9"],// feature high-register f0: freg = ["fr0","vr0"], f1: freg = ["fr1","vr1"], f2: freg = ["fr2","vr2"], From 2cca4357173901107770472a24f211cff3f47ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 20:03:44 +0000 Subject: [PATCH 095/107] Mention the syntax for `use` on `mod foo;` if `foo` doesn't exist Newcomers might get confused that `mod` is the only way of defining scopes, and that it can be used as if it were `use`. Fix #69492. --- compiler/rustc_expand/messages.ftl | 1 + compiler/rustc_expand/src/errors.rs | 1 + tests/run-make/unknown-mod-stdin/unknown-mod.stderr | 1 + tests/ui/error-codes/E0583.stderr | 1 + .../invalid-module-declaration.stderr | 1 + tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr | 1 + .../missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr | 1 + tests/ui/modules/special_module_name.stderr | 2 ++ tests/ui/parser/mod_file_not_exist.stderr | 1 + tests/ui/parser/mod_file_not_exist_windows.stderr | 1 + tests/ui/parser/unsafe-mod.stderr | 1 + .../mod_file_nonascii_forbidden.stderr | 1 + 12 files changed, 13 insertions(+) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 6c7e68246ea5..8b93829623db 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -86,6 +86,7 @@ expand_module_circular = expand_module_file_not_found = file not found for module `{$name}` .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}" + .note = if there is a `mod {$name}` elsewhere in the crate already, import it with `use crate::...` instead expand_module_in_block = cannot declare a non-inline module inside a block unless it has a path attribute diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index e3a0ae3570eb..d86632c47fc5 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -350,6 +350,7 @@ pub(crate) struct ModuleInBlockName { #[derive(Diagnostic)] #[diag(expand_module_file_not_found, code = "E0583")] #[help] +#[note] pub(crate) struct ModuleFileNotFound { #[primary_span] pub span: Span, diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr index d7258fe4f68d..81ff83938378 100644 --- a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr +++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr @@ -5,6 +5,7 @@ error[E0583]: file not found for module `unknown` | ^^^^^^^^^^^^ | = help: to create the module `unknown`, create file "unknown.rs" or "unknown/mod.rs" + = note: if there is a `mod unknown` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/error-codes/E0583.stderr b/tests/ui/error-codes/E0583.stderr index c7bbbf114997..6707f2864f23 100644 --- a/tests/ui/error-codes/E0583.stderr +++ b/tests/ui/error-codes/E0583.stderr @@ -5,6 +5,7 @@ LL | mod module_that_doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" or "$DIR/module_that_doesnt_exist/mod.rs" + = note: if there is a `mod module_that_doesnt_exist` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr index 7bc8efd7e4a9..08aec25928c0 100644 --- a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -5,6 +5,7 @@ LL | pub mod baz; | ^^^^^^^^^^^^ | = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs" + = note: if there is a `mod baz` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index 31e4206a5463..5f4d19439acc 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -5,6 +5,7 @@ LL | mod missing; | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo/missing.rs" or "$DIR/foo/missing/mod.rs" + = note: if there is a `mod missing` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr index 9d252398b7a1..d5f5ea870597 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -5,6 +5,7 @@ LL | mod missing; | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" or "$DIR/foo_inline/inline/missing/mod.rs" + = note: if there is a `mod missing` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/modules/special_module_name.stderr b/tests/ui/modules/special_module_name.stderr index bc4b4f1b3181..84473bf8c0bc 100644 --- a/tests/ui/modules/special_module_name.stderr +++ b/tests/ui/modules/special_module_name.stderr @@ -5,6 +5,7 @@ LL | mod lib; | ^^^^^^^^ | = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs" + = note: if there is a `mod lib` elsewhere in the crate already, import it with `use crate::...` instead error[E0583]: file not found for module `main` --> $DIR/special_module_name.rs:4:1 @@ -13,6 +14,7 @@ LL | mod main; | ^^^^^^^^^ | = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs" + = note: if there is a `mod main` elsewhere in the crate already, import it with `use crate::...` instead warning: found module declaration for lib.rs --> $DIR/special_module_name.rs:1:1 diff --git a/tests/ui/parser/mod_file_not_exist.stderr b/tests/ui/parser/mod_file_not_exist.stderr index 62456d518804..c2f9d30d9ec4 100644 --- a/tests/ui/parser/mod_file_not_exist.stderr +++ b/tests/ui/parser/mod_file_not_exist.stderr @@ -5,6 +5,7 @@ LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs" + = note: if there is a `mod not_a_real_file` elsewhere in the crate already, import it with `use crate::...` instead error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 diff --git a/tests/ui/parser/mod_file_not_exist_windows.stderr b/tests/ui/parser/mod_file_not_exist_windows.stderr index d5143dbe982a..53b09d8ca53a 100644 --- a/tests/ui/parser/mod_file_not_exist_windows.stderr +++ b/tests/ui/parser/mod_file_not_exist_windows.stderr @@ -5,6 +5,7 @@ LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs" + = note: if there is a `mod not_a_real_file` elsewhere in the crate already, import it with `use crate::...` instead error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist_windows.rs:7:16 diff --git a/tests/ui/parser/unsafe-mod.stderr b/tests/ui/parser/unsafe-mod.stderr index dac6e7a35505..fbe24aa10da4 100644 --- a/tests/ui/parser/unsafe-mod.stderr +++ b/tests/ui/parser/unsafe-mod.stderr @@ -5,6 +5,7 @@ LL | unsafe mod n; | ^^^^^^^^^^^^^ | = help: to create the module `n`, create file "$DIR/n.rs" or "$DIR/n/mod.rs" + = note: if there is a `mod n` elsewhere in the crate already, import it with `use crate::...` instead error: module cannot be declared unsafe --> $DIR/unsafe-mod.rs:1:1 diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr index 7639ae9f6a4f..8ca6a37c6251 100644 --- a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr @@ -5,6 +5,7 @@ LL | mod řųśť; | ^^^^^^^^^ | = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs" + = note: if there is a `mod řųśť` elsewhere in the crate already, import it with `use crate::...` instead error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name --> $DIR/mod_file_nonascii_forbidden.rs:1:5 From 04a3850317ba03dc6188c1e9cf96cd10af2c4d35 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:20:27 +0000 Subject: [PATCH 096/107] Run tests for riscv64 --- .github/workflows/main.yml | 10 +++++++++- build_system/utils.rs | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 652d6eca3f6e..47d9a3b93f72 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,10 +50,12 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - # s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default - os: ubuntu-latest env: TARGET_TRIPLE: s390x-unknown-linux-gnu + - os: ubuntu-latest + env: + TARGET_TRIPLE: riscv64gc-unknown-linux-gnu - os: windows-latest env: TARGET_TRIPLE: x86_64-pc-windows-msvc @@ -92,6 +94,12 @@ jobs: sudo apt-get update sudo apt-get install -y gcc-s390x-linux-gnu qemu-user + - name: Install riscv64gc toolchain and qemu + if: matrix.env.TARGET_TRIPLE == 'riscv64gc-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-riscv64-linux-gnu qemu-user + - name: Prepare dependencies run: ./y.sh prepare diff --git a/build_system/utils.rs b/build_system/utils.rs index 9f24c043a504..149f1618f5c0 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -42,6 +42,16 @@ impl Compiler { "/usr/s390x-linux-gnu".to_owned(), ]; } + "riscv64gc-unknown-linux-gnu" => { + // We are cross-compiling for riscv64. Use the correct linker and run tests in qemu. + self.rustflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned()); + self.rustdocflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned()); + self.runner = vec![ + "qemu-riscv64".to_owned(), + "-L".to_owned(), + "/usr/riscv64-linux-gnu".to_owned(), + ]; + } "x86_64-pc-windows-gnu" => { // We are cross-compiling for Windows. Run tests in wine. self.runner = vec!["wine".to_owned()]; From 453ce49a6f56fce01603696c90ab301f97219fc1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 8 Oct 2023 16:55:10 +0000 Subject: [PATCH 097/107] Support inline asm on riscv64 --- src/inline_asm.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index dd2127d554dd..59a458b11a22 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -745,6 +745,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it generated_asm.push_str(" mov x19, x0\n"); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" addi sp, sp, -16\n"); + generated_asm.push_str(" sd ra, 8(sp)\n"); + generated_asm.push_str(" sd s1, 0(sp)\n"); // s1 is callee saved + // s1/x9 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it + generated_asm.push_str(" mv s1, a0\n"); + } _ => unimplemented!("prologue for {:?}", arch), } } @@ -761,6 +768,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(" ldp fp, lr, [sp], #32\n"); generated_asm.push_str(" ret\n"); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ld s1, 0(sp)\n"); + generated_asm.push_str(" ld ra, 8(sp)\n"); + generated_asm.push_str(" addi sp, sp, 16\n"); + generated_asm.push_str(" ret\n"); + } _ => unimplemented!("epilogue for {:?}", arch), } } @@ -773,6 +786,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { InlineAsmArch::AArch64 => { generated_asm.push_str(" brk #0x1"); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ebreak\n"); + } _ => unimplemented!("epilogue_noreturn for {:?}", arch), } } @@ -794,6 +810,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" sd "); + reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap(); + } _ => unimplemented!("save_register for {:?}", arch), } } @@ -815,6 +836,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ld "); + reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap(); + } _ => unimplemented!("restore_register for {:?}", arch), } } From 46388c17021e7146151255af671211934709bbf9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Oct 2023 16:33:33 +0000 Subject: [PATCH 098/107] Re-enable all inline asm usage for the rustc tests --- scripts/setup_rust_fork.sh | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 60ac6bc9951e..6bcf56abb950 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -13,23 +13,6 @@ git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ am ../patches/*-stdlib-*.patch -git apply - < config.toml < Date: Sat, 21 Oct 2023 16:34:57 +0000 Subject: [PATCH 099/107] Introduce asm_supported() helper --- src/global_asm.rs | 8 +++++--- src/inline_asm.rs | 11 ++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/global_asm.rs b/src/global_asm.rs index ebd9b728d90b..6692d1b85eac 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -81,6 +81,10 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, } } +pub(crate) fn asm_supported(tcx: TyCtxt<'_>) -> bool { + cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows +} + #[derive(Debug)] pub(crate) struct GlobalAsmConfig { asm_enabled: bool, @@ -90,10 +94,8 @@ pub(crate) struct GlobalAsmConfig { impl GlobalAsmConfig { pub(crate) fn new(tcx: TyCtxt<'_>) -> Self { - let asm_enabled = cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows; - GlobalAsmConfig { - asm_enabled, + asm_enabled: asm_supported(tcx), assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"), output_filenames: tcx.output_filenames(()).clone(), } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 59a458b11a22..8e340cf91ae3 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -8,6 +8,7 @@ use rustc_span::sym; use rustc_target::asm::*; use target_lexicon::BinaryFormat; +use crate::global_asm::asm_supported; use crate::prelude::*; enum CInlineAsmOperand<'tcx> { @@ -44,9 +45,13 @@ pub(crate) fn codegen_inline_asm<'tcx>( ) { // FIXME add .eh_frame unwind info directives - if !template.is_empty() - && (cfg!(not(feature = "inline_asm")) || fx.tcx.sess.target.is_like_windows) - { + if !asm_supported(fx.tcx) { + if template.is_empty() { + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; + } + // Used by panic_abort if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { fx.bcx.ins().trap(TrapCode::User(1)); From eb30083b6952f1564725c8027a4a63ad3f00d79c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Oct 2023 16:39:23 +0000 Subject: [PATCH 100/107] Fix epilogue_noreturn for AArch64 --- src/inline_asm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 8e340cf91ae3..75d7f2e5c548 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -789,7 +789,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(" ud2\n"); } InlineAsmArch::AArch64 => { - generated_asm.push_str(" brk #0x1"); + generated_asm.push_str(" brk #0x1\n"); } InlineAsmArch::RiscV64 => { generated_asm.push_str(" ebreak\n"); From 78cd77f1f129ec6d217d6bf80a7a4ff0299e54d8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Oct 2023 16:39:54 +0000 Subject: [PATCH 101/107] Give better error for unsupported asm!() --- src/inline_asm.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 75d7f2e5c548..d809fd4bb15f 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -228,6 +228,16 @@ pub(crate) fn codegen_inline_asm<'tcx>( fx.bcx.ins().jump(destination_block, &[]); return; } + + if cfg!(not(feature = "inline_asm")) { + fx.tcx.sess.span_err( + span, + "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift", + ); + } else { + fx.tcx.sess.span_err(span, "asm! and global_asm! are not yet supported on Windows"); + } + return; } let operands = operands From 1848d25a8340e60efe9b4b7797b00b156f89a2b1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Oct 2023 16:52:09 +0000 Subject: [PATCH 102/107] Add shim for core::hint::spin_loop() on riscv64 --- src/inline_asm.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index d809fd4bb15f..ed0772342548 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -149,6 +149,16 @@ pub(crate) fn codegen_inline_asm<'tcx>( return; } + // Used by core::hint::spin_loop() + if template[0] + == InlineAsmTemplatePiece::String(".insn i 0x0F, 0, x0, x0, 0x010".to_string()) + && template.len() == 1 + { + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; + } + // Used by measureme if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string()) && template[1] == InlineAsmTemplatePiece::String("\n".to_string()) From af871808459c84ba9e39aff0fb75a632cd8fb927 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Sat, 21 Oct 2023 10:53:35 -0700 Subject: [PATCH 103/107] fix broken link to ayu theme in the rustdoc book --- src/doc/rustdoc/src/write-documentation/what-to-include.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/write-documentation/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md index 16457ed0ff82..4bcae4d222c7 100644 --- a/src/doc/rustdoc/src/write-documentation/what-to-include.md +++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md @@ -117,7 +117,7 @@ rustdoc --theme awesome.css src/lib.rs Here is an example of a new theme, [Ayu]. -[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/themes/ayu.css +[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/rustdoc.css#L2384-L2574 [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden [Documentation tests]: documentation-tests.md [on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme From 695beca219e795cae47dfeddb836c234ebadd551 Mon Sep 17 00:00:00 2001 From: Gimbles Date: Sat, 21 Oct 2023 23:41:32 +0530 Subject: [PATCH 104/107] Update boxed.rs --- library/alloc/src/boxed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 8ab851a0ea64..4a62013c685f 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -207,7 +207,7 @@ impl Box { /// ``` /// let five = Box::new(5); /// ``` - #[cfg(all(not(no_global_oom_handling)))] + #[cfg(not(no_global_oom_handling))] #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] From c07d1e2f88cb3b1a0604ae8f18b478c1aeb7a7fa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:01:08 +0000 Subject: [PATCH 105/107] Use same --remap-path-prefix as bootstrap for testing the rustc test suite This allows removing the CFG_VIRTUAL_RUST_SOURCE_BASE_DIR hack and re-enabling a fair amount of tests. --- build_system/build_sysroot.rs | 9 +++++++++ scripts/setup_rust_fork.sh | 7 ++++--- scripts/test_rustc_tests.sh | 14 -------------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 31a4b209826f..1ed896c6bf0e 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -1,3 +1,4 @@ +use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; @@ -259,6 +260,14 @@ fn build_clif_sysroot_for_triple( // inlining. rustflags.push("-Zinline-mir".to_owned()); } + if let Some(prefix) = env::var_os("CG_CLIF_STDLIB_REMAP_PATH_PREFIX") { + rustflags.push("--remap-path-prefix".to_owned()); + rustflags.push(format!( + "{}={}", + STDLIB_SRC.to_path(dirs).to_str().unwrap(), + prefix.to_str().unwrap() + )); + } compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); maybe_incremental(&mut build_cmd); diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 6bcf56abb950..3e48fb006dea 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash set -e -./y.sh build +# Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX. +# CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass +# --remap-path-prefix to handle this. +CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build echo "[SETUP] Rust fork" git clone https://github.com/rust-lang/rust.git || true @@ -32,8 +35,6 @@ verbose-tests = false EOF popd -export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build/stdlib; pwd)" - # Allow the testsuite to use llvm tools host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin" diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 738701c6409c..b485f2571cc7 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -111,20 +111,6 @@ rm tests/ui/consts/issue-33537.rs # same rm tests/ui/layout/valid_range_oob.rs # different ICE message rm tests/ui/const-generics/generic_const_exprs/issue-80742.rs # gives error instead of ICE with cg_clif -rm tests/ui/consts/issue-miri-1910.rs # different error message -rm tests/ui/consts/offset_ub.rs # same -rm tests/ui/consts/const-eval/ub-slice-get-unchecked.rs # same -rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same -rm tests/ui/lint/lint-const-item-mutation.rs # same -rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same -rm tests/ui/suggestions/derive-trait-for-method-call.rs # same -rm tests/ui/typeck/issue-46112.rs # same -rm tests/ui/consts/const_cmp_type_id.rs # same -rm tests/ui/consts/issue-73976-monomorphic.rs # same -rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same -rm tests/ui/consts/issue-94675.rs # same -rm tests/ui/associated-types/issue-85103-layout-debug.rs # same - # rustdoc-clif passes extra args, suppressing the help message when no args are passed rm -r tests/run-make/issue-88756-default-output From 193fec640dfaeee507cf13f677dbcda42b98374a Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Sun, 22 Oct 2023 05:29:24 +0000 Subject: [PATCH 106/107] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index bc3882bcf2b0..0335ad3c1d87 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -249624b5043013d18c00f0401ca431c1a6baa8cd +9e3f784eb2c7c847b6c3578b373c0e0bc9233ca3 From 8cbac823d016c1afb3c24e3d87c2896566a7d5d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Oct 2023 08:40:37 +0200 Subject: [PATCH 107/107] clippy --- src/tools/miri/src/shims/backtrace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 08b26f5fe854..48dafc40c621 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let flags = if let Some(flags_op) = args.get(0) { + let flags = if let Some(flags_op) = args.first() { this.read_scalar(flags_op)?.to_u64()? } else { throw_ub_format!("expected at least 1 argument")