54 releases (stable)

new 2.1.7 Mar 26, 2023
2.1.5 Feb 27, 2023
2.1.1 Nov 30, 2022
2.0.9 Jul 19, 2022
0.1.0-pre.3 Mar 29, 2021

#32 in Procedural macros

Download history 193/week @ 2022-12-04 224/week @ 2022-12-11 247/week @ 2022-12-18 117/week @ 2022-12-25 139/week @ 2023-01-01 146/week @ 2023-01-08 224/week @ 2023-01-15 239/week @ 2023-01-22 297/week @ 2023-01-29 333/week @ 2023-02-05 290/week @ 2023-02-12 143/week @ 2023-02-19 154/week @ 2023-02-26 143/week @ 2023-03-05 101/week @ 2023-03-12 134/week @ 2023-03-19

536 downloads per month




docs.rs documentation

This crate provides macros for creating Dylint libraries, and utilities for creating configurable libraries.



The dylint_library! macro expands to the following:

extern crate rustc_driver;

pub extern "C" fn dylint_version() -> *mut std::os::raw::c_char {

If your library uses the dylint_library! macro and the dylint-link tool, then all you should have to do is implement the register_lints function. See the examples in this repository.

declare_late_lint!, etc.

If your library contains just one lint, using declare_late_lint!, etc. can make your code more concise. Each of these macros requires the same arguments as declare_lint!, and wraps the following:

  • a call to dylint_library!
  • an implementation of the register_lints function
  • a call to declare_lint!
  • a call to declare_lint_pass!

For example, declare_late_lint!(vis NAME, Level, "description") expands to the following:


extern crate rustc_lint;
extern crate rustc_session;

pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
    lint_store.register_late_pass(|_| Box::new(Name));

rustc_session::declare_lint!(vis NAME, Level, "description");

rustc_session::declare_lint_pass!(Name => [NAME]);

declare_early_lint! and declare_pre_expansion_lint! are defined similarly.

impl_late_lint!, etc.

impl_late_lint!, etc. are like declare_late_lint!, etc. except:

  • each calls impl_lint_pass! instead of declare_lint_pass!;
  • each requires an additional argument to specify the value of the lint's LintPass structure.

That is, impl_late_lint!'s additional argument is what goes here:

    lint_store.register_late_pass(|_| Box::new(...));

An example use of impl_pre_expansion_lint! can be found in env_cargo_path in this repository.

Configurable libraries

Libraries can be configured by including a dylint.toml file in the target workspace's root directory. This crate provides the following functions for reading and parsing dylint.toml files:

A configurable library containing just one lint will typically have a lib.rs file of the following form:

dylint_linting::impl_late_lint! {

// Lint configuration
#[derive(Default, serde::Deserialize)]
struct Config {
    boolean: bool,
    strings: Vec<String>,

// Keep a copy of the configuration in the `LintPass` structure.
struct LintName {
    config: Config,

// Read the configuration from the `dylint.toml` file, or use the default configuration if
// none is present.
impl LintName {
    pub fn new() -> Self {
        Self {
            config: dylint_linting::config_or_default(env!("CARGO_PKG_NAME")),

For a concrete example of a lib.rs file with this form, see the non_local_effect_before_error_return library in this repository.

A library containing more than one lint must implement the register_lints function without relying on the above macros. If the library is configurable, then its register_lints function should include a call to dylint_linting::init_config, as in the following example:

pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
    // `init_config` or `try_init_config` must be called before `config_or_default`, `config`,
    // or `config_toml` is called.

    lint_store.register_lints(&[FIRST_LINT_NAME, SECOND_LINT_NAME]);

    lint_store.register_late_pass(|_| Box::new(LintPassName::new()));

Additional documentation on config_or_default, etc. can be found on docs.rs.


~50K SLoC