Auto merge of #76549 - ehuss:lints-comments, r=wesleywiser

Auto-generate lint documentation.

This adds a tool which will generate the lint documentation in the rustc book automatically. This is motivated by keeping the documentation up-to-date, and consistently formatted. It also ensures the examples are correct and that they actually generate the expected lint. The lint groups table is also auto-generated. See https://github.com/rust-lang/compiler-team/issues/349 for the original proposal.

An outline of how this works:
- The `declare_lint!` macro now accepts a doc comment where the documentation is written. This is inspired by how clippy works.
- A new tool `src/tools/lint-docs` scrapes the documentation and adds it to the rustc book during the build.
    - It runs each example and verifies its output and embeds the output in the book.
    - It does a few formatting checks.
    - It verifies that every lint is documented.
- Groups are collected from `rustc -W help`.

I updated the documentation for all the missing lints. I have also added an "Explanation" section to each lint providing a reason for the lint and suggestions on how to resolve it.

This can lead towards a future enhancement of possibly showing these docs via the `--explain` flag to make them easily accessible and discoverable.
This commit is contained in:
bors 2020-09-14 05:54:44 +00:00
commit b5f55b7e15
23 changed files with 3869 additions and 1567 deletions

View File

@ -1677,6 +1677,15 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
[[package]]
name = "lint-docs"
version = "0.1.0"
dependencies = [
"serde_json",
"tempfile",
"walkdir",
]
[[package]]
name = "lock_api"
version = "0.3.4"

View File

