Skip to content

Why not

This page records what was left out, so nobody has to rediscover these decisions. There are four kinds: rules no tool can check, gaps in lints that are enabled, lints that were considered and rejected, and rules that belong to specific Google codebases.

About 30 sections of the guide are design judgment. A linter sees syntax, while these rules depend on intent, audience and the future of the code:

Rule Why a lint cannot decide it
Library or application code The same function can be either; it depends on who calls it.
Newtype or type alias Depends on whether values could be confused, which is a domain question.
Named fields or tuples (f64, f64) is fine in a local helper and confusing in a public return type.
Iterators or Vec, impl IntoIterator or slices, impl Into<T> The guide lists six exceptions based on how callers use the result.
Generics or dyn Trait, trait or inherent impl Code size and API intent, not syntax.
Extension trait ownership Which team owns the type is not in the source.
Leaf module naming, non-leaf modules holding implementations “Primary item” and “a small amount of glue code” are judgment calls.
Locally-scoped trait imports Whether a trait is “used extensively throughout the file” is a threshold the guide leaves open.
Lifetime, generic parameter and abbreviation naming Descriptiveness is subjective; Ip is fine, Cfg is not.
Getters and setters, closure accessors Clippy cannot tell a getter from any other method returning a field.
Macros vs. functions Requires weighing alternatives that do not exist in the code yet.
Type inference “Enough explicit types that someone familiar with the codebase can follow” depends on the reader.
#[doc(hidden)], const fn commitments, operator overloading Ownership, future intent and meaning.
Trait selection (Copy, Clone, PartialEq vs. Eq, Hash) Depends on whether the type will stay Copy and how it will be used.

These rules live in AGENTS.md for agents and human-review.md for reviewers.

Lint Catches Misses
absolute_paths std::fs::read(), crate::a::f(), regex::Regex::new() inline Two-segment type paths (regex::Regex in a signature) and bare imported functions (use std::mem::swap; swap(..))
wildcard_imports Glob imports except the guide’s allowed forms use super::* in non-test inline modules is flagged although the guide allows it; defining a prelude module is not flagged
fn_params_excessive_bools Two or more bool parameters A single bool whose meaning is unclear at the call site
redundant_clone, implicit_clone Clones that are provably unnecessary Clones used to dodge a borrow that could be restructured
must_use_candidate Pure public functions Functions with side effects whose return value is still critical
missing_assert_message Assertions with no message Messages that only restate the condition
needless_for_each, format_push_string for_each, push_str(&format!(..)) Long or stateful iterator chains, chains in for headers, a + b + c string concatenation, str::replace templating
undocumented_unsafe_blocks unsafe without // SAFETY: Whether the comment is correct, and whether unsafe was needed at all
Lint or setting Why it is off
clippy::pedantic as a group Many of its lints have nothing to do with the guide (module_name_repetitions, similar_names, cast_*). The useful ones are enabled individually.
clippy::string_add, clippy::string_add_assign They flag every a + b. The guide only asks for format! when concatenating more than two strings.
clippy::clone_on_ref_ptr The guide says cloning an Rc/Arc “is an expected way to use them”. Rc/Arc themselves are already gated by disallowed_types.
clippy::rc_buffer, clippy::rc_mutex Covered more broadly by disallowed_types on Rc and Arc.
clippy::enum_glob_use Flags use Enum::* everywhere, including in function bodies, where the guide allows it. wildcard_imports already handles the cases the guide forbids.
warn-on-all-wildcard-imports = true Would flag use super::* in test modules, which the guide allows.
clippy::wildcard_enum_match_arm Bans the wildcard arm. The guide requires a wildcard arm when matching #[non_exhaustive] enums from other crates.
clippy::single_char_lifetime_names, clippy::min_ident_chars, clippy::many_single_char_names The guide allows single-letter lifetimes for method-local relationships and single-letter generics such as T. These lints cannot tell the allowed cases apart.
clippy::missing_const_for_fn Pushes toward marking functions const. The guide warns the opposite way: only make a public function const if you will keep it const.
clippy::derive_partial_eq_without_eq Pushes toward deriving Eq. The guide prefers PartialEq unless Eq is needed.
missing_copy_implementations, missing_debug_implementations The guide asks for Copy only when the type will reasonably stay Copy, and does not mention Debug. Blanket lints would force commitments the guide leaves to judgment.
clippy::return_self_not_must_use Targets builder methods, while the guide’s #[must_use]-on-types rule targets errors and lazy computations.
clippy::missing_docs_in_private_items The guide asks for docs on public APIs only.
clippy::expect_used, clippy::panic The guide permits expect and panic! for bugs and violated invariants.
clippy::allow_attributes It would force #[expect] everywhere. #[expect] is preferred, but it breaks on lints that fire only under some cfg combinations, so #[allow] with a reason stays legal.
clippy::mod_module_files, clippy::self_named_module_files The guide does not choose between foo/mod.rs and foo.rs.

The guide suggests the built-in non_exhaustive_omitted_patterns lint for its rule on matching #[non_exhaustive] enums. That lint is still feature-gated: on stable Rust it is reported as an unknown lint and does nothing. Enabling it would mean either a nightly toolchain, which the guide’s no-unstable-features rule rules out, or a permanently unknown-lint warning. The rule lives in AGENTS.md and the review checklist until the lint is stabilized. Re-check with each Rust release:

Terminal window
echo '#![warn(non_exhaustive_omitted_patterns)]' > /tmp/probe.rs && rustc --crate-type lib --out-dir /tmp /tmp/probe.rs

The guide includes rules tagged for particular Google codebases. They depend on Google’s build systems and runtimes, so this kit does not enforce them. If your codebase has the same constraint, the table shows how to add it.

Rule Codebase To adopt anyway
Prefer small crates Chromium Review policy
Flat file layout for rust_library sources Chromium Review policy
Use chromium::import!() Chromium Not applicable outside Chromium
Don’t use async / .await Chromium No lint exists; review policy
Don’t start threads through the standard library Chromium Add { path = "std::thread::spawn" } and std::thread::Builder::spawn to disallowed-methods
Use fuchsia_sync::Mutex Fuchsia Add std::sync::Mutex and parking_lot::Mutex to disallowed-types
Use the per-codebase test framework Chromium, Fuchsia Not applicable outside those codebases

The guide’s exceptions for unstable features (Android embedded, Chrome’s approved list, Fuchsia) are also out of scope. This kit pins stable.

The guide says a codebase that wants to stay on stable may skip its nightly-only rustfmt options. This kit keeps them in rustfmt.toml anyway, because stable rustfmt ignores them with a warning. To silence the warning on a stable-only team, delete the three nightly options; the import granularity rule then moves to review.

Unofficial community project, not affiliated with or endorsed by Google. TheGoogle Rust Style Guide is published by Google under CC-BY 3.0. This kit is Apache-2.0.