diff --git a/Cargo.toml b/Cargo.toml index 7bfb3fca..e75ac976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,93 @@ lazy_static = "1.4" # prefer https://doc.rust-lang.org/std/sync/struct.OnceLock. num-derive = "0.4" num-traits = "0.2" +[workspace.lints.rust] +# Safer unsafe +unsafe_op_in_unsafe_fn = "warn" +invalid_reference_casting = "warn" +pointer_structural_match = "warn" +# Correctness +unused_tuple_struct_fields = "warn" +# Style, readability +# https://quinedot.github.io/rust-learning/dont-hide.htm +elided_lifetimes_in_paths = "warn" +absolute_paths_not_starting_with_crate = "warn" +single_use_lifetimes = "warn" +unreachable_pub = "warn" +unused_lifetimes = "warn" +unused_qualifications = "warn" +keyword_idents = "warn" +noop_method_call = "warn" +# TODO: NOTE(@CBenoit): we probably want to ensure this in core tier crates only +# missing_docs = "warn" +# Compile-time / optimization +unused_crate_dependencies = "warn" +unused_macro_rules = "warn" + +[workspace.lints.clippy] +# Safer unsafe +undocumented_unsafe_blocks = "warn" +# FIXME: https://github.com/rust-lang/rust-clippy/issues/11312 (fixed for 1.75.0) +# multiple_unsafe_ops_per_block = "warn" +transmute_ptr_to_ptr = "warn" +as_ptr_cast_mut = "warn" +cast_ptr_alignment = "warn" +fn_to_numeric_cast_any = "warn" +ptr_cast_constness = "warn" +# Correctness +arithmetic_side_effects = "warn" +cast_lossless = "warn" +cast_possible_truncation = "warn" +cast_possible_wrap = "warn" +cast_sign_loss = "warn" +float_cmp = "warn" +as_underscore = "warn" +# TODO: let’s either handle `None`, `Err` or use `expect` to give a reason +# unwrap_used = "warn" +large_stack_frames = "warn" +# Style, readability +# with semicolon-outside-block-ignore-multiline = true +semicolon_outside_block = "warn" +clone_on_ref_ptr = "warn" +cloned_instead_of_copied = "warn" +trait_duplication_in_bounds = "warn" +type_repetition_in_bounds = "warn" +checked_conversions = "warn" +get_unwrap = "warn" +# TODO: reduce risk of confusing similar names together, and protects against +# typos when variable shadowing was intended +# similar_names = "warn" +str_to_string = "warn" +string_to_string = "warn" +# TODO: std_instead_of_alloc = "warn" +# TODO: std_instead_of_core = "warn" +separated_literal_suffix = "warn" +unused_self = "warn" +# TODO: use_self = "warn" # NOTE(@CBenoit): not sure about that one +useless_let_if_seq = "warn" +# TODO: partial_pub_fields = "warn" +string_add = "warn" +range_plus_one = "warn" +# Compile-time / optimization +inline_always = "warn" +or_fun_call = "warn" +unnecessary_box_returns = "warn" +# Extra-pedantic clippy +collection_is_never_read = "warn" +copy_iterator = "warn" +expl_impl_clone_on_copy = "warn" +implicit_clone = "warn" +large_types_passed_by_value = "warn" +redundant_clone = "warn" +alloc_instead_of_core = "warn" +empty_drop = "warn" +return_self_not_must_use = "warn" +wildcard_dependencies = "warn" +# Let’s not merge unintended eprint!/print! statements in libraries +print_stderr = "warn" +print_stdout = "warn" +dbg_macro = "warn" + [profile.dev] opt-level = 1 diff --git a/clippy.toml b/clippy.toml index 2ded6b07..7a0e8bd2 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,3 +1,4 @@ +msrv = "1.75" semicolon-outside-block-ignore-multiline = true accept-comment-above-statement = true accept-comment-above-attributes = true diff --git a/crates/ironrdp-acceptor/Cargo.toml b/crates/ironrdp-acceptor/Cargo.toml index 0b975bf3..6056c337 100644 --- a/crates/ironrdp-acceptor/Cargo.toml +++ b/crates/ironrdp-acceptor/Cargo.toml @@ -21,3 +21,7 @@ ironrdp-svc.workspace = true ironrdp-connector.workspace = true ironrdp-async.workspace = true tracing.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-ainput/Cargo.toml b/crates/ironrdp-ainput/Cargo.toml index 6ef58e3e..2d1e5fd3 100644 --- a/crates/ironrdp-ainput/Cargo.toml +++ b/crates/ironrdp-ainput/Cargo.toml @@ -22,3 +22,7 @@ bitflags.workspace = true num-derive.workspace = true # TODO: remove num-traits.workspace = true # TODO: remove + +[lints] +workspace = true + diff --git a/crates/ironrdp-async/Cargo.toml b/crates/ironrdp-async/Cargo.toml index f600fff6..97830b33 100644 --- a/crates/ironrdp-async/Cargo.toml +++ b/crates/ironrdp-async/Cargo.toml @@ -21,3 +21,7 @@ ironrdp-connector.workspace = true ironrdp-pdu.workspace = true # ironrdp-session.workspace = true tracing.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-blocking/Cargo.toml b/crates/ironrdp-blocking/Cargo.toml index f3df8478..bfe9b529 100644 --- a/crates/ironrdp-blocking/Cargo.toml +++ b/crates/ironrdp-blocking/Cargo.toml @@ -21,3 +21,7 @@ ironrdp-connector.workspace = true ironrdp-pdu.workspace = true # ironrdp-session.workspace = true tracing.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-client-glutin/Cargo.toml b/crates/ironrdp-client-glutin/Cargo.toml index cf5cb307..062600cf 100644 --- a/crates/ironrdp-client-glutin/Cargo.toml +++ b/crates/ironrdp-client-glutin/Cargo.toml @@ -43,3 +43,7 @@ anyhow = "1.0" # GUI glutin = "0.29" ironrdp-glutin-renderer = { path = "../glutin-renderer"} + +[lints] +workspace = true + diff --git a/crates/ironrdp-client/Cargo.toml b/crates/ironrdp-client/Cargo.toml index cec2fd25..dd2f030b 100644 --- a/crates/ironrdp-client/Cargo.toml +++ b/crates/ironrdp-client/Cargo.toml @@ -64,3 +64,7 @@ url = "2.5" windows = { version = "0.48", features = [ "Win32_Foundation", ] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-cliprdr-format/Cargo.toml b/crates/ironrdp-cliprdr-format/Cargo.toml index b52475fe..646c9164 100644 --- a/crates/ironrdp-cliprdr-format/Cargo.toml +++ b/crates/ironrdp-cliprdr-format/Cargo.toml @@ -20,3 +20,7 @@ test = false ironrdp-pdu.workspace = true thiserror.workspace = true png = "0.17" + +[lints] +workspace = true + diff --git a/crates/ironrdp-cliprdr-native/Cargo.toml b/crates/ironrdp-cliprdr-native/Cargo.toml index 1db43fd3..41404092 100644 --- a/crates/ironrdp-cliprdr-native/Cargo.toml +++ b/crates/ironrdp-cliprdr-native/Cargo.toml @@ -30,3 +30,7 @@ windows = { version = "0.48", features = [ "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging" ] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-cliprdr/Cargo.toml b/crates/ironrdp-cliprdr/Cargo.toml index 7a4334a3..66e8336a 100644 --- a/crates/ironrdp-cliprdr/Cargo.toml +++ b/crates/ironrdp-cliprdr/Cargo.toml @@ -22,3 +22,7 @@ ironrdp-svc.workspace = true thiserror.workspace = true tracing.workspace = true bitflags.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-connector/Cargo.toml b/crates/ironrdp-connector/Cargo.toml index eddec3bf..05e9a517 100644 --- a/crates/ironrdp-connector/Cargo.toml +++ b/crates/ironrdp-connector/Cargo.toml @@ -33,3 +33,7 @@ url = "2.5" # NOTE: can be removed after #260 is merged [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["std"] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-displaycontrol/Cargo.toml b/crates/ironrdp-displaycontrol/Cargo.toml index d3ee97ce..7b25e84e 100644 --- a/crates/ironrdp-displaycontrol/Cargo.toml +++ b/crates/ironrdp-displaycontrol/Cargo.toml @@ -16,3 +16,7 @@ ironrdp-dvc.workspace = true ironrdp-pdu.workspace = true ironrdp-svc.workspace = true tracing.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-dvc/Cargo.toml b/crates/ironrdp-dvc/Cargo.toml index e25cabcb..4286b052 100644 --- a/crates/ironrdp-dvc/Cargo.toml +++ b/crates/ironrdp-dvc/Cargo.toml @@ -24,3 +24,7 @@ ironrdp-svc.workspace = true ironrdp-pdu = { workspace = true, features = ["alloc"] } tracing.workspace = true slab = "0.4" + +[lints] +workspace = true + diff --git a/crates/ironrdp-error/Cargo.toml b/crates/ironrdp-error/Cargo.toml index d1fe1905..1ed226f2 100644 --- a/crates/ironrdp-error/Cargo.toml +++ b/crates/ironrdp-error/Cargo.toml @@ -19,3 +19,7 @@ test = false default = [] std = ["alloc"] alloc = [] + +[lints] +workspace = true + diff --git a/crates/ironrdp-futures/Cargo.toml b/crates/ironrdp-futures/Cargo.toml index a5095084..4f18ce0b 100644 --- a/crates/ironrdp-futures/Cargo.toml +++ b/crates/ironrdp-futures/Cargo.toml @@ -19,3 +19,7 @@ test = false bytes = "1" futures-util = { version = "0.3", features = ["io"] } ironrdp-async.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-fuzzing/Cargo.toml b/crates/ironrdp-fuzzing/Cargo.toml index b9fe5008..b80b5ce8 100644 --- a/crates/ironrdp-fuzzing/Cargo.toml +++ b/crates/ironrdp-fuzzing/Cargo.toml @@ -19,3 +19,7 @@ ironrdp-rdpsnd.workspace = true ironrdp-cliprdr-format.workspace = true ironrdp-displaycontrol.workspace = true ironrdp-svc.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-glutin-renderer/Cargo.toml b/crates/ironrdp-glutin-renderer/Cargo.toml index 15aec672..d418a342 100644 --- a/crates/ironrdp-glutin-renderer/Cargo.toml +++ b/crates/ironrdp-glutin-renderer/Cargo.toml @@ -18,3 +18,7 @@ thiserror.workspace = true glow = "0.12" glutin = { version = "0.29" } openh264 = { version = "0.4" } + +[lints] +workspace = true + diff --git a/crates/ironrdp-graphics/Cargo.toml b/crates/ironrdp-graphics/Cargo.toml index 2f9657cc..3a127033 100644 --- a/crates/ironrdp-graphics/Cargo.toml +++ b/crates/ironrdp-graphics/Cargo.toml @@ -30,3 +30,7 @@ thiserror.workspace = true [dev-dependencies] bmp = "0.5" expect-test.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-input/Cargo.toml b/crates/ironrdp-input/Cargo.toml index 4ea45dd8..b2d474fd 100644 --- a/crates/ironrdp-input/Cargo.toml +++ b/crates/ironrdp-input/Cargo.toml @@ -19,3 +19,7 @@ test = false ironrdp-pdu.workspace = true bitvec = "1.0" smallvec = "1.13" + +[lints] +workspace = true + diff --git a/crates/ironrdp-pdu-generators/Cargo.toml b/crates/ironrdp-pdu-generators/Cargo.toml index 714331c0..d5b178dd 100644 --- a/crates/ironrdp-pdu-generators/Cargo.toml +++ b/crates/ironrdp-pdu-generators/Cargo.toml @@ -12,3 +12,7 @@ test = false [dependencies] # ironrdp-pdu.workspace = true # proptest.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-pdu/Cargo.toml b/crates/ironrdp-pdu/Cargo.toml index 384e7df1..debd3c22 100644 --- a/crates/ironrdp-pdu/Cargo.toml +++ b/crates/ironrdp-pdu/Cargo.toml @@ -42,3 +42,7 @@ pkcs1 = "0.7" [dev-dependencies] expect-test.workspace = true lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html + +[lints] +workspace = true + diff --git a/crates/ironrdp-rdcleanpath/Cargo.toml b/crates/ironrdp-rdcleanpath/Cargo.toml index 17898122..060fe83f 100644 --- a/crates/ironrdp-rdcleanpath/Cargo.toml +++ b/crates/ironrdp-rdcleanpath/Cargo.toml @@ -16,4 +16,7 @@ doctest = false test = false [dependencies] -der = { version = "0.7", features = ["alloc", "derive"] } \ No newline at end of file +der = { version = "0.7", features = ["alloc", "derive"] } +[lints] +workspace = true + diff --git a/crates/ironrdp-rdpdr/Cargo.toml b/crates/ironrdp-rdpdr/Cargo.toml index eb86a84d..4d400895 100644 --- a/crates/ironrdp-rdpdr/Cargo.toml +++ b/crates/ironrdp-rdpdr/Cargo.toml @@ -21,3 +21,7 @@ ironrdp-pdu.workspace = true ironrdp-svc.workspace = true tracing.workspace = true bitflags.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-rdpsnd-native/Cargo.toml b/crates/ironrdp-rdpsnd-native/Cargo.toml index 2cba6a3e..77375631 100644 --- a/crates/ironrdp-rdpsnd-native/Cargo.toml +++ b/crates/ironrdp-rdpsnd-native/Cargo.toml @@ -22,3 +22,7 @@ tracing.workspace = true [dev-dependencies] tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-rdpsnd/Cargo.toml b/crates/ironrdp-rdpsnd/Cargo.toml index 83a494e0..fc03ee0c 100644 --- a/crates/ironrdp-rdpsnd/Cargo.toml +++ b/crates/ironrdp-rdpsnd/Cargo.toml @@ -24,3 +24,7 @@ bitflags.workspace = true tracing.workspace = true ironrdp-svc.workspace = true ironrdp-pdu = { workspace = true, features = ["alloc"] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-replay-client/Cargo.toml b/crates/ironrdp-replay-client/Cargo.toml index f30a5e5e..3ba54728 100644 --- a/crates/ironrdp-replay-client/Cargo.toml +++ b/crates/ironrdp-replay-client/Cargo.toml @@ -18,3 +18,7 @@ tracing.workspace = true tracing-subscriber = { version = "0.3", features = ["env-filter"] } clap = { version = "4.2", features = ["derive", "cargo"] } glutin = { version = "0.29" } + +[lints] +workspace = true + diff --git a/crates/ironrdp-server/Cargo.toml b/crates/ironrdp-server/Cargo.toml index 03e7643e..d5b0475a 100644 --- a/crates/ironrdp-server/Cargo.toml +++ b/crates/ironrdp-server/Cargo.toml @@ -34,3 +34,7 @@ tracing.workspace = true [dev-dependencies] tokio = { version = "1", features = ["sync"] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-session-generators/Cargo.toml b/crates/ironrdp-session-generators/Cargo.toml index 1f3f2fd3..cf0cadfa 100644 --- a/crates/ironrdp-session-generators/Cargo.toml +++ b/crates/ironrdp-session-generators/Cargo.toml @@ -13,3 +13,7 @@ test = false # ironrdp-session.workspace = true # ironrdp-pdu-generators.workspace = true # proptest.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-session/Cargo.toml b/crates/ironrdp-session/Cargo.toml index a4a17888..08b69d5e 100644 --- a/crates/ironrdp-session/Cargo.toml +++ b/crates/ironrdp-session/Cargo.toml @@ -24,3 +24,7 @@ ironrdp-graphics.workspace = true ironrdp-pdu = { workspace = true, features = ["std"] } ironrdp-displaycontrol.workspace = true tracing.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-svc/Cargo.toml b/crates/ironrdp-svc/Cargo.toml index e875b7a6..7e863073 100644 --- a/crates/ironrdp-svc/Cargo.toml +++ b/crates/ironrdp-svc/Cargo.toml @@ -22,3 +22,7 @@ std = [] [dependencies] ironrdp-pdu = { workspace = true, features = ["alloc"] } bitflags.workspace = true + +[lints] +workspace = true + diff --git a/crates/ironrdp-testsuite-core/Cargo.toml b/crates/ironrdp-testsuite-core/Cargo.toml index fa9fe584..579113d6 100644 --- a/crates/ironrdp-testsuite-core/Cargo.toml +++ b/crates/ironrdp-testsuite-core/Cargo.toml @@ -40,3 +40,7 @@ proptest.workspace = true rstest.workspace = true expect-test.workspace = true anyhow = "1" + +[lints] +workspace = true + diff --git a/crates/ironrdp-tls/Cargo.toml b/crates/ironrdp-tls/Cargo.toml index a9cc6557..265092fb 100644 --- a/crates/ironrdp-tls/Cargo.toml +++ b/crates/ironrdp-tls/Cargo.toml @@ -26,3 +26,7 @@ tokio = { version = "1.36" } x509-cert = { version = "0.2", default-features = false, features = ["std"], optional = true } tokio-native-tls = { version = "0.3", optional = true } tokio-rustls = { version = "0.26", optional = true } + +[lints] +workspace = true + diff --git a/crates/ironrdp-tokio/Cargo.toml b/crates/ironrdp-tokio/Cargo.toml index a2b4f8c8..56a19ce8 100644 --- a/crates/ironrdp-tokio/Cargo.toml +++ b/crates/ironrdp-tokio/Cargo.toml @@ -19,3 +19,7 @@ test = false bytes = "1" ironrdp-async.workspace = true tokio = { version = "1", features = ["io-util"] } + +[lints] +workspace = true + diff --git a/crates/ironrdp-web/Cargo.toml b/crates/ironrdp-web/Cargo.toml index cbad79ea..25a12c99 100644 --- a/crates/ironrdp-web/Cargo.toml +++ b/crates/ironrdp-web/Cargo.toml @@ -71,3 +71,7 @@ tap = "1" semver = "1" url = "2.5" base64 = "0.22" + +[lints] +workspace = true + diff --git a/crates/ironrdp/Cargo.toml b/crates/ironrdp/Cargo.toml index 3005f74c..5aeb99f4 100644 --- a/crates/ironrdp/Cargo.toml +++ b/crates/ironrdp/Cargo.toml @@ -74,3 +74,7 @@ doc-scrape-examples = true [[example]] name = "server" doc-scrape-examples = true + +[lints] +workspace = true + diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index d22786b8..0c7f2d0e 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -33,3 +33,7 @@ embed-resource = "2.4" windows = { version = "0.48", features = [ "Win32_Foundation", ] } + +[lints] +workspace = true + diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index faf8b38b..12fdd2aa 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -47,3 +47,4 @@ path = "fuzz_targets/channel_processing.rs" test = false doc = false bench = false + diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 7c28a257..d3c7fa3a 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -13,3 +13,7 @@ anyhow = "1" pico-args = "0.5" xshell = "0.2" tinyjson = "2.5" + +[lints] +workspace = true + diff --git a/xtask/src/check.rs b/xtask/src/check.rs index 8399e98c..8eae85ea 100644 --- a/xtask/src/check.rs +++ b/xtask/src/check.rs @@ -1,81 +1,5 @@ use crate::prelude::*; -// TODO: when 1.74 is released use `[lints]`: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lints -const EXTRA_LINTS: &[&str] = &[ - // == Safer unsafe == // - "unsafe_op_in_unsafe_fn", - "invalid_reference_casting", - "pointer_structural_match", - "clippy::undocumented_unsafe_blocks", - // "clippy::multiple_unsafe_ops_per_block", // FIXME: https://github.com/rust-lang/rust-clippy/issues/11312 (fixed for 1.75.0) - "clippy::transmute_ptr_to_ptr", - "clippy::as_ptr_cast_mut", - "clippy::cast_ptr_alignment", - "clippy::fn_to_numeric_cast_any", - "clippy::ptr_cast_constness", - // == Correctness == // - "unused_tuple_struct_fields", - "clippy::arithmetic_side_effects", - "clippy::cast_lossless", - "clippy::cast_possible_truncation", - "clippy::cast_possible_wrap", - "clippy::cast_sign_loss", - "clippy::float_cmp", - "clippy::as_underscore", - // TODO: "clippy::unwrap_used", // let’s either handle `None`, `Err` or use `expect` to give a reason - "clippy::large_stack_frames", - // == Style, readability == // - "elided_lifetimes_in_paths", // https://quinedot.github.io/rust-learning/dont-hide.html - "absolute_paths_not_starting_with_crate", - "single_use_lifetimes", - "unreachable_pub", - "unused_lifetimes", - "unused_qualifications", - "keyword_idents", - "noop_method_call", - "clippy::semicolon_outside_block", // with semicolon-outside-block-ignore-multiline = true - "clippy::clone_on_ref_ptr", - "clippy::cloned_instead_of_copied", - "clippy::trait_duplication_in_bounds", - "clippy::type_repetition_in_bounds", - "clippy::checked_conversions", - "clippy::get_unwrap", - // TODO: "clippy::similar_names", // reduce risk of confusing similar names together, and protects against typos when variable shadowing was intended - "clippy::str_to_string", - "clippy::string_to_string", - // TODO: "clippy::std_instead_of_alloc", - // TODO: "clippy::std_instead_of_core", - "clippy::separated_literal_suffix", - "clippy::unused_self", - // TODO: "clippy::use_self", // NOTE(@CBenoit): not sure about that one - "clippy::useless_let_if_seq", - // TODO: "clippy::partial_pub_fields", - "clippy::string_add", - "clippy::range_plus_one", - // TODO: "missing_docs" // NOTE(@CBenoit): we probably want to ensure this in core tier crates only - // == Compile-time / optimization == // - "unused_crate_dependencies", - "unused_macro_rules", - "clippy::inline_always", - "clippy::or_fun_call", - "clippy::unnecessary_box_returns", - // == Extra-pedantic clippy == // - "clippy::collection_is_never_read", - "clippy::copy_iterator", - "clippy::expl_impl_clone_on_copy", - "clippy::implicit_clone", - "clippy::large_types_passed_by_value", - "clippy::redundant_clone", - "clippy::alloc_instead_of_core", - "clippy::empty_drop", - "clippy::return_self_not_must_use", - "clippy::wildcard_dependencies", - // == Let’s not merge unintended eprint!/print! statements in libraries == // - "clippy::print_stderr", - "clippy::print_stdout", - "clippy::dbg_macro", -]; - pub fn fmt(sh: &Shell) -> anyhow::Result<()> { let _s = Section::new("FORMATTING"); @@ -94,9 +18,7 @@ pub fn lints(sh: &Shell) -> anyhow::Result<()> { let _s = Section::new("LINTS"); // TODO: when 1.74 is released use `--keep-going`: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#keep-going - let cmd = cmd!(sh, "{CARGO} clippy --workspace --locked -- -D warnings"); - - EXTRA_LINTS.iter().fold(cmd, |cmd, lint| cmd.args(["-W", lint])).run()?; + cmd!(sh, "{CARGO} clippy --workspace --locked -- -D warnings").run()?; println!("All good!");