@ -9,6 +9,7 @@ members = [
"src/tools/compiletest",
"src/tools/error_index_generator",
"src/tools/linkchecker",
"src/tools/lint-docs",
"src/tools/rustbook",
"src/tools/unstable-book-gen",
"src/tools/tidy",

View File

@ -7,6 +7,31 @@ use rustc_session::lint::FutureIncompatibleInfo;
use rustc_span::symbol::sym;
declare_lint! {
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
///
/// ### Example
///
/// ```rust
/// # #![allow(unused)]
/// [1, 2, 3].into_iter().for_each(|n| { *n; });
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In the future, it is planned to add an `IntoIter` implementation for
/// arrays such that it will iterate over *values* of the array instead of
/// references. Due to how method resolution works, this will change
/// existing code that uses `into_iter` on arrays. The solution to avoid
/// this warning is to use `iter()` instead of `into_iter()`.
///
/// This is a [future-incompatible] lint to transition this to a hard error
/// in the future. See [issue #66145] for more details and a more thorough
/// description of the lint.
///
/// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub ARRAY_INTO_ITER,
Warn,
"detects calling `into_iter` on arrays",

View File

@ -61,6 +61,23 @@ use tracing::{debug, trace};
pub use rustc_session::lint::builtin::*;
declare_lint! {
/// The `while_true` lint detects `while true { }`.
///
/// ### Example
///
/// ```rust,no_run
/// while true {
///
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// `while true` should be replaced with `loop`. A `loop` expression is
/// the preferred way to write an infinite loop because it more directly
/// expresses the intent of the loop.
WHILE_TRUE,
Warn,
"suggest using `loop { }` instead of `while true { }`"
@ -102,6 +119,24 @@ impl EarlyLintPass for WhileTrue {
}
declare_lint! {
/// The `box_pointers` lints use of the Box type.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(box_pointers)]
/// struct Foo {
/// x: Box<isize>,
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is mostly historical, and not particularly useful. `Box<T>`
/// used to be built into the language, and the only way to do heap
/// allocation. Today's Rust can call into other allocators, etc.
BOX_POINTERS,
Allow,
"use of owned (Box type) heap memory"
@ -156,6 +191,36 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
}
declare_lint! {
/// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
/// instead of `Struct { x }` in a pattern.
///
/// ### Example
///
/// ```rust
/// struct Point {
/// x: i32,
/// y: i32,
/// }
///
///
/// fn main() {
/// let p = Point {
/// x: 5,
/// y: 5,
/// };
///
/// match p {
/// Point { x: x, y: y } => (),
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The preferred style is to avoid the repetition of specifying both the
/// field name and the binding name if both identifiers are the same.
NON_SHORTHAND_FIELD_PATTERNS,
Warn,
"using `Struct { x: x }` instead of `Struct { x }` in a pattern"
@ -216,6 +281,25 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
}
declare_lint! {
/// The `unsafe_code` lint catches usage of `unsafe` code.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unsafe_code)]
/// fn main() {
/// unsafe {
///
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is intended to restrict the usage of `unsafe`, which can be
/// difficult to use correctly.
UNSAFE_CODE,
Allow,
"usage of `unsafe` code"
@ -303,6 +387,25 @@ impl EarlyLintPass for UnsafeCode {
}
declare_lint! {
/// The `missing_docs` lint detects missing documentation for public items.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(missing_docs)]
/// pub fn foo() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is intended to ensure that a library is well-documented.
/// Items without documentation can be difficult for users to understand
/// how to use properly.
///
/// This lint is "allow" by default because it can be noisy, and not all
/// projects may want to enforce everything to be documented.
pub MISSING_DOCS,
Allow,
"detects missing documentation for public members",
@ -528,6 +631,34 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}
declare_lint! {
/// The `missing_copy_implementations` lint detects potentially-forgotten
/// implementations of [`Copy`].
///
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(missing_copy_implementations)]
/// pub struct Foo {
/// pub field: i32
/// }
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Historically (before 1.0), types were automatically marked as `Copy`
/// if possible. This was changed so that it required an explicit opt-in
/// by implementing the `Copy` trait. As part of this change, a lint was
/// added to alert if a copyable type was not marked `Copy`.
///
/// This lint is "allow" by default because this code isn't bad; it is
/// common to write newtypes like this specifically so that a `Copy` type
/// is no longer `Copy`. `Copy` types can result in unintended copies of
/// large data which can impact performance.
pub MISSING_COPY_IMPLEMENTATIONS,
Allow,
"detects potentially-forgotten implementations of `Copy`"
@ -584,6 +715,32 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
}
declare_lint! {
/// The `missing_debug_implementations` lint detects missing
/// implementations of [`fmt::Debug`].
///
/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(missing_debug_implementations)]
/// pub struct Foo;
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Having a `Debug` implementation on all types can assist with
/// debugging, as it provides a convenient way to format and display a
/// value. Using the `#[derive(Debug)]` attribute will automatically
/// generate a typical implementation, or a custom implementation can be
/// added by manually implementing the `Debug` trait.
///
/// This lint is "allow" by default because adding `Debug` to all types can
/// have a negative impact on compile time and code size. It also requires
/// boilerplate to be added to every type, which can be an impediment.
MISSING_DEBUG_IMPLEMENTATIONS,
Allow,
"detects missing implementations of Debug"
@ -640,6 +797,45 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
}
declare_lint! {
/// The `anonymous_parameters` lint detects anonymous parameters in trait
/// definitions.
///
/// ### Example
///
/// ```rust,edition2015,compile_fail
/// #![deny(anonymous_parameters)]
/// // edition 2015
/// pub trait Foo {
/// fn foo(usize);
/// }
/// fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This syntax is mostly a historical accident, and can be worked around
/// quite easily by adding an `_` pattern or a descriptive identifier:
///
/// ```rust
/// trait Foo {
/// fn foo(_: usize);
/// }
/// ```
///
/// This syntax is now a hard error in the 2018 edition. In the 2015
/// edition, this lint is "allow" by default, because the old code is
/// still valid, and warning for all old code can be noisy. This lint
/// enables the [`cargo fix`] tool with the `--edition` flag to
/// automatically transition old code from the 2015 edition to 2018. The
/// tool will switch this lint to "warn" and will automatically apply the
/// suggested fix from the compiler (which is to add `_` to each
/// parameter). This provides a completely automated way to update old
/// code for a new edition. See [issue #41686] for more details.
///
/// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub ANONYMOUS_PARAMETERS,
Allow,
"detects anonymous parameters",
@ -806,12 +1002,54 @@ impl EarlyLintPass for UnusedDocComment {
}
declare_lint! {
/// The `no_mangle_const_items` lint detects any `const` items with the
/// [`no_mangle` attribute].
///
/// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
///
/// ### Example
///
/// ```rust,compile_fail
/// #[no_mangle]
/// const FOO: i32 = 5;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Constants do not have their symbols exported, and therefore, this
/// probably means you meant to use a [`static`], not a [`const`].
///
/// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
/// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
NO_MANGLE_CONST_ITEMS,
Deny,
"const items will not have their symbols exported"
}
declare_lint! {
/// The `no_mangle_generic_items` lint detects generic items that must be
/// mangled.
///
/// ### Example
///
/// ```rust
/// #[no_mangle]
/// fn foo<T>(t: T) {
///
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// An function with generics must have its symbol mangled to accommodate
/// the generic parameter. The [`no_mangle` attribute] has no effect in
/// this situation, and should be removed.
///
/// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
NO_MANGLE_GENERIC_ITEMS,
Warn,
"generic items must be mangled"
@ -882,6 +1120,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
}
declare_lint! {
/// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
/// T` because it is [undefined behavior].
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// ### Example
///
/// ```rust,compile_fail
/// unsafe {
/// let y = std::mem::transmute::<&i32, &mut i32>(&5);
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Certain assumptions are made about aliasing of data, and this transmute
/// violates those assumptions. Consider using [`UnsafeCell`] instead.
///
/// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
MUTABLE_TRANSMUTES,
Deny,
"mutating transmuted &mut T from &T may cause undefined behavior"
@ -931,6 +1190,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
}
declare_lint! {
/// The `unstable_features` is deprecated and should no longer be used.
UNSTABLE_FEATURES,
Allow,
"enabling unstable features (deprecated. do not use)"
@ -956,6 +1216,32 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
}
declare_lint! {
/// The `unreachable_pub` lint triggers for `pub` items not reachable from
/// the crate root.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unreachable_pub)]
/// mod foo {
/// pub mod bar {
///
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// A bare `pub` visibility may be misleading if the item is not actually
/// publicly exported from the crate. The `pub(crate)` visibility is
/// recommended to be used instead, which more clearly expresses the intent
/// that the item is only visible within its own crate.
///
/// This lint is "allow" by default because it will trigger for a large
/// amount existing Rust code, and has some false-positives. Eventually it
/// is desired for this to become warn-by-default.
pub UNREACHABLE_PUB,
Allow,
"`pub` items not reachable from crate root"
@ -1035,6 +1321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
}
declare_lint! {
/// The `type_alias_bounds` lint detects bounds in type aliases.
///
/// ### Example
///
/// ```rust
/// type SendVec<T: Send> = Vec<T>;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The trait bounds in a type alias are currently ignored, and should not
/// be included to avoid confusion. This was previously allowed
/// unintentionally; this may become a hard error in the future.
TYPE_ALIAS_BOUNDS,
Warn,
"bounds in type aliases are not enforced"
@ -1194,6 +1495,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
}
declare_lint! {
/// The `trivial_bounds` lint detects trait bounds that don't depend on
/// any type parameters.
///
/// ### Example
///
/// ```rust
/// #![feature(trivial_bounds)]
/// pub struct A where i32: Copy;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Usually you would not write a trait bound that you know is always
/// true, or never true. However, when using macros, the macro may not
/// know whether or not the constraint would hold or not at the time when
/// generating the code. Currently, the compiler does not alert you if the
/// constraint is always true, and generates an error if it is never true.
/// The `trivial_bounds` feature changes this to be a warning in both
/// cases, giving macros more freedom and flexibility to generate code,
/// while still providing a signal when writing non-macro code that
/// something is amiss.
///
/// See [RFC 2056] for more details. This feature is currently only
/// available on the nightly channel, see [tracking issue #48214].
///
/// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
/// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
TRIVIAL_BOUNDS,
Warn,
"these bounds don't depend on an type parameters"
@ -1270,6 +1600,29 @@ declare_lint_pass!(
);
declare_lint! {
/// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
/// pattern], which is deprecated.
///
/// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
///
/// ### Example
///
/// ```rust
/// let x = 123;
/// match x {
/// 0...100 => {}
/// _ => {}
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The `...` range pattern syntax was changed to `..=` to avoid potential
/// confusion with the [`..` range expression]. Use the new form instead.
///
/// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
Warn,
"`...` range patterns are deprecated"
@ -1356,6 +1709,38 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}
declare_lint! {
/// The `unnameable_test_items` lint detects [`#[test]`][test] functions
/// that are not able to be run by the test harness because they are in a
/// position where they are not nameable.
///
/// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
///
/// ### Example
///
/// ```rust,test
/// fn main() {
/// #[test]
/// fn foo() {
/// // This test will not fail because it does not run.
/// assert_eq!(1, 2);
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In order for the test harness to run a test, the test function must be
/// located in a position where it can be accessed from the crate root.
/// This generally means it must be defined in a module, and not anywhere
/// else such as inside another function. The compiler previously allowed
/// this without an error, so a lint was added as an alert that a test is
/// not being used. Whether or not this should be allowed has not yet been
/// decided, see [RFC 2471] and [issue #36629].
///
/// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
/// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
UNNAMEABLE_TEST_ITEMS,
Warn,
"detects an item that cannot be named being marked as `#[test_case]`",
@ -1401,6 +1786,41 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
}
declare_lint! {
/// The `keyword_idents` lint detects edition keywords being used as an
/// identifier.
///
/// ### Example
///
/// ```rust,edition2015,compile_fail
/// #![deny(keyword_idents)]
/// // edition 2015
/// fn dyn() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Rust [editions] allow the language to evolve without breaking
/// backwards compatibility. This lint catches code that uses new keywords
/// that are added to the language that are used as identifiers (such as a
/// variable name, function name, etc.). If you switch the compiler to a
/// new edition without updating the code, then it will fail to compile if
/// you are using a new keyword as an identifier.
///
/// You can manually change the identifiers to a non-keyword, or use a
/// [raw identifier], for example `r#dyn`, to transition to a new edition.
///
/// This lint solves the problem automatically. It is "allow" by default
/// because the code is perfectly valid in older editions. The [`cargo
/// fix`] tool with the `--edition` flag will switch this lint to "warn"
/// and automatically apply the suggested fix from the compiler (which is
/// to use a raw identifier). This provides a completely automated way to
/// update old code for a new edition.
///
/// [editions]: https://doc.rust-lang.org/edition-guide/
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub KEYWORD_IDENTS,
Allow,
"detects edition keywords being used as an identifier",
@ -1802,6 +2222,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
}
declare_lint! {
/// The `incomplete_features` lint detects unstable features enabled with
/// the [`feature` attribute] that may function improperly in some or all
/// cases.
///
/// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
///
/// ### Example
///
/// ```rust
/// #![feature(generic_associated_types)]
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Although it is encouraged for people to experiment with unstable
/// features, some of them are known to be incomplete or faulty. This lint
/// is a signal that the feature has not yet been finished, and you may
/// experience problems with it.
pub INCOMPLETE_FEATURES,
Warn,
"incomplete features that may function improperly in some or all cases"
@ -1842,6 +2282,36 @@ impl EarlyLintPass for IncompleteFeatures {
}
declare_lint! {
/// The `invalid_value` lint detects creating a value that is not valid,
/// such as a NULL reference.
///
/// ### Example
///
/// ```rust,no_run
/// # #![allow(unused)]
/// unsafe {
/// let x: &'static i32 = std::mem::zeroed();
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In some situations the compiler can detect that the code is creating
/// an invalid value, which should be avoided.
///
/// In particular, this lint will check for improper use of
/// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
/// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
/// lint should provide extra information to indicate what the problem is
/// and a possible solution.
///
/// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
/// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
/// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
/// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
pub INVALID_VALUE,
Warn,
"an invalid value is being created (such as a NULL reference)"
@ -2073,6 +2543,40 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
}
declare_lint! {
/// The `clashing_extern_declarations` lint detects when an `extern fn`
/// has been declared with the same name but different types.
///
/// ### Example
///
/// ```rust
/// mod m {
/// extern "C" {
/// fn foo();
/// }
/// }
///
/// extern "C" {
/// fn foo(_: u32);
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Because two symbols of the same name cannot be resolved to two
/// different functions at link time, and one function cannot possibly
/// have two types, a clashing extern declaration is almost certainly a
/// mistake. Check to make sure that the `extern` definitions are correct
/// and equivalent, and possibly consider unifying them in one location.
///
/// This lint does not run between crates because a project may have
/// dependencies which both rely on the same extern function, but declare
/// it in a different (but valid) way. For example, they may both declare
/// an opaque type for one or more of the arguments (which would end up
/// distinct types), or use types that are valid conversions in the
/// language the `extern fn` is defined in. In these cases, the compiler
/// can't say that the clashing declaration is incorrect.
pub CLASHING_EXTERN_DECLARATIONS,
Warn,
"detects when an extern fn has been declared with the same name but different types"

View File

@ -4,6 +4,32 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_span::symbol::Symbol;
declare_lint! {
/// The `non_ascii_idents` lint detects non-ASCII identifiers.
///
/// ### Example
///
/// ```rust,compile_fail
/// # #![allow(unused)]
/// #![feature(non_ascii_idents)]
/// #![deny(non_ascii_idents)]
/// fn main() {
/// let föö = 1;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Currently on stable Rust, identifiers must contain ASCII characters.
/// The [`non_ascii_idents`] nightly-only feature allows identifiers to
/// contain non-ASCII characters. This lint allows projects that wish to
/// retain the limit of only using ASCII characters to switch this lint to
/// "forbid" (for example to ease collaboration or for security reasons).
/// See [RFC 2457] for more details.
///
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
/// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md
pub NON_ASCII_IDENTS,
Allow,
"detects non-ASCII identifiers",
@ -11,6 +37,37 @@ declare_lint! {
}
declare_lint! {
/// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in
/// identifiers.
///
/// ### Example
///
/// ```rust
/// # #![allow(unused)]
/// #![feature(non_ascii_idents)]
/// const µ: f64 = 0.000001;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// With the [`non_ascii_idents`] nightly-only feature enabled,
/// identifiers are allowed to use non-ASCII characters. This lint warns
/// about using characters which are not commonly used, and may cause
/// visual confusion.
///
/// This lint is triggered by identifiers that contain a codepoint that is
/// not part of the set of "Allowed" codepoints as described by [Unicode®
/// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General
/// Security Profile for Identifiers][TR39Allowed].
///
/// Note that the set of uncommon codepoints may change over time. Beware
/// that if you "forbid" this lint that existing code may fail in the
/// future.
///
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
/// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile
pub UNCOMMON_CODEPOINTS,
Warn,
"detects uncommon Unicode codepoints in identifiers",
@ -18,6 +75,43 @@ declare_lint! {
}
declare_lint! {
/// The `confusable_idents` lint detects visually confusable pairs between
/// identifiers.
///
/// ### Example
///
/// ```rust
/// #![feature(non_ascii_idents)]
///
/// // Latin Capital Letter E With Caron
/// pub const Ě: i32 = 1;
/// // Latin Capital Letter E With Breve
/// pub const Ĕ: i32 = 2;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// With the [`non_ascii_idents`] nightly-only feature enabled,
/// identifiers are allowed to use non-ASCII characters. This lint warns
/// when different identifiers may appear visually similar, which can
/// cause confusion.
///
/// The confusable detection algorithm is based on [Unicode® Technical
/// Standard #39 Unicode Security Mechanisms Section 4 Confusable
/// Detection][TR39Confusable]. For every distinct identifier X execute
/// the function `skeleton(X)`. If there exist two distinct identifiers X
/// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it.
/// The compiler uses the same mechanism to check if an identifier is too
/// similar to a keyword.
///
/// Note that the set of confusable characters may change over time.
/// Beware that if you "forbid" this lint that existing code may fail in
/// the future.
///
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
/// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection
pub CONFUSABLE_IDENTS,
Warn,
"detects visually confusable pairs between identifiers",
@ -25,6 +119,41 @@ declare_lint! {
}
declare_lint! {
/// The `mixed_script_confusables` lint detects visually confusable
/// characters in identifiers between different [scripts].
///
/// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode)
///
/// ### Example
///
/// ```rust
/// #![feature(non_ascii_idents)]
///
/// // The Japanese katakana character エ can be confused with the Han character 工.
/// const エ: &'static str = "アイウ";
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// With the [`non_ascii_idents`] nightly-only feature enabled,
/// identifiers are allowed to use non-ASCII characters. This lint warns
/// when characters between different scripts may appear visually similar,
/// which can cause confusion.
///
/// If the crate contains other identifiers in the same script that have
/// non-confusable characters, then this lint will *not* be issued. For
/// example, if the example given above has another identifier with
/// katakana characters (such as `let カタカナ = 123;`), then this indicates
/// that you are intentionally using katakana, and it will not warn about
/// it.
///
/// Note that the set of confusable characters may change over time.
/// Beware that if you "forbid" this lint that existing code may fail in
/// the future.
///
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
pub MIXED_SCRIPT_CONFUSABLES,
Warn,
"detects Unicode scripts whose mixed script confusables codepoints are solely used",

View File

@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext
}
declare_lint! {
/// The `non_camel_case_types` lint detects types, variants, traits and
/// type parameters that don't have camel case names.
///
/// ### Example
///
/// ```rust
/// struct my_struct;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The preferred style for these identifiers is to use "camel case", such
/// as `MyStruct`, where the first letter should not be lowercase, and
/// should not use underscores between letters. Underscores are allowed at
/// the beginning and end of the identifier, as well as between
/// non-letters (such as `X86_64`).
pub NON_CAMEL_CASE_TYPES,
Warn,
"types, variants, traits and type parameters should have camel case names"
@ -161,6 +179,22 @@ impl EarlyLintPass for NonCamelCaseTypes {
}
declare_lint! {
/// The `non_snake_case` lint detects variables, methods, functions,
/// lifetime parameters and modules that don't have snake case names.
///
/// ### Example
///
/// ```rust
/// let MY_VALUE = 5;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The preferred style for these identifiers is to use "snake case",
/// where all the characters are in lowercase, with words separated with a
/// single underscore, such as `my_value`.
pub NON_SNAKE_CASE,
Warn,
"variables, methods, functions, lifetime parameters and modules should have snake case names"
@ -379,6 +413,21 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
}
declare_lint! {
/// The `non_upper_case_globals` lint detects static items that don't have
/// uppercase identifiers.
///
/// ### Example
///
/// ```rust
/// static max_points: i32 = 5;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The preferred style is for static item names to use all uppercase
/// letters such as `MAX_POINTS`.
pub NON_UPPER_CASE_GLOBALS,
Warn,
"static constants should have uppercase identifiers"

View File

@ -4,6 +4,21 @@ use rustc_errors::Applicability;
use rustc_span::Span;
declare_lint! {
/// The `redundant_semicolons` lint detects unnecessary trailing
/// semicolons.
///
/// ### Example
///
/// ```rust
/// let _ = 123;;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Extra semicolons are not needed, and may be removed to avoid confusion
/// and visual clutter.
pub REDUNDANT_SEMICOLONS,
Warn,
"detects unnecessary trailing semicolons"

View File

@ -23,18 +23,82 @@ use std::cmp;
use tracing::debug;
declare_lint! {
/// The `unused_comparisons` lint detects comparisons made useless by
/// limits of the types involved.
///
/// ### Example
///
/// ```rust
/// fn foo(x: u8) {
/// x >= 0;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// A useless comparison may indicate a mistake, and should be fixed or
/// removed.
UNUSED_COMPARISONS,
Warn,
"comparisons made useless by limits of the types involved"
}
declare_lint! {
/// The `overflowing_literals` lint detects literal out of range for its
/// type.
///
/// ### Example
///
/// ```rust,compile_fail
/// let x: u8 = 1000;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// It is usually a mistake to use a literal that overflows the type where
/// it is used. Either use a literal that is within range, or change the
/// type to be within the range of the literal.
OVERFLOWING_LITERALS,
Deny,
"literal out of range for its type"
}
declare_lint! {
/// The `variant_size_differences` lint detects enums with widely varying
/// variant sizes.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(variant_size_differences)]
/// enum En {
/// V0(u8),
/// VBig([u8; 1024]),
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// It can be a mistake to add a variant to an enum that is much larger
/// than the other variants, bloating the overall size required for all
/// variants. This can impact performance and memory usage. This is
/// triggered if one variant is more than 3 times larger than the
/// second-largest variant.
///
/// Consider placing the large variant's contents on the heap (for example
/// via [`Box`]) to keep the overall size of the enum itself down.
///
/// This lint is "allow" by default because it can be noisy, and may not be
/// an actual problem. Decisions about this should be guided with
/// profiling and benchmarking.
///
/// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html
VARIANT_SIZE_DIFFERENCES,
Allow,
"detects enums with widely varying variant sizes"
@ -495,6 +559,27 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
declare_lint! {
/// The `improper_ctypes` lint detects incorrect use of types in foreign
/// modules.
///
/// ### Example
///
/// ```rust
/// extern "C" {
/// static STATIC: String;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The compiler has several checks to verify that types used in `extern`
/// blocks are safe and follow certain rules to ensure proper
/// compatibility with the foreign interfaces. This lint is issued when it
/// detects a probable mistake in a definition. The lint usually should
/// provide a description of the issue, along with possibly a hint on how
/// to resolve it.
IMPROPER_CTYPES,
Warn,
"proper use of libc types in foreign modules"
@ -503,6 +588,27 @@ declare_lint! {
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
declare_lint! {
/// The `improper_ctypes_definitions` lint detects incorrect use of
/// [`extern` function] definitions.
///
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
///
/// ### Example
///
/// ```rust
/// # #![allow(unused)]
/// pub extern "C" fn str_type(p: &str) { }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// There are many parameter and return types that may be specified in an
/// `extern` function that are not compatible with the given ABI. This
/// lint is an alert that these types should not be used. The lint usually
/// should provide a description of the issue, along with possibly a hint
/// on how to resolve it.
IMPROPER_CTYPES_DEFINITIONS,
Warn,
"proper use of libc types in foreign item definitions"

View File

@ -20,6 +20,29 @@ use rustc_span::{BytePos, Span, DUMMY_SP};
use tracing::debug;
declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as
/// `#[must_use]`.
///
/// ### Example
///
/// ```rust
/// fn returns_result() -> Result<(), ()> {
/// Ok(())
/// }
///
/// fn main() {
/// returns_result();
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The `#[must_use]` attribute is an indicator that it is a mistake to
/// ignore the value. See [the reference] for more details.
///
/// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
pub UNUSED_MUST_USE,
Warn,
"unused result of a type flagged as `#[must_use]`",
@ -27,6 +50,39 @@ declare_lint! {
}
declare_lint! {
/// The `unused_results` lint checks for the unused result of an
/// expression in a statement.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unused_results)]
/// fn foo<T>() -> T { panic!() }
///
/// fn main() {
/// foo::<usize>();
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Ignoring the return value of a function may indicate a mistake. In
/// cases were it is almost certain that the result should be used, it is
/// recommended to annotate the function with the [`must_use` attribute].
/// Failure to use such a return value will trigger the [`unused_must_use`
/// lint] which is warn-by-default. The `unused_results` lint is
/// essentially the same, but triggers for *all* return values.
///
/// This lint is "allow" by default because it can be noisy, and may not be
/// an actual problem. For example, calling the `remove` method of a `Vec`
/// or `HashMap` returns the previous value, which you may not care about.
/// Using this lint would require explicitly ignoring or discarding such
/// values.
///
/// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
/// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
pub UNUSED_RESULTS,
Allow,
"unused result of an expression in a statement"
@ -265,6 +321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
declare_lint! {
/// The `path_statements` lint detects path statements with no effect.
///
/// ### Example
///
/// ```rust
/// let x = 42;
///
/// x;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// It is usually a mistake to have a statement that has no effect.
pub PATH_STATEMENTS,
Warn,
"path statements with no effect"
@ -635,6 +706,21 @@ trait UnusedDelimLint {
}
declare_lint! {
/// The `unused_parens` lint detects `if`, `match`, `while` and `return`
/// with parentheses; they do not need them.
///
/// ### Examples
///
/// ```rust
/// if(true) {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The parenthesis are not needed, and should be removed. This is the
/// preferred style for writing these expressions.
pub(super) UNUSED_PARENS,
Warn,
"`if`, `match`, `while` and `return` do not need parentheses"
@ -808,6 +894,23 @@ impl EarlyLintPass for UnusedParens {
}
declare_lint! {
/// The `unused_braces` lint detects unnecessary braces around an
/// expression.
///
/// ### Example
///
/// ```rust
/// if { true } {
/// // ...
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The braces are not needed, and should be removed. This is the
/// preferred style for writing these expressions.
pub(super) UNUSED_BRACES,
Warn,
"unnecessary braces around an expression"
@ -929,6 +1032,30 @@ impl EarlyLintPass for UnusedBraces {
}
declare_lint! {
/// The `unused_import_braces` lint catches unnecessary braces around an
/// imported item.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unused_import_braces)]
/// use test::{A};
///
/// pub mod test {
/// pub struct A;
/// }
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// If there is only a single item, then remove the braces (`use test::A;`
/// for example).
///
/// This lint is "allow" by default because it is only enforcing a
/// stylistic choice.
UNUSED_IMPORT_BRACES,
Allow,
"unnecessary braces around an imported item"
@ -978,6 +1105,25 @@ impl EarlyLintPass for UnusedImportBraces {
}
declare_lint! {
/// The `unused_allocation` lint detects unnecessary allocations that can
/// be eliminated.
///
/// ### Example
///
/// ```rust
/// #![feature(box_syntax)]
/// fn main() {
/// let a = (box [1,2,3]).len();
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// When a `box` expression is immediately coerced to a reference, then
/// the allocation is unnecessary, and a reference (using `&` or `&mut`)
/// should be used instead to avoid the allocation.
pub(super) UNUSED_ALLOCATION,
Warn,
"detects unnecessary allocations that can be eliminated"

View File

@ -65,9 +65,15 @@ pub struct Lint {
///
/// The name is written with underscores, e.g., "unused_imports".
/// On the command line, underscores become dashes.
///
/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
/// for naming guidelines.
pub name: &'static str,
/// Default level for the lint.
///
/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
/// for guidelines on choosing a default level.
pub default_level: Level,
/// Description of the lint or the issue it detects.
@ -275,17 +281,60 @@ impl LintBuffer {
}
/// Declares a static item of type `&'static Lint`.
///
/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
/// and guidelines on writing lints.
///
/// The macro call should start with a doc comment explaining the lint
/// which will be embedded in the rustc user documentation book. It should
/// be written in markdown and have a format that looks like this:
///
/// ```rust,ignore (doc-example)
/// /// The `my_lint_name` lint detects [short explanation here].
/// ///
/// /// ### Example
/// ///
/// /// ```rust
/// /// [insert a concise example that triggers the lint]
/// /// ```
/// ///
/// /// {{produces}}
/// ///
/// /// ### Explanation
/// ///
/// /// This should be a detailed explanation of *why* the lint exists,
/// /// and also include suggestions on how the user should fix the problem.
/// /// Try to keep the text simple enough that a beginner can understand,
/// /// and include links to other documentation for terminology that a
/// /// beginner may not be familiar with. If this is "allow" by default,
/// /// it should explain why (are there false positives or other issues?). If
/// /// this is a future-incompatible lint, it should say so, with text that
/// /// looks roughly like this:
/// ///
/// /// This is a [future-incompatible] lint to transition this to a hard
/// /// error in the future. See [issue #xxxxx] for more details.
/// ///
/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx
/// ```
///
/// The `{{produces}}` tag will be automatically replaced with the output from
/// the example by the build system. You can build and view the rustc book
/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too
/// complex to run as a simple example (for example, it needs an extern
/// crate), mark it with `ignore` and manually paste the expected output below
/// the example.
#[macro_export]
macro_rules! declare_lint {
($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
$crate::declare_lint!(
$vis $NAME, $Level, $desc,
$(#[$attr])* $vis $NAME, $Level, $desc,
);
);
($vis: vis $NAME: ident, $Level: ident, $desc: expr,
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
$(@future_incompatible = $fi:expr;)?
$(@feature_gate = $gate:expr;)?
$($v:ident),*) => (
$(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
@ -298,9 +347,10 @@ macro_rules! declare_lint {
..$crate::lint::Lint::default_fields_for_macro()
};
);
($vis: vis $NAME: ident, $Level: ident, $desc: expr,
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
$lint_edition: expr => $edition_level: ident
) => (
$(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,6 @@ book!(
Nomicon, "src/doc/nomicon", "nomicon";
Reference, "src/doc/reference", "reference";
RustByExample, "src/doc/rust-by-example", "rust-by-example";
RustcBook, "src/doc/rustc", "rustc";
RustdocBook, "src/doc/rustdoc", "rustdoc";
);
@ -718,3 +717,66 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()>
symlink_dir(config, src, dst)
}
#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustcBook {
pub compiler: Compiler,
pub target: TargetSelection,
}
impl Step for RustcBook {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
run.path("src/doc/rustc").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(RustcBook {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
/// Builds the rustc book.
///
/// The lints are auto-generated by a tool, and then merged into the book
/// in the "md-doc" directory in the build output directory. Then
/// "rustbook" is used to convert it to HTML.
fn run(self, builder: &Builder<'_>) {
let out_base = builder.md_doc_out(self.target).join("rustc");
t!(fs::create_dir_all(&out_base));
let out_listing = out_base.join("src/lints");
builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
builder.info(&format!("Generating lint docs ({})", self.target));
let rustc = builder.rustc(self.compiler);
// The tool runs `rustc` for extracting output examples, so it needs a
// functional sysroot.
builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
let mut cmd = builder.tool_cmd(Tool::LintDocs);
cmd.arg("--src");
cmd.arg(builder.src.join("compiler"));
cmd.arg("--out");
cmd.arg(&out_listing);
cmd.arg("--rustc");
cmd.arg(rustc);
if builder.config.verbose() {
cmd.arg("--verbose");
}
builder.run(&mut cmd);
// Run rustbook/mdbook to generate the HTML pages.
builder.ensure(RustbookSrc {
target: self.target,
name: INTERNER.intern_str("rustc"),
src: INTERNER.intern_path(out_base),
});
if is_explicit_request(builder, "src/doc/rustc") {
let out = builder.doc_out(self.target);
let index = out.join("rustc").join("index.html");
open(builder, &index);
}
}
}

View File

@ -367,6 +367,7 @@ bootstrap_tool!(
RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
LintDocs, "src/tools/lint-docs", "lint-docs";
);
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]

View File

@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals
Here's a list of each lint group, and the lints that they are made up of:
| group | description | lints |
|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals |
| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings |
| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer |
| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub |
| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens |
| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision |
{{groups-table}}
Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`.

View File

@ -26,3 +26,35 @@ warning: unused variable: `x`
This is the `unused_variables` lint, and it tells you that you've introduced
a variable that you don't use in your code. That's not *wrong*, so it's not
an error, but it might be a bug, so you get a warning.
## Future-incompatible lints
Sometimes the compiler needs to be changed to fix an issue that can cause
existing code to stop compiling. "Future-incompatible" lints are issued in
these cases to give users of Rust a smooth transition to the new behavior.
Initially, the compiler will continue to accept the problematic code and issue
a warning. The warning has a description of the problem, a notice that this
will become an error in the future, and a link to a tracking issue that
provides detailed information and an opportunity for feedback. This gives
users some time to fix the code to accommodate the change. After some time,
the warning may become an error.
The following is an example of what a future-incompatible looks like:
```text
warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
--> lint_example.rs:11:13
|
11 | let y = &x.data.0;
| ^^^^^^^^^
|
= note: `#[warn(safe_packed_borrows)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
= note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
```
For more information about the process and policy of future-incompatible
changes, see [RFC 1589].
[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md

View File

@ -1,454 +1,3 @@
# Allowed-by-default lints
These lints are all set to the 'allow' level by default. As such, they won't show up
unless you set them to a higher lint level with a flag or attribute.
## anonymous-parameters
This lint detects anonymous parameters. Some example code that triggers this lint:
```rust
trait Foo {
fn foo(usize);
}
```
When set to 'deny', this will produce:
```text
error: use of deprecated anonymous parameter
--> src/lib.rs:5:11
|
5 | fn foo(usize);
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
```
This syntax is mostly a historical accident, and can be worked around quite
easily:
```rust
trait Foo {
fn foo(_: usize);
}
```
## bare-trait-object
This lint suggests using `dyn Trait` for trait objects. Some example code
that triggers this lint:
```rust
#![feature(dyn_trait)]
trait Trait { }
fn takes_trait_object(_: Box<Trait>) {
}
```
When set to 'deny', this will produce:
```text
error: trait objects without an explicit `dyn` are deprecated
--> src/lib.rs:7:30
|
7 | fn takes_trait_object(_: Box<Trait>) {
| ^^^^^ help: use `dyn`: `dyn Trait`
|
```
To fix it, do as the help message suggests:
```rust
#![feature(dyn_trait)]
#![deny(bare_trait_objects)]
trait Trait { }
fn takes_trait_object(_: Box<dyn Trait>) {
}
```
## box-pointers
This lints use of the Box type. Some example code that triggers this lint:
```rust
struct Foo {
x: Box<isize>,
}
```
When set to 'deny', this will produce:
```text
error: type uses owned (Box type) pointers: std::boxed::Box<isize>
--> src/lib.rs:6:5
|
6 | x: Box<isize> //~ ERROR type uses owned
| ^^^^^^^^^^^^^
|
```
This lint is mostly historical, and not particularly useful. `Box<T>` used to
be built into the language, and the only way to do heap allocation. Today's
Rust can call into other allocators, etc.
## elided-lifetime-in-path
This lint detects the use of hidden lifetime parameters. Some example code
that triggers this lint:
```rust
struct Foo<'a> {
x: &'a u32
}
fn foo(x: &Foo) {
}
```
When set to 'deny', this will produce:
```text
error: hidden lifetime parameters are deprecated, try `Foo<'_>`
--> src/lib.rs:5:12
|
5 | fn foo(x: &Foo) {
| ^^^
|
```
Lifetime elision elides this lifetime, but that is being deprecated.
## missing-copy-implementations
This lint detects potentially-forgotten implementations of `Copy`. Some
example code that triggers this lint:
```rust
pub struct Foo {
pub field: i32
}
```
When set to 'deny', this will produce:
```text
error: type could implement `Copy`; consider adding `impl Copy`
--> src/main.rs:3:1
|
3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy`
4 | | pub field: i32
5 | | }
| |_^
|
```
You can fix the lint by deriving `Copy`.
This lint is set to 'allow' because this code isn't bad; it's common to write
newtypes like this specifically so that a `Copy` type is no longer `Copy`.
## missing-debug-implementations
This lint detects missing implementations of `fmt::Debug`. Some example code
that triggers this lint:
```rust
pub struct Foo;
```
When set to 'deny', this will produce:
```text
error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
--> src/main.rs:3:1
|
3 | pub struct Foo;
| ^^^^^^^^^^^^^^^
|
```
You can fix the lint by deriving `Debug`.
## missing-docs
This lint detects missing documentation for public items. Some example code
that triggers this lint:
```rust
pub fn foo() {}
```
When set to 'deny', this will produce:
```text
error: missing documentation for crate
--> src/main.rs:1:1
|
1 | / #![deny(missing_docs)]
2 | |
3 | | pub fn foo() {}
4 | |
5 | | fn main() {}
| |____________^
|
error: missing documentation for a function
--> src/main.rs:3:1
|
3 | pub fn foo() {}
| ^^^^^^^^^^^^
```
To fix the lint, add documentation to all items.
## single-use-lifetimes
This lint detects lifetimes that are only used once. Some example code that
triggers this lint:
```rust
struct Foo<'x> {
x: &'x u32
}
```
When set to 'deny', this will produce:
```text
error: lifetime name `'x` only used once
--> src/main.rs:3:12
|
3 | struct Foo<'x> {
| ^^
|
```
## trivial-casts
This lint detects trivial casts which could be replaced with coercion, which may require
type ascription or a temporary variable. Some example code
that triggers this lint:
```rust
let x: &u32 = &42;
let _ = x as *const u32;
```
When set to 'deny', this will produce:
```text
error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
--> src/main.rs:5:13
|
5 | let _ = x as *const u32;
| ^^^^^^^^^^^^^^^
|
note: lint level defined here
--> src/main.rs:1:9
|
1 | #![deny(trivial_casts)]
| ^^^^^^^^^^^^^
```
## trivial-numeric-casts
This lint detects trivial casts of numeric types which could be removed. Some
example code that triggers this lint:
```rust
let x = 42i32 as i32;
```
When set to 'deny', this will produce:
```text
error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
--> src/main.rs:4:13
|
4 | let x = 42i32 as i32;
| ^^^^^^^^^^^^
|
```
## unreachable-pub
This lint triggers for `pub` items not reachable from the crate root. Some
example code that triggers this lint:
```rust
mod foo {
pub mod bar {
}
}
```
When set to 'deny', this will produce:
```text
error: unreachable `pub` item
--> src/main.rs:4:5
|
4 | pub mod bar {
| ---^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
```
## unsafe-code
This lint catches usage of `unsafe` code. Some example code that triggers this lint:
```rust
fn main() {
unsafe {
}
}
```
When set to 'deny', this will produce:
```text
error: usage of an `unsafe` block
--> src/main.rs:4:5
|
4 | / unsafe {
5 | |
6 | | }
| |_____^
|
```
## unstable-features
This lint is deprecated and no longer used.
## unused-extern-crates
This lint guards against `extern crate` items that are never used. Some
example code that triggers this lint:
```rust,ignore
extern crate semver;
```
When set to 'deny', this will produce:
```text
error: unused extern crate
--> src/main.rs:3:1
|
3 | extern crate semver;
| ^^^^^^^^^^^^^^^^^^^^
|
```
## unused-import-braces
This lint catches unnecessary braces around an imported item. Some example
code that triggers this lint:
```rust
use test::{A};
pub mod test {
pub struct A;
}
# fn main() {}
```
When set to 'deny', this will produce:
```text
error: braces around A is unnecessary
--> src/main.rs:3:1
|
3 | use test::{A};
| ^^^^^^^^^^^^^^
|
```
To fix it, `use test::A;`
## unused-qualifications
This lint detects unnecessarily qualified names. Some example code that triggers this lint:
```rust
mod foo {
pub fn bar() {}
}
fn main() {
use foo::bar;
foo::bar();
}
```
When set to 'deny', this will produce:
```text
error: unnecessary qualification
--> src/main.rs:9:5
|
9 | foo::bar();
| ^^^^^^^^
|
```
You can call `bar()` directly, without the `foo::`.
## unused-results
This lint checks for the unused result of an expression in a statement. Some
example code that triggers this lint:
```rust,no_run
fn foo<T>() -> T { panic!() }
fn main() {
foo::<usize>();
}
```
When set to 'deny', this will produce:
```text
error: unused result
--> src/main.rs:6:5
|
6 | foo::<usize>();
| ^^^^^^^^^^^^^^^
|
```
## variant-size-differences
This lint detects enums with widely varying variant sizes. Some example code that triggers this lint:
```rust
enum En {
V0(u8),
VBig([u8; 1024]),
}
```
When set to 'deny', this will produce:
```text
error: enum variant is more than three times larger (1024 bytes) than the next largest
--> src/main.rs:5:5
|
5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger
| ^^^^^^^^^^^^^^^^
|
```
This file is auto-generated by the lint-docs script.

View File

@ -1,203 +1,3 @@
# Deny-by-default lints
These lints are all set to the 'deny' level by default.
## exceeding-bitshifts
This lint detects that a shift exceeds the type's number of bits. Some
example code that triggers this lint:
```rust,ignore
1_i32 << 32;
```
This will produce:
```text
error: bitshift exceeds the type's number of bits
--> src/main.rs:2:5
|
2 | 1_i32 << 32;
| ^^^^^^^^^^^
|
```
## invalid-type-param-default
This lint detects type parameter default erroneously allowed in invalid location. Some
example code that triggers this lint:
```rust,ignore
fn foo<T=i32>(t: T) {}
```
This will produce:
```text
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
--> src/main.rs:4:8
|
4 | fn foo<T=i32>(t: T) {}
| ^
|
= note: `#[deny(invalid_type_param_default)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
```
## mutable-transmutes
This lint catches transmuting from `&T` to `&mut T` because it is undefined
behavior. Some example code that triggers this lint:
```rust,ignore
unsafe {
let y = std::mem::transmute::<&i32, &mut i32>(&5);
}
```
This will produce:
```text
error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
--> src/main.rs:3:17
|
3 | let y = std::mem::transmute::<&i32, &mut i32>(&5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
```
## no-mangle-const-items
This lint detects any `const` items with the `#[no_mangle]` attribute.
Constants do not have their symbols exported, and therefore, this probably
means you meant to use a `static`, not a `const`. Some example code that
triggers this lint:
```rust,ignore
#[no_mangle]
const FOO: i32 = 5;
```
This will produce:
```text
error: const items should never be `#[no_mangle]`
--> src/main.rs:3:1
|
3 | const FOO: i32 = 5;
| -----^^^^^^^^^^^^^^
| |
| help: try a static value: `pub static`
|
```
## overflowing-literals
This lint detects literal out of range for its type. Some
example code that triggers this lint:
```rust,compile_fail
let x: u8 = 1000;
```
This will produce:
```text
error: literal out of range for u8
--> src/main.rs:2:17
|
2 | let x: u8 = 1000;
| ^^^^
|
```
## patterns-in-fns-without-body
This lint detects patterns in functions without body were that were
previously erroneously allowed. Some example code that triggers this lint:
```rust,compile_fail
trait Trait {
fn foo(mut arg: u8);
}
```
This will produce:
```text
warning: patterns aren't allowed in methods without bodies
--> src/main.rs:2:12
|
2 | fn foo(mut arg: u8);
| ^^^^^^^
|
= note: `#[warn(patterns_in_fns_without_body)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>
```
To fix this, remove the pattern; it can be used in the implementation without
being used in the definition. That is:
```rust
trait Trait {
fn foo(arg: u8);
}
impl Trait for i32 {
fn foo(mut arg: u8) {
}
}
```
## pub-use-of-private-extern-crate
This lint detects a specific situation of re-exporting a private `extern crate`;
## unknown-crate-types
This lint detects an unknown crate type found in a `#[crate_type]` directive. Some
example code that triggers this lint:
```rust,ignore
#![crate_type="lol"]
```
This will produce:
```text
error: invalid `crate_type` value
--> src/lib.rs:1:1
|
1 | #![crate_type="lol"]
| ^^^^^^^^^^^^^^^^^^^^
|
```
## const-err
This lint detects expressions that will always panic at runtime and would be an
error in a `const` context.
```rust,ignore
let _ = [0; 4][4];
```
This will produce:
```text
error: index out of bounds: the len is 4 but the index is 4
--> src/lib.rs:1:9
|
1 | let _ = [0; 4][4];
| ^^^^^^^^^
|
```
## order-dependent-trait-objects
This lint detects a trait coherency violation that would allow creating two
trait impls for the same dynamic trait object involving marker traits.
This file is auto-generated by the lint-docs script.

View File

@ -1,903 +1,3 @@
# Warn-by-default lints
These lints are all set to the 'warn' level by default.
## const-err
This lint detects an erroneous expression while doing constant evaluation. Some
example code that triggers this lint:
```rust,ignore
let b = 200u8 + 200u8;
```
This will produce:
```text
warning: attempt to add with overflow
--> src/main.rs:2:9
|
2 | let b = 200u8 + 200u8;
| ^^^^^^^^^^^^^
|
```
## dead-code
This lint detects unused, unexported items. Some
example code that triggers this lint:
```rust
fn foo() {}
```
This will produce:
```text
warning: function is never used: `foo`
--> src/lib.rs:2:1
|
2 | fn foo() {}
| ^^^^^^^^
|
```
## deprecated
This lint detects use of deprecated items. Some
example code that triggers this lint:
```rust
#[deprecated]
fn foo() {}
fn bar() {
foo();
}
```
This will produce:
```text
warning: use of deprecated item 'foo'
--> src/lib.rs:7:5
|
7 | foo();
| ^^^
|
```
## illegal-floating-point-literal-pattern
This lint detects floating-point literals used in patterns. Some example code
that triggers this lint:
```rust
let x = 42.0;
match x {
5.0 => {},
_ => {},
}
```
This will produce:
```text
warning: floating-point literals cannot be used in patterns
--> src/main.rs:4:9
|
4 | 5.0 => {},
| ^^^
|
= note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
```
## improper-ctypes
This lint detects proper use of libc types in foreign modules. Some
example code that triggers this lint:
```rust
extern "C" {
static STATIC: String;
}
```
This will produce:
```text
warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type
--> src/main.rs:2:20
|
2 | static STATIC: String;
| ^^^^^^
|
```
## late-bound-lifetime-arguments
This lint detects generic lifetime arguments in path segments with
late bound lifetime parameters. Some example code that triggers this lint:
```rust
struct S;
impl S {
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
}
fn main() {
S.late::<'static>(&0, &0);
}
```
This will produce:
```text
warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
--> src/main.rs:8:14
|
4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
| -- the late bound lifetime parameter is introduced here
...
8 | S.late::<'static>(&0, &0);
| ^^^^^^^
|
= note: `#[warn(late_bound_lifetime_arguments)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
```
## non-camel-case-types
This lint detects types, variants, traits and type parameters that don't have
camel case names. Some example code that triggers this lint:
```rust
struct s;
```
This will produce:
```text
warning: type `s` should have a camel case name such as `S`
--> src/main.rs:1:1
|
1 | struct s;
| ^^^^^^^^^
|
```
## non-shorthand-field-patterns
This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some
example code that triggers this lint:
```rust
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point {
x: 5,
y: 5,
};
match p {
Point { x: x, y: y } => (),
}
}
```
This will produce:
```text
warning: the `x:` in this pattern is redundant
--> src/main.rs:14:17
|
14 | Point { x: x, y: y } => (),
| --^^
| |
| help: remove this
|
warning: the `y:` in this pattern is redundant
--> src/main.rs:14:23
|
14 | Point { x: x, y: y } => (),
| --^^
| |
| help: remove this
```
## non-snake-case
This lint detects variables, methods, functions, lifetime parameters and
modules that don't have snake case names. Some example code that triggers
this lint:
```rust
let X = 5;
```
This will produce:
```text
warning: variable `X` should have a snake case name such as `x`
--> src/main.rs:2:9
|
2 | let X = 5;
| ^
|
```
## non-upper-case-globals
This lint detects static constants that don't have uppercase identifiers.
Some example code that triggers this lint:
```rust
static x: i32 = 5;
```
This will produce:
```text
warning: static variable `x` should have an upper case name such as `X`
--> src/main.rs:1:1
|
1 | static x: i32 = 5;
| ^^^^^^^^^^^^^^^^^^
|
```
## no-mangle-generic-items
This lint detects generic items must be mangled. Some
example code that triggers this lint:
```rust
#[no_mangle]
fn foo<T>(t: T) {
}
```
This will produce:
```text
warning: functions generic over types must be mangled
--> src/main.rs:2:1
|
1 | #[no_mangle]
| ------------ help: remove this attribute
2 | / fn foo<T>(t: T) {
3 | |
4 | | }
| |_^
|
```
## path-statements
This lint detects path statements with no effect. Some example code that
triggers this lint:
```rust
let x = 42;
x;
```
This will produce:
```text
warning: path statement with no effect
--> src/main.rs:3:5
|
3 | x;
| ^^
|
```
## private-in-public
This lint detects private items in public interfaces not caught by the old implementation. Some
example code that triggers this lint:
```rust,ignore
pub trait Trait {
type A;
}
pub struct S;
mod foo {
struct Z;
impl ::Trait for ::S {
type A = Z;
}
}
# fn main() {}
```
This will produce:
```text
error[E0446]: private type `foo::Z` in public interface
--> src/main.rs:11:9
|
11 | type A = Z;
| ^^^^^^^^^^^ can't leak private type
```
## private-no-mangle-fns
This lint detects functions marked `#[no_mangle]` that are also private.
Given that private functions aren't exposed publicly, and `#[no_mangle]`
controls the public symbol, this combination is erroneous. Some example code
that triggers this lint:
```rust
#[no_mangle]
fn foo() {}
```
This will produce:
```text
warning: function is marked `#[no_mangle]`, but not exported
--> src/main.rs:2:1
|
2 | fn foo() {}
| -^^^^^^^^^^
| |
| help: try making it public: `pub`
|
```
To fix this, either make it public or remove the `#[no_mangle]`.
## private-no-mangle-statics
This lint detects any statics marked `#[no_mangle]` that are private.
Given that private statics aren't exposed publicly, and `#[no_mangle]`
controls the public symbol, this combination is erroneous. Some example code
that triggers this lint:
```rust
#[no_mangle]
static X: i32 = 4;
```
This will produce:
```text
warning: static is marked `#[no_mangle]`, but not exported
--> src/main.rs:2:1
|
2 | static X: i32 = 4;
| -^^^^^^^^^^^^^^^^^
| |
| help: try making it public: `pub`
|
```
To fix this, either make it public or remove the `#[no_mangle]`.
## renamed-and-removed-lints
This lint detects lints that have been renamed or removed. Some
example code that triggers this lint:
```rust
#![deny(raw_pointer_derive)]
```
This will produce:
```text
warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok
--> src/main.rs:1:9
|
1 | #![deny(raw_pointer_derive)]
| ^^^^^^^^^^^^^^^^^^
|
```
To fix this, either remove the lint or use the new name.
## safe-packed-borrows
This lint detects borrowing a field in the interior of a packed structure
with alignment other than 1. Some example code that triggers this lint:
```rust
#[repr(packed)]
pub struct Unaligned<T>(pub T);
pub struct Foo {
start: u8,
data: Unaligned<u32>,
}
fn main() {
let x = Foo { start: 0, data: Unaligned(1) };
let y = &x.data.0;
}
```
This will produce:
```text
warning: borrow of packed field requires unsafe function or block (error E0133)
--> src/main.rs:11:13
|
11 | let y = &x.data.0;
| ^^^^^^^^^
|
= note: `#[warn(safe_packed_borrows)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
```
## stable-features
This lint detects a `#[feature]` attribute that's since been made stable. Some
example code that triggers this lint:
```rust
#![feature(test_accepted_feature)]
```
This will produce:
```text
warning: this feature has been stable since 1.0.0. Attribute no longer needed
--> src/main.rs:1:12
|
1 | #![feature(test_accepted_feature)]
| ^^^^^^^^^^^^^^^^^^^^^
|
```
To fix, simply remove the `#![feature]` attribute, as it's no longer needed.
## type-alias-bounds
This lint detects bounds in type aliases. These are not currently enforced.
Some example code that triggers this lint:
```rust
#[allow(dead_code)]
type SendVec<T: Send> = Vec<T>;
```
This will produce:
```text
warning: bounds on generic parameters are not enforced in type aliases
--> src/lib.rs:2:17
|
2 | type SendVec<T: Send> = Vec<T>;
| ^^^^
|
= note: `#[warn(type_alias_bounds)]` on by default
= help: the bound will not be checked when the type alias is used, and should be removed
```
## tyvar-behind-raw-pointer
This lint detects raw pointer to an inference variable. Some
example code that triggers this lint:
```rust
let data = std::ptr::null();
let _ = &data as *const *const ();
if data.is_null() {}
```
This will produce:
```text
warning: type annotations needed
--> src/main.rs:4:13
|
4 | if data.is_null() {}
| ^^^^^^^
|
= note: `#[warn(tyvar_behind_raw_pointer)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
```
## unconditional-recursion
This lint detects functions that cannot return without calling themselves.
Some example code that triggers this lint:
```rust
fn foo() {
foo();
}
```
This will produce:
```text
warning: function cannot return without recursing
--> src/main.rs:1:1
|
1 | fn foo() {
| ^^^^^^^^ cannot return without recursing
2 | foo();
| ----- recursive call site
|
```
## unknown-lints
This lint detects unrecognized lint attribute. Some
example code that triggers this lint:
```rust,ignore
#[allow(not_a_real_lint)]
```
This will produce:
```text
warning: unknown lint: `not_a_real_lint`
--> src/main.rs:1:10
|
1 | #![allow(not_a_real_lint)]
| ^^^^^^^^^^^^^^^
|
```
## unreachable-code
This lint detects unreachable code paths. Some example code that
triggers this lint:
```rust,no_run
panic!("we never go past here!");
let x = 5;
```
This will produce:
```text
warning: unreachable statement
--> src/main.rs:4:5
|
4 | let x = 5;
| ^^^^^^^^^^
|
```
## unreachable-patterns
This lint detects unreachable patterns. Some
example code that triggers this lint:
```rust
let x = 5;
match x {
y => (),
5 => (),
}
```
This will produce:
```text
warning: unreachable pattern
--> src/main.rs:5:5
|
5 | 5 => (),
| ^
|
```
The `y` pattern will always match, so the five is impossible to reach.
Remember, match arms match in order, you probably wanted to put the `5` case
above the `y` case.
## unstable-name-collision
This lint detects that you've used a name that the standard library plans to
add in the future, which means that your code may fail to compile without
additional type annotations in the future. Either rename, or add those
annotations now.
## unused-allocation
This lint detects unnecessary allocations that can be eliminated.
## unused-assignments
This lint detects assignments that will never be read. Some
example code that triggers this lint:
```rust
let mut x = 5;
x = 6;
```
This will produce:
```text
warning: value assigned to `x` is never read
--> src/main.rs:4:5
|
4 | x = 6;
| ^
|
```
## unused-attributes
This lint detects attributes that were not used by the compiler. Some
example code that triggers this lint:
```rust
#![macro_export]
```
This will produce:
```text
warning: unused attribute
--> src/main.rs:1:1
|
1 | #![macro_export]
| ^^^^^^^^^^^^^^^^
|
```
## unused-comparisons
This lint detects comparisons made useless by limits of the types involved. Some
example code that triggers this lint:
```rust
fn foo(x: u8) {
x >= 0;
}
```
This will produce:
```text
warning: comparison is useless due to type limits
--> src/main.rs:6:5
|
6 | x >= 0;
| ^^^^^^
|
```
## unused-doc-comment
This lint detects doc comments that aren't used by rustdoc. Some
example code that triggers this lint:
```rust
/// docs for x
let x = 12;
```
This will produce:
```text
warning: doc comment not used by rustdoc
--> src/main.rs:2:5
|
2 | /// docs for x
| ^^^^^^^^^^^^^^
|
```
## unused-features
This lint detects unused or unknown features found in crate-level `#[feature]` directives.
To fix this, simply remove the feature flag.
## unused-imports
This lint detects imports that are never used. Some
example code that triggers this lint:
```rust
use std::collections::HashMap;
```
This will produce:
```text
warning: unused import: `std::collections::HashMap`
--> src/main.rs:1:5
|
1 | use std::collections::HashMap;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
```
## unused-macros
This lint detects macros that were not used. Some example code that
triggers this lint:
```rust
macro_rules! unused {
() => {};
}
fn main() {
}
```
This will produce:
```text
warning: unused macro definition
--> src/main.rs:1:1
|
1 | / macro_rules! unused {
2 | | () => {};
3 | | }
| |_^
|
```
## unused-must-use
This lint detects unused result of a type flagged as `#[must_use]`. Some
example code that triggers this lint:
```rust
fn returns_result() -> Result<(), ()> {
Ok(())
}
fn main() {
returns_result();
}
```
This will produce:
```text
warning: unused `std::result::Result` that must be used
--> src/main.rs:6:5
|
6 | returns_result();
| ^^^^^^^^^^^^^^^^^
|
```
## unused-mut
This lint detects mut variables which don't need to be mutable. Some
example code that triggers this lint:
```rust
let mut x = 5;
```
This will produce:
```text
warning: variable does not need to be mutable
--> src/main.rs:2:9
|
2 | let mut x = 5;
| ----^
| |
| help: remove this `mut`
|
```
## unused-parens
This lint detects `if`, `match`, `while` and `return` with parentheses; they
do not need them. Some example code that triggers this lint:
```rust
if(true) {}
```
This will produce:
```text
warning: unnecessary parentheses around `if` condition
--> src/main.rs:2:7
|
2 | if(true) {}
| ^^^^^^ help: remove these parentheses
|
```
## unused-unsafe
This lint detects unnecessary use of an `unsafe` block. Some
example code that triggers this lint:
```rust
unsafe {}
```
This will produce:
```text
warning: unnecessary `unsafe` block
--> src/main.rs:2:5
|
2 | unsafe {}
| ^^^^^^ unnecessary `unsafe` block
|
```
## unused-variables
This lint detects variables which are not used in any way. Some
example code that triggers this lint:
```rust
let x = 5;
```
This will produce:
```text
warning: unused variable: `x`
--> src/main.rs:2:9
|
2 | let x = 5;
| ^ help: consider using `_x` instead
|
```
## warnings
This lint is a bit special; by changing its level, you change every other warning
that would produce a warning to whatever value you'd like:
```rust
#![deny(warnings)]
```
As such, you won't ever trigger this lint in your code directly.
## while-true
This lint detects `while true { }`. Some example code that triggers this
lint:
```rust,no_run
while true {
}
```
This will produce:
```text
warning: denote infinite loops with `loop { ... }`
--> src/main.rs:2:5
|
2 | while true {
| ^^^^^^^^^^ help: use `loop`
|
```
This file is auto-generated by the lint-docs script.

View File

@ -49,6 +49,30 @@ warning: missing documentation for a function
| ^^^^^^^^^^^^^^^^^^^^^
```
## missing_crate_level_docs
This lint is **allowed by default**. It detects if there is no documentation
at the crate root. For example:
```rust
#![warn(missing_crate_level_docs)]
```
This will generate the following warning:
```text
warning: no documentation found for this crate's top-level module
|
= help: The following guide may be of use:
https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
```
This is currently "allow" by default, but it is intended to make this a
warning in the future. This is intended as a means to introduce new users on
*how* to document their crate by pointing them to some instructions on how to
get started, without providing overwhelming warnings like `missing_docs`
might.
## missing_doc_code_examples
This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
@ -117,3 +141,37 @@ warning: Documentation test in private item
8 | | /// ```
| |___________^
```
## invalid_codeblock_attributes
This lint **warns by default**. It detects code block attributes in
documentation examples that have potentially mis-typed values. For example:
```rust
/// Example.
///
/// ```should-panic
/// assert_eq!(1, 2);
/// ```
pub fn foo() {}
```
Which will give:
```text
warning: unknown attribute `should-panic`. Did you mean `should_panic`?
--> src/lib.rs:1:1
|
1 | / /// Example.
2 | | ///
3 | | /// ```should-panic
4 | | /// assert_eq!(1, 2);
5 | | /// ```
| |_______^
|
= note: `#[warn(invalid_codeblock_attributes)]` on by default
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
```
In the example above, the correct form is `should_panic`. This helps detect
typo mistakes for some common attributes.

View File

@ -0,0 +1,13 @@
[package]
name = "lint-docs"
version = "0.1.0"
authors = ["The Rust Project Developers"]
edition = "2018"
description = "A script to extract the lint documentation for the rustc book."
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde_json = "1.0.57"
tempfile = "3.1.0"
walkdir = "2.3.1"

View File

@ -0,0 +1,114 @@
use crate::Lint;
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::path::Path;
use std::process::Command;
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
("unused", "Lints that detect things being declared but not used, or excess syntax"),
("rustdoc", "Rustdoc-specific lints"),
("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
("nonstandard-style", "Violation of standard naming conventions"),
("future-incompatible", "Lints that detect code that has future-compatibility problems"),
("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
];
/// Updates the documentation of lint groups.
pub(crate) fn generate_group_docs(
lints: &[Lint],
rustc_path: &Path,
out_path: &Path,
) -> Result<(), Box<dyn Error>> {
let groups = collect_groups(rustc_path)?;
let groups_path = out_path.join("groups.md");
let contents = fs::read_to_string(&groups_path)
.map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?);
// Delete the output because rustbuild uses hard links in its copies.
let _ = fs::remove_file(&groups_path);
fs::write(&groups_path, new_contents)
.map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
Ok(())
}
type LintGroups = BTreeMap<String, BTreeSet<String>>;
/// Collects the group names from rustc.
fn collect_groups(rustc: &Path) -> Result<LintGroups, Box<dyn Error>> {
let mut result = BTreeMap::new();
let mut cmd = Command::new(rustc);
cmd.arg("-Whelp");
let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
if !output.status.success() {
return Err(format!(
"failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
output.status,
std::str::from_utf8(&output.stderr).unwrap(),
std::str::from_utf8(&output.stdout).unwrap(),
)
.into());
}
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let lines = stdout.lines();
let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
for line in table_start {
if line.is_empty() {
break;
}
let mut parts = line.trim().splitn(2, ' ');
let name = parts.next().expect("name in group");
if name == "warnings" {
// This is special.
continue;
}
let lints =
parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
assert!(result.insert(name.to_string(), lints).is_none());
}
if result.is_empty() {
return Err(
format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
);
}
Ok(result)
}
fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result<String, Box<dyn Error>> {
let mut result = String::new();
let mut to_link = Vec::new();
result.push_str("| Group | Description | Lints |\n");
result.push_str("|-------|-------------|-------|\n");
result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
for (group_name, group_lints) in groups {
let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name)
.ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))?
.1;
to_link.extend(group_lints);
let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap();
}
result.push('\n');
result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
for lint_name in to_link {
let lint_def =
lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
format!(
"`rustc -W help` defined lint `{}` but that lint does not appear to exist",
lint_name
)
})?;
write!(
result,
"[{}]: listing/{}#{}\n",
lint_name,
lint_def.level.doc_filename(),
lint_name
)
.unwrap();
}
Ok(result)
}

View File

@ -0,0 +1,472 @@
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use walkdir::WalkDir;
mod groups;
struct Lint {
name: String,
doc: Vec<String>,
level: Level,
path: PathBuf,
lineno: usize,
}
impl Lint {
fn doc_contains(&self, text: &str) -> bool {
self.doc.iter().any(|line| line.contains(text))
}
fn is_ignored(&self) -> bool {
self.doc
.iter()
.filter(|line| line.starts_with("```rust"))
.all(|line| line.contains(",ignore"))
}
}
#[derive(Clone, Copy, PartialEq)]
enum Level {
Allow,
Warn,
Deny,
}
impl Level {
fn doc_filename(&self) -> &str {
match self {
Level::Allow => "allowed-by-default.md",
Level::Warn => "warn-by-default.md",
Level::Deny => "deny-by-default.md",
}
}
}
/// Collects all lints, and writes the markdown documentation at the given directory.
pub fn extract_lint_docs(
src_path: &Path,
out_path: &Path,
rustc_path: &Path,
verbose: bool,
) -> Result<(), Box<dyn Error>> {
let mut lints = gather_lints(src_path)?;
for lint in &mut lints {
generate_output_example(lint, rustc_path, verbose).map_err(|e| {
format!(
"failed to test example in lint docs for `{}` in {}:{}: {}",
lint.name,
lint.path.display(),
lint.lineno,
e
)
})?;
}
save_lints_markdown(&lints, &out_path.join("listing"))?;
groups::generate_group_docs(&lints, rustc_path, out_path)?;
Ok(())
}
/// Collects all lints from all files in the given directory.
fn gather_lints(src_path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
let mut lints = Vec::new();
for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) {
if !entry.path().extension().map_or(false, |ext| ext == "rs") {
continue;
}
lints.extend(lints_from_file(entry.path())?);
}
if lints.is_empty() {
return Err("no lints were found!".into());
}
Ok(lints)
}
/// Collects all lints from the given file.
fn lints_from_file(path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
let mut lints = Vec::new();
let contents = fs::read_to_string(path)
.map_err(|e| format!("could not read {}: {}", path.display(), e))?;
let mut lines = contents.lines().enumerate();
loop {
// Find a lint declaration.
let lint_start = loop {
match lines.next() {
Some((lineno, line)) => {
if line.trim().starts_with("declare_lint!") {
break lineno + 1;
}
}
None => return Ok(lints),
}
};
// Read the lint.
let mut doc_lines = Vec::new();
let (doc, name) = loop {
match lines.next() {
Some((lineno, line)) => {
let line = line.trim();
if line.starts_with("/// ") {
doc_lines.push(line.trim()[4..].to_string());
} else if line.starts_with("///") {
doc_lines.push("".to_string());
} else if line.starts_with("// ") {
// Ignore comments.
continue;
} else {
let name = lint_name(line).map_err(|e| {
format!(
"could not determine lint name in {}:{}: {}, line was `{}`",
path.display(),
lineno,
e,
line
)
})?;
if doc_lines.is_empty() {
return Err(format!(
"did not find doc lines for lint `{}` in {}",
name,
path.display()
)
.into());
}
break (doc_lines, name);
}
}
None => {
return Err(format!(
"unexpected EOF for lint definition at {}:{}",
path.display(),
lint_start
)
.into());
}
}
};
// These lints are specifically undocumented. This should be reserved
// for internal rustc-lints only.
if name == "deprecated_in_future" {
continue;
}
// Read the level.
let level = loop {
match lines.next() {
// Ignore comments.
Some((_, line)) if line.trim().starts_with("// ") => {}
Some((lineno, line)) => match line.trim() {
"Allow," => break Level::Allow,
"Warn," => break Level::Warn,
"Deny," => break Level::Deny,
_ => {
return Err(format!(
"unexpected lint level `{}` in {}:{}",
line,
path.display(),
lineno
)
.into());
}
},
None => {
return Err(format!(
"expected lint level in {}:{}, got EOF",
path.display(),
lint_start
)
.into());
}
}
};
// The rest of the lint definition is ignored.
assert!(!doc.is_empty());
lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start });
}
}
/// Extracts the lint name (removing the visibility modifier, and checking validity).
fn lint_name(line: &str) -> Result<String, &'static str> {
// Skip over any potential `pub` visibility.
match line.trim().split(' ').next_back() {
Some(name) => {
if !name.ends_with(',') {
return Err("lint name should end with comma");
}
let name = &name[..name.len() - 1];
if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() {
return Err("lint name did not have expected format");
}
Ok(name.to_lowercase().to_string())
}
None => Err("could not find lint name"),
}
}
/// Mutates the lint definition to replace the `{{produces}}` marker with the
/// actual output from the compiler.
fn generate_output_example(
lint: &mut Lint,
rustc_path: &Path,
verbose: bool,
) -> Result<(), Box<dyn Error>> {
// Explicit list of lints that are allowed to not have an example. Please
// try to avoid adding to this list.
if matches!(
lint.name.as_str(),
"unused_features" // broken lint
| "unstable_features" // deprecated
) {
return Ok(());
}
if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") {
// Rustdoc lints are documented in the rustdoc book, don't check these.
return Ok(());
}
check_style(lint)?;
// Unfortunately some lints have extra requirements that this simple test
// setup can't handle (like extern crates). An alternative is to use a
// separate test suite, and use an include mechanism such as mdbook's
// `{{#rustdoc_include}}`.
if !lint.is_ignored() {
replace_produces(lint, rustc_path, verbose)?;
}
Ok(())
}
/// Checks the doc style of the lint.
fn check_style(lint: &Lint) -> Result<(), Box<dyn Error>> {
for &expected in &["### Example", "### Explanation", "{{produces}}"] {
if expected == "{{produces}}" && lint.is_ignored() {
continue;
}
if !lint.doc_contains(expected) {
return Err(format!("lint docs should contain the line `{}`", expected).into());
}
}
if let Some(first) = lint.doc.first() {
if !first.starts_with(&format!("The `{}` lint", lint.name)) {
return Err(format!(
"lint docs should start with the text \"The `{}` lint\" to introduce the lint",
lint.name
)
.into());
}
}
Ok(())
}
/// Mutates the lint docs to replace the `{{produces}}` marker with the actual
/// output from the compiler.
fn replace_produces(
lint: &mut Lint,
rustc_path: &Path,
verbose: bool,
) -> Result<(), Box<dyn Error>> {
let mut lines = lint.doc.iter_mut();
loop {
// Find start of example.
let options = loop {
match lines.next() {
Some(line) if line.starts_with("```rust") => {
break line[7..].split(',').collect::<Vec<_>>();
}
Some(line) if line.contains("{{produces}}") => {
return Err("lint marker {{{{produces}}}} found, \
but expected to immediately follow a rust code block"
.into());
}
Some(_) => {}
None => return Ok(()),
}
};
// Find the end of example.
let mut example = Vec::new();
loop {
match lines.next() {
Some(line) if line == "```" => break,
Some(line) => example.push(line),
None => {
return Err(format!(
"did not find end of example triple ticks ```, docs were:\n{:?}",
lint.doc
)
.into());
}
}
}
// Find the {{produces}} line.
loop {
match lines.next() {
Some(line) if line.is_empty() => {}
Some(line) if line == "{{produces}}" => {
let output =
generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?;
line.replace_range(
..,
&format!(
"This will produce:\n\
\n\
```text\n\
{}\
```",
output
),
);
break;
}
// No {{produces}} after example, find next example.
Some(_line) => break,
None => return Ok(()),
}
}
}
}
/// Runs the compiler against the example, and extracts the output.
fn generate_lint_output(
name: &str,
example: &[&mut String],
options: &[&str],
rustc_path: &Path,
verbose: bool,
) -> Result<String, Box<dyn Error>> {
if verbose {
eprintln!("compiling lint {}", name);
}
let tempdir = tempfile::TempDir::new()?;
let tempfile = tempdir.path().join("lint_example.rs");
let mut source = String::new();
let needs_main = !example.iter().any(|line| line.contains("fn main"));
// Remove `# ` prefix for hidden lines.
let unhidden =
example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line });
let mut lines = unhidden.peekable();
while let Some(line) = lines.peek() {
if line.starts_with("#!") {
source.push_str(line);
source.push('\n');
lines.next();
} else {
break;
}
}
if needs_main {
source.push_str("fn main() {\n");
}
for line in lines {
source.push_str(line);
source.push('\n')
}
if needs_main {
source.push_str("}\n");
}
fs::write(&tempfile, source)
.map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
let mut cmd = Command::new(rustc_path);
if options.contains(&"edition2015") {
cmd.arg("--edition=2015");
} else {
cmd.arg("--edition=2018");
}
cmd.arg("--error-format=json");
if options.contains(&"test") {
cmd.arg("--test");
}
cmd.arg("lint_example.rs");
cmd.current_dir(tempdir.path());
let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
let stderr = std::str::from_utf8(&output.stderr).unwrap();
let msgs = stderr
.lines()
.filter(|line| line.starts_with('{'))
.map(serde_json::from_str)
.collect::<Result<Vec<serde_json::Value>, _>>()?;
match msgs
.iter()
.find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
{
Some(msg) => {
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
Ok(rendered.to_string())
}
None => {
match msgs.iter().find(
|msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
) {
Some(msg) => {
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
Ok(rendered.to_string())
}
None => {
let rendered: Vec<&str> =
msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
Err(format!(
"did not find lint `{}` in output of example, got:\n{}",
name,
rendered.join("\n")
)
.into())
}
}
}
}
}
static ALLOWED_MD: &str = r#"# Allowed-by-default lints
These lints are all set to the 'allow' level by default. As such, they won't show up
unless you set them to a higher lint level with a flag or attribute.
"#;
static WARN_MD: &str = r#"# Warn-by-default lints
These lints are all set to the 'warn' level by default.
"#;
static DENY_MD: &str = r#"# Deny-by-default lints
These lints are all set to the 'deny' level by default.
"#;
/// Saves the mdbook lint chapters at the given path.
fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box<dyn Error>> {
save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?;
save_level(lints, Level::Warn, out_dir, WARN_MD)?;
save_level(lints, Level::Deny, out_dir, DENY_MD)?;
Ok(())
}
fn save_level(
lints: &[Lint],
level: Level,
out_dir: &Path,
header: &str,
) -> Result<(), Box<dyn Error>> {
let mut result = String::new();
result.push_str(header);
let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
these_lints.sort_unstable_by_key(|lint| &lint.name);
for lint in &these_lints {
write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
}
result.push('\n');
for lint in &these_lints {
write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
for line in &lint.doc {
result.push_str(line);
result.push('\n');
}
result.push('\n');
}
let out_path = out_dir.join(level.doc_filename());
// Delete the output because rustbuild uses hard links in its copies.
let _ = fs::remove_file(&out_path);
fs::write(&out_path, result)
.map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
Ok(())
}

View File

@ -0,0 +1,56 @@
use std::error::Error;
use std::path::PathBuf;
fn main() {
if let Err(e) = doit() {
println!("error: {}", e);
std::process::exit(1);
}
}
fn doit() -> Result<(), Box<dyn Error>> {
let mut args = std::env::args().skip(1);
let mut src_path = None;
let mut out_path = None;
let mut rustc_path = None;
let mut verbose = false;
while let Some(arg) = args.next() {
match arg.as_str() {
"--src" => {
src_path = match args.next() {
Some(s) => Some(PathBuf::from(s)),
None => return Err("--src requires a value".into()),
};
}
"--out" => {
out_path = match args.next() {
Some(s) => Some(PathBuf::from(s)),
None => return Err("--out requires a value".into()),
};
}
"--rustc" => {
rustc_path = match args.next() {
Some(s) => Some(PathBuf::from(s)),
None => return Err("--rustc requires a value".into()),
};
}
"-v" | "--verbose" => verbose = true,
s => return Err(format!("unexpected argument `{}`", s).into()),
}
}
if src_path.is_none() {
return Err("--src must be specified to the directory with the compiler source".into());
}
if out_path.is_none() {
return Err("--out must be specified to the directory with the lint listing docs".into());
}
if rustc_path.is_none() {
return Err("--rustc must be specified to the path of rustc".into());
}
lint_docs::extract_lint_docs(
&src_path.unwrap(),
&out_path.unwrap(),
&rustc_path.unwrap(),
verbose,
)
}