1144 lines
66 KiB
HTML
1144 lines
66 KiB
HTML
<!DOCTYPE HTML>
|
||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||
<head>
|
||
<!-- Book generated using mdBook -->
|
||
<meta charset="UTF-8">
|
||
<title>Errors and lints - Rust Compiler Development Guide</title>
|
||
|
||
|
||
<!-- Custom HTML head -->
|
||
|
||
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="theme-color" content="#ffffff">
|
||
|
||
<link rel="icon" href="favicon.svg">
|
||
<link rel="shortcut icon" href="favicon.png">
|
||
<link rel="stylesheet" href="css/variables.css">
|
||
<link rel="stylesheet" href="css/general.css">
|
||
<link rel="stylesheet" href="css/chrome.css">
|
||
<link rel="stylesheet" href="css/print.css" media="print">
|
||
|
||
<!-- Fonts -->
|
||
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||
<link rel="stylesheet" href="fonts/fonts.css">
|
||
|
||
<!-- Highlight.js Stylesheets -->
|
||
<link rel="stylesheet" id="highlight-css" href="highlight.css">
|
||
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
|
||
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
|
||
|
||
<!-- Custom theme stylesheets -->
|
||
|
||
|
||
<!-- Provide site root and default themes to javascript -->
|
||
<script>
|
||
const path_to_root = "";
|
||
const default_light_theme = "light";
|
||
const default_dark_theme = "navy";
|
||
</script>
|
||
<!-- Start loading toc.js asap -->
|
||
<script src="toc.js"></script>
|
||
</head>
|
||
<body>
|
||
<div id="body-container">
|
||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||
<script>
|
||
try {
|
||
let theme = localStorage.getItem('mdbook-theme');
|
||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
||
|
||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||
}
|
||
|
||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||
}
|
||
} catch (e) { }
|
||
</script>
|
||
|
||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||
<script>
|
||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
||
let theme;
|
||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||
const html = document.documentElement;
|
||
html.classList.remove('light')
|
||
html.classList.add(theme);
|
||
html.classList.add("js");
|
||
</script>
|
||
|
||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||
|
||
<!-- Hide / unhide sidebar before it is displayed -->
|
||
<script>
|
||
let sidebar = null;
|
||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||
if (document.body.clientWidth >= 1080) {
|
||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||
sidebar = sidebar || 'visible';
|
||
} else {
|
||
sidebar = 'hidden';
|
||
}
|
||
sidebar_toggle.checked = sidebar === 'visible';
|
||
html.classList.remove('sidebar-visible');
|
||
html.classList.add("sidebar-" + sidebar);
|
||
</script>
|
||
|
||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||
<!-- populated by js -->
|
||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||
<noscript>
|
||
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
|
||
</noscript>
|
||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||
<div class="sidebar-resize-indicator"></div>
|
||
</div>
|
||
</nav>
|
||
|
||
<div id="page-wrapper" class="page-wrapper">
|
||
|
||
<div class="page">
|
||
<div id="menu-bar-hover-placeholder"></div>
|
||
<div id="menu-bar" class="menu-bar sticky">
|
||
<div class="left-buttons">
|
||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||
<i class="fa fa-bars"></i>
|
||
</label>
|
||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||
<i class="fa fa-paint-brush"></i>
|
||
</button>
|
||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||
</ul>
|
||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||
<i class="fa fa-search"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<h1 class="menu-title">Rust Compiler Development Guide</h1>
|
||
|
||
<div class="right-buttons">
|
||
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||
<i id="print-button" class="fa fa-print"></i>
|
||
</a>
|
||
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
|
||
<i id="git-repository-button" class="fa fa-github"></i>
|
||
</a>
|
||
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/master/src/diagnostics.md" title="Suggest an edit" aria-label="Suggest an edit">
|
||
<i id="git-edit-button" class="fa fa-edit"></i>
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div id="search-wrapper" class="hidden">
|
||
<form id="searchbar-outer" class="searchbar-outer">
|
||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||
</form>
|
||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||
<div id="searchresults-header" class="searchresults-header"></div>
|
||
<ul id="searchresults">
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||
<script>
|
||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||
});
|
||
</script>
|
||
|
||
<div id="content" class="content">
|
||
<main>
|
||
<h1 id="errors-and-lints"><a class="header" href="#errors-and-lints">Errors and lints</a></h1>
|
||
<ul>
|
||
<li><a href="#diagnostic-structure">Diagnostic structure</a>
|
||
<ul>
|
||
<li><a href="#error-codes-and-explanations">Error codes and explanations</a></li>
|
||
<li><a href="#lints-versus-fixed-diagnostics">Lints versus fixed diagnostics</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#diagnostic-output-style-guide">Diagnostic output style guide</a>
|
||
<ul>
|
||
<li><a href="#lint-naming">Lint naming</a></li>
|
||
<li><a href="#diagnostic-levels">Diagnostic levels</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#helpful-tips-and-options">Helpful tips and options</a>
|
||
<ul>
|
||
<li><a href="#finding-the-source-of-errors">Finding the source of errors</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#span"><code>Span</code></a></li>
|
||
<li><a href="#error-messages">Error messages</a></li>
|
||
<li><a href="#suggestions">Suggestions</a>
|
||
<ul>
|
||
<li><a href="#suggestion-style-guide">Suggestion Style Guide</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#lints">Lints</a>
|
||
<ul>
|
||
<li><a href="#when-do-lints-run">When do lints run?</a></li>
|
||
<li><a href="#lint-definition-terms">Lint definition terms</a></li>
|
||
<li><a href="#declaring-a-lint">Declaring a lint</a></li>
|
||
<li><a href="#edition-gated-lints">Edition-gated lints</a></li>
|
||
<li><a href="#feature-gated-lints">Feature-gated lints</a></li>
|
||
<li><a href="#future-incompatible-lints">Future-incompatible lints</a></li>
|
||
<li><a href="#renaming-or-removing-a-lint">Renaming or removing a lint</a></li>
|
||
<li><a href="#lint-groups">Lint groups</a></li>
|
||
<li><a href="#linting-early-in-the-compiler">Linting early in the compiler</a>
|
||
<ul>
|
||
<li><a href="#linting-even-earlier-in-the-compiler">Linting even earlier in the compiler</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#json-diagnostic-output">JSON diagnostic output</a></li>
|
||
<li><a href="#rustc_on_unimplemented"><code>#[rustc_on_unimplemented]</code></a>
|
||
<ul>
|
||
<li><a href="#filtering">Filtering</a></li>
|
||
<li><a href="#formatting">Formatting</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>A lot of effort has been put into making <code>rustc</code> have great error messages.
|
||
This chapter is about how to emit compile errors and lints from the compiler.</p>
|
||
<h2 id="diagnostic-structure"><a class="header" href="#diagnostic-structure">Diagnostic structure</a></h2>
|
||
<p>The main parts of a diagnostic error are the following:</p>
|
||
<pre><code>error[E0000]: main error message
|
||
--> file.rs:LL:CC
|
||
|
|
||
LL | <code>
|
||
| -^^^^- secondary label
|
||
| |
|
||
| primary label
|
||
|
|
||
= note: note without a `Span`, created with `.note`
|
||
note: sub-diagnostic message for `.span_note`
|
||
--> file.rs:LL:CC
|
||
|
|
||
LL | more code
|
||
| ^^^^
|
||
</code></pre>
|
||
<ul>
|
||
<li>Level (<code>error</code>, <code>warning</code>, etc.). It indicates the severity of the message.
|
||
(See <a href="#diagnostic-levels">diagnostic levels</a>)</li>
|
||
<li>Code (for example, for "mismatched types", it is <code>E0308</code>). It helps
|
||
users get more information about the current error through an extended
|
||
description of the problem in the error code index. Not all diagnostic have a
|
||
code. For example, diagnostics created by lints don't have one.</li>
|
||
<li>Message. It is the main description of the problem. It should be general and
|
||
able to stand on its own, so that it can make sense even in isolation.</li>
|
||
<li>Diagnostic window. This contains several things:
|
||
<ul>
|
||
<li>The path, line number and column of the beginning of the primary span.</li>
|
||
<li>The users' affected code and its surroundings.</li>
|
||
<li>Primary and secondary spans underlying the users' code. These spans can
|
||
optionally contain one or more labels.
|
||
<ul>
|
||
<li>Primary spans should have enough text to describe the problem in such a
|
||
way that if it were the only thing being displayed (for example, in an
|
||
IDE) it would still make sense. Because it is "spatially aware" (it
|
||
points at the code), it can generally be more succinct than the error
|
||
message.</li>
|
||
<li>If cluttered output can be foreseen in cases when multiple span labels
|
||
overlap, it is a good idea to tweak the output appropriately. For
|
||
example, the <code>if/else arms have incompatible types</code> error uses different
|
||
spans depending on whether the arms are all in the same line, if one of
|
||
the arms is empty and if none of those cases applies.</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>Sub-diagnostics. Any error can have multiple sub-diagnostics that look
|
||
similar to the main part of the error. These are used for cases where the
|
||
order of the explanation might not correspond with the order of the code. If
|
||
the order of the explanation can be "order free", leveraging secondary labels
|
||
in the main diagnostic is preferred, as it is typically less verbose.</li>
|
||
</ul>
|
||
<p>The text should be matter of fact and avoid capitalization and periods, unless
|
||
multiple sentences are <em>needed</em>:</p>
|
||
<pre><code class="language-txt">error: the fobrulator needs to be krontrificated
|
||
</code></pre>
|
||
<p>When code or an identifier must appear in a message or label, it should be
|
||
surrounded with backticks:</p>
|
||
<pre><code class="language-txt">error: the identifier `foo.bar` is invalid
|
||
</code></pre>
|
||
<h3 id="error-codes-and-explanations"><a class="header" href="#error-codes-and-explanations">Error codes and explanations</a></h3>
|
||
<p>Most errors have an associated error code. Error codes are linked to long-form
|
||
explanations which contains an example of how to trigger the error and in-depth
|
||
details about the error. They may be viewed with the <code>--explain</code> flag, or via
|
||
the <a href="https://doc.rust-lang.org/error-index.html">error index</a>.</p>
|
||
<p>As a general rule, give an error a code (with an associated explanation) if the
|
||
explanation would give more information than the error itself. A lot of the time
|
||
it's better to put all the information in the emitted error itself. However,
|
||
sometimes that would make the error verbose or there are too many possible
|
||
triggers to include useful information for all cases in the error, in which case
|
||
it's a good idea to add an explanation.<sup class="footnote-reference" id="fr-estebank-1"><a href="#footnote-estebank">1</a></sup>
|
||
As always, if you are not sure, just ask your reviewer!</p>
|
||
<p>If you decide to add a new error with an associated error code, please read
|
||
<a href="./diagnostics/error-codes.html">this section</a> for a guide and important details about the
|
||
process.</p>
|
||
<h3 id="lints-versus-fixed-diagnostics"><a class="header" href="#lints-versus-fixed-diagnostics">Lints versus fixed diagnostics</a></h3>
|
||
<p>Some messages are emitted via <a href="#lints">lints</a>, where the user can control the
|
||
level. Most diagnostics are hard-coded such that the user cannot control the
|
||
level.</p>
|
||
<p>Usually it is obvious whether a diagnostic should be "fixed" or a lint, but
|
||
there are some grey areas.</p>
|
||
<p>Here are a few examples:</p>
|
||
<ul>
|
||
<li>Borrow checker errors: these are fixed errors. The user cannot adjust the
|
||
level of these diagnostics to silence the borrow checker.</li>
|
||
<li>Dead code: this is a lint. While the user probably doesn't want dead code in
|
||
their crate, making this a hard error would make refactoring and development
|
||
very painful.</li>
|
||
<li><a href="#future-incompatible-lints">future-incompatible lints</a>:
|
||
these are silenceable lints.
|
||
It was decided that making them fixed errors would cause too much breakage,
|
||
so warnings are instead emitted,
|
||
and will eventually be turned into fixed (hard) errors.</li>
|
||
</ul>
|
||
<p>Hard-coded warnings (those using methods like <code>span_warn</code>) should be avoided
|
||
for normal code, preferring to use lints instead. Some cases, such as warnings
|
||
with CLI flags, will require the use of hard-coded warnings.</p>
|
||
<p>See the <code>deny</code> <a href="#diagnostic-levels">lint level</a> below for guidelines when to
|
||
use an error-level lint instead of a fixed error.</p>
|
||
<h2 id="diagnostic-output-style-guide"><a class="header" href="#diagnostic-output-style-guide">Diagnostic output style guide</a></h2>
|
||
<ul>
|
||
<li>Write in plain simple English. If your message, when shown on a – possibly
|
||
small – screen (which hasn't been cleaned for a while), cannot be understood
|
||
by a normal programmer, who just came out of bed after a night partying,
|
||
it's too complex.</li>
|
||
<li><code>Error</code>, <code>Warning</code>, <code>Note</code>, and <code>Help</code> messages start with a lowercase
|
||
letter and do not end with punctuation.</li>
|
||
<li>Error messages should be succinct. Users will see these error messages many
|
||
times, and more verbose descriptions can be viewed with the <code>--explain</code>
|
||
flag. That said, don't make it so terse that it's hard to understand.</li>
|
||
<li>The word "illegal" is illegal. Prefer "invalid" or a more specific word
|
||
instead.</li>
|
||
<li>Errors should document the span of code where they occur (use
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html"><code>rustc_errors::DiagCtxt</code></a>'s
|
||
<code>span_*</code> methods or a diagnostic struct's <code>#[primary_span]</code> to easily do
|
||
this). Also <code>note</code> other spans that have contributed to the error if the span
|
||
isn't too large.</li>
|
||
<li>When emitting a message with span, try to reduce the span to the smallest
|
||
amount possible that still signifies the issue</li>
|
||
<li>Try not to emit multiple error messages for the same error. This may require
|
||
detecting duplicates.</li>
|
||
<li>When the compiler has too little information for a specific error message,
|
||
consult with the compiler team to add new attributes for library code that
|
||
allow adding more information. For example see
|
||
<a href="#rustc_on_unimplemented"><code>#[rustc_on_unimplemented]</code></a>. Use these
|
||
annotations when available!</li>
|
||
<li>Keep in mind that Rust's learning curve is rather steep, and that the
|
||
compiler messages are an important learning tool.</li>
|
||
<li>When talking about the compiler, call it <code>the compiler</code>, not <code>Rust</code> or
|
||
<code>rustc</code>.</li>
|
||
<li>Use the <a href="https://en.wikipedia.org/wiki/Serial_comma">Oxford comma</a> when
|
||
writing lists of items.</li>
|
||
</ul>
|
||
<h3 id="lint-naming"><a class="header" href="#lint-naming">Lint naming</a></h3>
|
||
<p>From <a href="https://github.com/rust-lang/rfcs/blob/master/text/0344-conventions-galore.md#lints">RFC 0344</a>, lint names should be consistent, with the following
|
||
guidelines:</p>
|
||
<p>The basic rule is: the lint name should make sense when read as "allow
|
||
<em>lint-name</em>" or "allow <em>lint-name</em> items". For example, "allow
|
||
<code>deprecated</code> items" and "allow <code>dead_code</code>" makes sense, while "allow
|
||
<code>unsafe_block</code>" is ungrammatical (should be plural).</p>
|
||
<ul>
|
||
<li>
|
||
<p>Lint names should state the bad thing being checked for, e.g. <code>deprecated</code>,
|
||
so that <code>#[allow(deprecated)]</code> (items) reads correctly. Thus <code>ctypes</code> is not
|
||
an appropriate name; <code>improper_ctypes</code> is.</p>
|
||
</li>
|
||
<li>
|
||
<p>Lints that apply to arbitrary items (like the stability lints) should just
|
||
mention what they check for: use <code>deprecated</code> rather than
|
||
<code>deprecated_items</code>. This keeps lint names short. (Again, think "allow
|
||
<em>lint-name</em> items".)</p>
|
||
</li>
|
||
<li>
|
||
<p>If a lint applies to a specific grammatical class, mention that class and
|
||
use the plural form: use <code>unused_variables</code> rather than <code>unused_variable</code>.
|
||
This makes <code>#[allow(unused_variables)]</code> read correctly.</p>
|
||
</li>
|
||
<li>
|
||
<p>Lints that catch unnecessary, unused, or useless aspects of code should use
|
||
the term <code>unused</code>, e.g. <code>unused_imports</code>, <code>unused_typecasts</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>Use snake case in the same way you would for function names.</p>
|
||
</li>
|
||
</ul>
|
||
<h3 id="diagnostic-levels"><a class="header" href="#diagnostic-levels">Diagnostic levels</a></h3>
|
||
<p>Guidelines for different diagnostic levels:</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>error</code>: emitted when the compiler detects a problem that makes it unable to
|
||
compile the program, either because the program is invalid or the programmer
|
||
has decided to make a specific <code>warning</code> into an error.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>warning</code>: emitted when the compiler detects something odd about a program.
|
||
Care should be taken when adding warnings to avoid warning fatigue, and
|
||
avoid false-positives where there really isn't a problem with the code. Some
|
||
examples of when it is appropriate to issue a warning:</p>
|
||
<ul>
|
||
<li>A situation where the user <em>should</em> take action, such as swap out a
|
||
deprecated item, or use a <code>Result</code>, but otherwise doesn't prevent
|
||
compilation.</li>
|
||
<li>Unnecessary syntax that can be removed without affecting the semantics of
|
||
the code. For example, unused code, or unnecessary <code>unsafe</code>.</li>
|
||
<li>Code that is very likely to be incorrect, dangerous, or confusing, but the
|
||
language technically allows, and is not ready or confident enough to make
|
||
an error. For example <code>unused_comparisons</code> (out of bounds comparisons) or
|
||
<code>bindings_with_variant_name</code> (the user likely did not intend to create a
|
||
binding in a pattern).</li>
|
||
<li><a href="#future-incompatible">Future-incompatible lints</a>, where something was
|
||
accidentally or erroneously accepted in the past, but rejecting would
|
||
cause excessive breakage in the ecosystem.</li>
|
||
<li>Stylistic choices. For example, camel or snake case, or the <code>dyn</code> trait
|
||
warning in the 2018 edition. These have a high bar to be added, and should
|
||
only be used in exceptional circumstances. Other stylistic choices should
|
||
either be allow-by-default lints, or part of other tools like Clippy or
|
||
rustfmt.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><code>help</code>: emitted following an <code>error</code> or <code>warning</code> to give additional
|
||
information to the user about how to solve their problem. These messages
|
||
often include a suggestion string and <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html"><code>rustc_errors::Applicability</code></a>
|
||
confidence level to guide automated source fixes by tools. See the
|
||
<a href="#suggestions">Suggestions</a> section for more details.</p>
|
||
<p>The error or warning portion should <em>not</em> suggest how to fix the problem,
|
||
only the "help" sub-diagnostic should.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>note</code>: emitted to given more context and identify additional circumstances
|
||
and parts of the code that caused the warning or error. For example, the
|
||
borrow checker will note any previous conflicting borrows.</p>
|
||
<p><code>help</code> vs <code>note</code>: <code>help</code> should be used to show changes the user can
|
||
possibly make to fix the problem. <code>note</code> should be used for everything else,
|
||
such as other context, information and facts, online resources to read, etc.</p>
|
||
</li>
|
||
</ul>
|
||
<p>Not to be confused with <em>lint levels</em>, whose guidelines are:</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>forbid</code>: Lints should never default to <code>forbid</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>deny</code>: Equivalent to <code>error</code> diagnostic level. Some examples:</p>
|
||
<ul>
|
||
<li>A future-incompatible or edition-based lint that has graduated from the
|
||
warning level.</li>
|
||
<li>Something that has an extremely high confidence that is incorrect, but
|
||
still want an escape hatch to allow it to pass.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><code>warn</code>: Equivalent to the <code>warning</code> diagnostic level. See <code>warning</code> above
|
||
for guidelines.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>allow</code>: Examples of the kinds of lints that should default to <code>allow</code>:</p>
|
||
<ul>
|
||
<li>The lint has a too high false positive rate.</li>
|
||
<li>The lint is too opinionated.</li>
|
||
<li>The lint is experimental.</li>
|
||
<li>The lint is used for enforcing something that is not normally enforced.
|
||
For example, the <code>unsafe_code</code> lint can be used to prevent usage of unsafe
|
||
code.</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>More information about lint levels can be found in the <a href="https://doc.rust-lang.org/nightly/rustc/lints/levels.html">rustc
|
||
book</a> and the <a href="https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#lint-check-attributes">reference</a>.</p>
|
||
<h2 id="helpful-tips-and-options"><a class="header" href="#helpful-tips-and-options">Helpful tips and options</a></h2>
|
||
<h3 id="finding-the-source-of-errors"><a class="header" href="#finding-the-source-of-errors">Finding the source of errors</a></h3>
|
||
<p>There are three main ways to find where a given error is emitted:</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>grep</code> for either a sub-part of the error message/label or error code. This
|
||
usually works well and is straightforward, but there are some cases where
|
||
the code emitting the error is removed from the code where the error is
|
||
constructed behind a relatively deep call-stack. Even then, it is a good way
|
||
to get your bearings.</p>
|
||
</li>
|
||
<li>
|
||
<p>Invoking <code>rustc</code> with the nightly-only flag <code>-Z treat-err-as-bug=1</code>
|
||
will treat the first error being emitted as an Internal Compiler Error, which
|
||
allows you to get a
|
||
stack trace at the point the error has been emitted. Change the <code>1</code> to
|
||
something else if you wish to trigger on a later error.</p>
|
||
<p>There are limitations with this approach:</p>
|
||
<ul>
|
||
<li>Some calls get elided from the stack trace because they get inlined in the compiled <code>rustc</code>.</li>
|
||
<li>The <em>construction</em> of the error is far away from where it is <em>emitted</em>,
|
||
a problem similar to the one we faced with the <code>grep</code> approach.
|
||
In some cases, we buffer multiple errors in order to emit them in order.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Invoking <code>rustc</code> with <code>-Z track-diagnostics</code> will print error creation
|
||
locations alongside the error.</p>
|
||
</li>
|
||
</ul>
|
||
<p>The regular development practices apply: judicious use of <code>debug!()</code> statements
|
||
and use of a debugger to trigger break points in order to figure out in what
|
||
order things are happening.</p>
|
||
<h2 id="span"><a class="header" href="#span"><code>Span</code></a></h2>
|
||
<p><a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html"><code>Span</code></a> is the primary data structure in <code>rustc</code> used to represent a
|
||
location in the code being compiled. <code>Span</code>s are attached to most constructs in
|
||
HIR and MIR, allowing for more informative error reporting.</p>
|
||
<p>A <code>Span</code> can be looked up in a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html"><code>SourceMap</code></a> to get a "snippet"
|
||
useful for displaying errors with <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html#method.span_to_snippet"><code>span_to_snippet</code></a> and other
|
||
similar methods on the <code>SourceMap</code>.</p>
|
||
<h2 id="error-messages"><a class="header" href="#error-messages">Error messages</a></h2>
|
||
<p>The <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html"><code>rustc_errors</code></a> crate defines most of the utilities used for
|
||
reporting errors.</p>
|
||
<p>Diagnostics can be implemented as types which implement the <code>Diagnostic</code>
|
||
trait. This is preferred for new diagnostics as it enforces a separation
|
||
between diagnostic emitting logic and the main code paths. For less-complex
|
||
diagnostics, the <code>Diagnostic</code> trait can be derived -- see <a href="./diagnostics/diagnostic-structs.html">Diagnostic
|
||
structs</a>. Within the trait implementation, the APIs
|
||
described below can be used as normal.</p>
|
||
<p><a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html"><code>DiagCtxt</code></a> has methods that create and emit errors. These methods
|
||
usually have names like <code>span_err</code> or <code>struct_span_err</code> or <code>span_warn</code>, etc...
|
||
There are lots of them; they emit different types of "errors", such as
|
||
warnings, errors, fatal errors, suggestions, etc.</p>
|
||
<p>In general, there are two classes of such methods: ones that emit an error
|
||
directly and ones that allow finer control over what to emit. For example,
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.span_err"><code>span_err</code></a> emits the given error message at the given <code>Span</code>, but
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.struct_span_err"><code>struct_span_err</code></a> instead returns a
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html"><code>Diag</code></a>.</p>
|
||
<p>Most of these methods will accept strings, but it is recommended that typed
|
||
identifiers for translatable diagnostics be used for new diagnostics (see
|
||
<a href="./diagnostics/translation.html">Translation</a>).</p>
|
||
<p><code>Diag</code> allows you to add related notes and suggestions to an error
|
||
before emitting it by calling the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html#method.emit"><code>emit</code></a> method. (Failing to either
|
||
emit or <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html#method.cancel">cancel</a> a <code>Diag</code> will result in an ICE.) See the
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html">docs</a> for more info on what you can do.</p>
|
||
<pre><code class="language-rust ignore">// Get a `Diag`. This does _not_ emit an error yet.
|
||
let mut err = sess.dcx.struct_span_err(sp, fluent::example::example_error);
|
||
|
||
// In some cases, you might need to check if `sp` is generated by a macro to
|
||
// avoid printing weird errors about macro-generated code.
|
||
|
||
if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
|
||
// Use the snippet to generate a suggested fix
|
||
err.span_suggestion(suggestion_sp, fluent::example::try_qux_suggestion, format!("qux {}", snippet));
|
||
} else {
|
||
// If we weren't able to generate a snippet, then emit a "help" message
|
||
// instead of a concrete "suggestion". In practice this is unlikely to be
|
||
// reached.
|
||
err.span_help(suggestion_sp, fluent::example::qux_suggestion);
|
||
}
|
||
|
||
// emit the error
|
||
err.emit();</code></pre>
|
||
<pre><code class="language-fluent">example-example-error = oh no! this is an error!
|
||
.try-qux-suggestion = try using a qux here
|
||
.qux-suggestion = you could use a qux here instead
|
||
</code></pre>
|
||
<h2 id="suggestions"><a class="header" href="#suggestions">Suggestions</a></h2>
|
||
<p>In addition to telling the user exactly <em>why</em> their code is wrong, it's
|
||
oftentimes furthermore possible to tell them how to fix it. To this end,
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html"><code>Diag</code></a> offers a structured suggestions API, which formats code
|
||
suggestions pleasingly in the terminal, or (when the <code>--error-format json</code> flag
|
||
is passed) as JSON for consumption by tools like <a href="https://github.com/rust-lang/rustfix"><code>rustfix</code></a>.</p>
|
||
<p>Not all suggestions should be applied mechanically, they have a degree of
|
||
confidence in the suggested code, from high
|
||
(<code>Applicability::MachineApplicable</code>) to low (<code>Applicability::MaybeIncorrect</code>).
|
||
Be conservative when choosing the level. Use the
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html#method.span_suggestion"><code>span_suggestion</code></a> method of <code>Diag</code> to
|
||
make a suggestion. The last argument provides a hint to tools whether
|
||
the suggestion is mechanically applicable or not.</p>
|
||
<p>Suggestions point to one or more spans with corresponding code that will
|
||
replace their current content.</p>
|
||
<p>The message that accompanies them should be understandable in the following
|
||
contexts:</p>
|
||
<ul>
|
||
<li>shown as an independent sub-diagnostic (this is the default output)</li>
|
||
<li>shown as a label pointing at the affected span (this is done automatically if
|
||
some heuristics for verbosity are met)</li>
|
||
<li>shown as a <code>help</code> sub-diagnostic with no content (used for cases where the
|
||
suggestion is obvious from the text, but we still want to let tools to apply
|
||
them)</li>
|
||
<li>not shown (used for <em>very</em> obvious cases, but we still want to allow tools to
|
||
apply them)</li>
|
||
</ul>
|
||
<p>For example, to make our <code>qux</code> suggestion machine-applicable, we would do:</p>
|
||
<pre><code class="language-rust ignore">let mut err = sess.dcx.struct_span_err(sp, fluent::example::message);
|
||
|
||
if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
|
||
err.span_suggestion(
|
||
suggestion_sp,
|
||
fluent::example::try_qux_suggestion,
|
||
format!("qux {}", snippet),
|
||
Applicability::MachineApplicable,
|
||
);
|
||
} else {
|
||
err.span_help(suggestion_sp, fluent::example::qux_suggestion);
|
||
}
|
||
|
||
err.emit();</code></pre>
|
||
<p>This might emit an error like</p>
|
||
<pre><code class="language-console">$ rustc mycode.rs
|
||
error[E0999]: oh no! this is an error!
|
||
--> mycode.rs:3:5
|
||
|
|
||
3 | sad()
|
||
| ^ help: try using a qux here: `qux sad()`
|
||
|
||
error: aborting due to previous error
|
||
|
||
For more information about this error, try `rustc --explain E0999`.
|
||
</code></pre>
|
||
<p>In some cases, like when the suggestion spans multiple lines or when there are
|
||
multiple suggestions, the suggestions are displayed on their own:</p>
|
||
<pre><code class="language-console">error[E0999]: oh no! this is an error!
|
||
--> mycode.rs:3:5
|
||
|
|
||
3 | sad()
|
||
| ^
|
||
help: try using a qux here:
|
||
|
|
||
3 | qux sad()
|
||
| ^^^
|
||
|
||
error: aborting due to previous error
|
||
|
||
For more information about this error, try `rustc --explain E0999`.
|
||
</code></pre>
|
||
<p>The possible values of <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html"><code>Applicability</code></a> are:</p>
|
||
<ul>
|
||
<li><code>MachineApplicable</code>: Can be applied mechanically.</li>
|
||
<li><code>HasPlaceholders</code>: Cannot be applied mechanically because it has placeholder
|
||
text in the suggestions. For example: <code>try adding a type: `let x: <type>` </code>.</li>
|
||
<li><code>MaybeIncorrect</code>: Cannot be applied mechanically because the suggestion may
|
||
or may not be a good one.</li>
|
||
<li><code>Unspecified</code>: Cannot be applied mechanically because we don't know which
|
||
of the above cases it falls into.</li>
|
||
</ul>
|
||
<h3 id="suggestion-style-guide"><a class="header" href="#suggestion-style-guide">Suggestion Style Guide</a></h3>
|
||
<ul>
|
||
<li>
|
||
<p>Suggestions should not be a question. In particular, language like "did you
|
||
mean" should be avoided. Sometimes, it's unclear why a particular suggestion
|
||
is being made. In these cases, it's better to be upfront about what the
|
||
suggestion is.</p>
|
||
<p>Compare "did you mean: <code>Foo</code>" vs. "there is a struct with a similar name: <code>Foo</code>".</p>
|
||
</li>
|
||
<li>
|
||
<p>The message should not contain any phrases like "the following", "as shown",
|
||
etc. Use the span to convey what is being talked about.</p>
|
||
</li>
|
||
<li>
|
||
<p>The message may contain further instruction such as "to do xyz, use" or "to do
|
||
xyz, use abc".</p>
|
||
</li>
|
||
<li>
|
||
<p>The message may contain a name of a function, variable, or type, but avoid
|
||
whole expressions.</p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="lints"><a class="header" href="#lints">Lints</a></h2>
|
||
<p>The compiler linting infrastructure is defined in the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/index.html"><code>rustc_middle::lint</code></a>
|
||
module.</p>
|
||
<h3 id="when-do-lints-run"><a class="header" href="#when-do-lints-run">When do lints run?</a></h3>
|
||
<p>Different lints will run at different times based on what information the lint
|
||
needs to do its job. Some lints get grouped into <em>passes</em> where the lints
|
||
within a pass are processed together via a single visitor. Some of the passes
|
||
are:</p>
|
||
<ul>
|
||
<li>
|
||
<p>Pre-expansion pass: Works on <a href="the-parser.html">AST nodes</a> before <a href="macro-expansion.html">macro expansion</a>. This
|
||
should generally be avoided.</p>
|
||
<ul>
|
||
<li>Example: <a href="https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#keyword-idents"><code>keyword_idents</code></a> checks for identifiers that will become
|
||
keywords in future editions, but is sensitive to identifiers used in
|
||
macros.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Early lint pass: Works on <a href="the-parser.html">AST nodes</a> after <a href="macro-expansion.html">macro expansion</a> and name
|
||
resolution, just before <a href="./hir/lowering.html">AST lowering</a>. These lints are for purely
|
||
syntactical lints.</p>
|
||
<ul>
|
||
<li>Example: The <a href="https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unused-parens"><code>unused_parens</code></a> lint checks for parenthesized-expressions
|
||
in situations where they are not needed, like an <code>if</code> condition.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Late lint pass: Works on <a href="hir.html">HIR nodes</a>, towards the end of <a href="part-4-intro.html">analysis</a> (after
|
||
borrow checking, etc.). These lints have full type information available.
|
||
Most lints are late.</p>
|
||
<ul>
|
||
<li>Example: The <a href="https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#invalid-value"><code>invalid_value</code></a> lint (which checks for obviously invalid
|
||
uninitialized values) is a late lint because it needs type information to
|
||
figure out whether a type allows being left uninitialized.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>MIR pass: Works on <a href="mir/index.html">MIR nodes</a>. This isn't quite the same as other passes;
|
||
lints that work on MIR nodes have their own methods for running.</p>
|
||
<ul>
|
||
<li>Example: The <a href="https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#arithmetic-overflow"><code>arithmetic_overflow</code></a> lint is emitted when it detects a
|
||
constant value that may overflow.</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>Most lints work well via the pass systems, and they have a fairly
|
||
straightforward interface and easy way to integrate (mostly just implementing
|
||
a specific <code>check</code> function). However, some lints are easier to write when
|
||
they live on a specific code path anywhere in the compiler. For example, the
|
||
<a href="https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unused-mut"><code>unused_mut</code></a> lint is implemented in the borrow checker as it requires some
|
||
information and state in the borrow checker.</p>
|
||
<p>Some of these inline lints fire before the linting system is ready. Those
|
||
lints will be <em>buffered</em> where they are held until later phases of the
|
||
compiler when the linting system is ready. See <a href="#linting-early-in-the-compiler">Linting early in the
|
||
compiler</a>.</p>
|
||
<h3 id="lint-definition-terms"><a class="header" href="#lint-definition-terms">Lint definition terms</a></h3>
|
||
<p>Lints are managed via the <a href="diagnostics/lintstore.html"><code>LintStore</code></a> and get registered in
|
||
various ways. The following terms refer to the different classes of lints
|
||
generally based on how they are registered.</p>
|
||
<ul>
|
||
<li><em>Built-in</em> lints are defined inside the compiler source.</li>
|
||
<li><em>Driver-registered</em> lints are registered when the compiler driver is created
|
||
by an external driver. This is the mechanism used by Clippy, for example.</li>
|
||
<li><em>Tool</em> lints are lints with a path prefix like <code>clippy::</code> or <code>rustdoc::</code>.</li>
|
||
<li><em>Internal</em> lints are the <code>rustc::</code> scoped tool lints that only run on the
|
||
rustc source tree itself and are defined in the compiler source like a
|
||
regular built-in lint.</li>
|
||
</ul>
|
||
<p>More information about lint registration can be found in the <a href="diagnostics/lintstore.html">LintStore</a>
|
||
chapter.</p>
|
||
<h3 id="declaring-a-lint"><a class="header" href="#declaring-a-lint">Declaring a lint</a></h3>
|
||
<p>The built-in compiler lints are defined in the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/index.html"><code>rustc_lint</code></a>
|
||
crate. Lints that need to be implemented in other crates are defined in
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/index.html"><code>rustc_lint_defs</code></a>. You should prefer to place lints in <code>rustc_lint</code> if
|
||
possible. One benefit is that it is close to the dependency root, so it can be
|
||
much faster to work on.</p>
|
||
<p>Every lint is implemented via a <code>struct</code> that implements the <code>LintPass</code> <code>trait</code>
|
||
(you can also implement one of the more specific lint pass traits, either
|
||
<code>EarlyLintPass</code> or <code>LateLintPass</code> depending on when is best for your lint to run).
|
||
The trait implementation allows you to check certain syntactic constructs
|
||
as the linter walks the AST. You can then choose to emit lints in a
|
||
very similar way to compile errors.</p>
|
||
<p>You also declare the metadata of a particular lint via the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html"><code>declare_lint!</code></a>
|
||
macro. This macro includes the name, the default level, a short description, and some
|
||
more details.</p>
|
||
<p>Note that the lint and the lint pass must be registered with the compiler.</p>
|
||
<p>For example, the following lint checks for uses
|
||
of <code>while true { ... }</code> and suggests using <code>loop { ... }</code> instead.</p>
|
||
<pre><code class="language-rust ignore">// Declare a lint called `WHILE_TRUE`
|
||
declare_lint! {
|
||
WHILE_TRUE,
|
||
|
||
// warn-by-default
|
||
Warn,
|
||
|
||
// This string is the lint description
|
||
"suggest using `loop { }` instead of `while true { }`"
|
||
}
|
||
|
||
// This declares a struct and a lint pass, providing a list of associated lints. The
|
||
// compiler currently doesn't use the associated lints directly (e.g., to not
|
||
// run the pass or otherwise check that the pass emits the appropriate set of
|
||
// lints). However, it's good to be accurate here as it's possible that we're
|
||
// going to register the lints via the get_lints method on our lint pass (that
|
||
// this macro generates).
|
||
declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
|
||
|
||
// Helper function for `WhileTrue` lint.
|
||
// Traverse through any amount of parenthesis and return the first non-parens expression.
|
||
fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
|
||
while let ast::ExprKind::Paren(sub) = &expr.kind {
|
||
expr = sub;
|
||
}
|
||
expr
|
||
}
|
||
|
||
// `EarlyLintPass` has lots of methods. We only override the definition of
|
||
// `check_expr` for this lint because that's all we need, but you could
|
||
// override other methods for your own lint. See the rustc docs for a full
|
||
// list of methods.
|
||
impl EarlyLintPass for WhileTrue {
|
||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||
if let ast::ExprKind::While(cond, ..) = &e.kind
|
||
&& let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind
|
||
&& let ast::LitKind::Bool(true) = lit.kind
|
||
&& !lit.span.from_expansion()
|
||
{
|
||
let condition_span = cx.sess.source_map().guess_head_span(e.span);
|
||
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
|
||
lint.build(fluent::example::use_loop)
|
||
.span_suggestion_short(
|
||
condition_span,
|
||
fluent::example::suggestion,
|
||
"loop".to_owned(),
|
||
Applicability::MachineApplicable,
|
||
)
|
||
.emit();
|
||
})
|
||
}
|
||
}
|
||
}</code></pre>
|
||
<pre><code class="language-fluent">example-use-loop = denote infinite loops with `loop {"{"} ... {"}"}`
|
||
.suggestion = use `loop`
|
||
</code></pre>
|
||
<h3 id="edition-gated-lints"><a class="header" href="#edition-gated-lints">Edition-gated lints</a></h3>
|
||
<p>Sometimes we want to change the behavior of a lint in a new edition. To do this,
|
||
we just add the transition to our invocation of <code>declare_lint!</code>:</p>
|
||
<pre><code class="language-rust ignore">declare_lint! {
|
||
pub ANONYMOUS_PARAMETERS,
|
||
Allow,
|
||
"detects anonymous parameters",
|
||
Edition::Edition2018 => Warn,
|
||
}</code></pre>
|
||
<p>This makes the <code>ANONYMOUS_PARAMETERS</code> lint allow-by-default in the 2015 edition
|
||
but warn-by-default in the 2018 edition.</p>
|
||
<p>See <a href="./guides/editions.html#edition-specific-lints">Edition-specific lints</a> for more information.</p>
|
||
<h3 id="feature-gated-lints"><a class="header" href="#feature-gated-lints">Feature-gated lints</a></h3>
|
||
<p>Lints belonging to a feature should only be usable if the feature is enabled in the
|
||
crate. To support this, lint declarations can contain a feature gate like so:</p>
|
||
<pre><code class="language-rust ignore">declare_lint! {
|
||
pub SOME_LINT_NAME,
|
||
Warn,
|
||
"a new and useful, but feature gated lint",
|
||
@feature_gate = sym::feature_name;
|
||
}</code></pre>
|
||
<h3 id="future-incompatible-lints"><a class="header" href="#future-incompatible-lints">Future-incompatible lints</a></h3>
|
||
<p>The use of the term <code>future-incompatible</code> within the compiler has a slightly
|
||
broader meaning than what rustc exposes to users of the compiler.</p>
|
||
<p>Inside rustc, future-incompatible lints are for signalling to the user that code they have
|
||
written may not compile in the future. In general, future-incompatible code
|
||
exists for two reasons:</p>
|
||
<ul>
|
||
<li>The user has written unsound code that the compiler mistakenly accepted. While
|
||
it is within Rust's backwards compatibility guarantees to fix the soundness hole
|
||
(breaking the user's code), the lint is there to warn the user that this will happen
|
||
in some upcoming version of rustc <em>regardless of which edition the code uses</em>. This is the
|
||
meaning that rustc exclusively exposes to users as "future incompatible".</li>
|
||
<li>The user has written code that will either no longer compiler <em>or</em> will change
|
||
meaning in an upcoming <em>edition</em>. These are often called "edition lints" and can be
|
||
typically seen in the various "edition compatibility" lint groups (e.g., <code>rust_2021_compatibility</code>)
|
||
that are used to lint against code that will break if the user updates the crate's edition.
|
||
See <a href="guides/editions.html#migration-lints">migration lints</a> for more details.</li>
|
||
</ul>
|
||
<p>A future-incompatible lint should be declared with the <code>@future_incompatible</code>
|
||
additional "field":</p>
|
||
<pre><code class="language-rust ignore">declare_lint! {
|
||
pub ANONYMOUS_PARAMETERS,
|
||
Allow,
|
||
"detects anonymous parameters",
|
||
@future_incompatible = FutureIncompatibleInfo {
|
||
reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
|
||
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
|
||
};
|
||
}</code></pre>
|
||
<p>Notice the <code>reason</code> field which describes why the future incompatible change is happening.
|
||
This will change the diagnostic message the user receives as well as determine which
|
||
lint groups the lint is added to. In the example above, the lint is an "edition lint"
|
||
(since its "reason" is <code>EditionError</code>), signifying to the user that the use of anonymous
|
||
parameters will no longer compile in Rust 2018 and beyond.</p>
|
||
<p>Inside <a href="https://github.com/rust-lang/rust/blob/51fd129ac12d5bfeca7d216c47b0e337bf13e0c2/compiler/rustc_lint/src/context.rs#L212-L237">LintStore::register_lints</a>, lints with <code>future_incompatible</code>
|
||
fields get placed into either edition-based lint groups (if their <code>reason</code> is tied to
|
||
an edition) or into the <code>future_incompatibility</code> lint group.</p>
|
||
<p>If you need a combination of options that's not supported by the
|
||
<code>declare_lint!</code> macro, you can always change the <code>declare_lint!</code> macro
|
||
to support this.</p>
|
||
<h3 id="renaming-or-removing-a-lint"><a class="header" href="#renaming-or-removing-a-lint">Renaming or removing a lint</a></h3>
|
||
<p>If it is determined that a lint is either improperly named or no longer needed,
|
||
the lint must be registered for renaming or removal, which will trigger a warning if a user tries
|
||
to use the old lint name. To declare a rename/remove, add a line with
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_renamed"><code>store.register_renamed</code></a> or <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_removed"><code>store.register_removed</code></a> to the code of the
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html"><code>rustc_lint::register_builtins</code></a> function.</p>
|
||
<pre><code class="language-rust ignore">store.register_renamed("single_use_lifetime", "single_use_lifetimes");</code></pre>
|
||
<h3 id="lint-groups"><a class="header" href="#lint-groups">Lint groups</a></h3>
|
||
<p>Lints can be turned on in groups. These groups are declared in the
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html"><code>register_builtins</code></a> function in <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/index.html"><code>rustc_lint::lib</code></a>. The
|
||
<code>add_lint_group!</code> macro is used to declare a new group.</p>
|
||
<p>For example,</p>
|
||
<pre><code class="language-rust ignore">add_lint_group!(sess,
|
||
"nonstandard_style",
|
||
NON_CAMEL_CASE_TYPES,
|
||
NON_SNAKE_CASE,
|
||
NON_UPPER_CASE_GLOBALS);</code></pre>
|
||
<p>This defines the <code>nonstandard_style</code> group which turns on the listed lints. A
|
||
user can turn on these lints with a <code>!#[warn(nonstandard_style)]</code> attribute in
|
||
the source code, or by passing <code>-W nonstandard-style</code> on the command line.</p>
|
||
<p>Some lint groups are created automatically in <code>LintStore::register_lints</code>. For instance,
|
||
any lint declared with <code>FutureIncompatibleInfo</code> where the reason is
|
||
<code>FutureIncompatibilityReason::FutureReleaseError</code> (the default when
|
||
<code>@future_incompatible</code> is used in <code>declare_lint!</code>), will be added to
|
||
the <code>future_incompatible</code> lint group. Editions also have their own lint groups
|
||
(e.g., <code>rust_2021_compatibility</code>) automatically generated for any lints signaling
|
||
future-incompatible code that will break in the specified edition.</p>
|
||
<h3 id="linting-early-in-the-compiler"><a class="header" href="#linting-early-in-the-compiler">Linting early in the compiler</a></h3>
|
||
<p>On occasion, you may need to define a lint that runs before the linting system
|
||
has been initialized (e.g. during parsing or macro expansion). This is
|
||
problematic because we need to have computed lint levels to know whether we
|
||
should emit a warning or an error or nothing at all.</p>
|
||
<p>To solve this problem, we buffer the lints until the linting system is
|
||
processed. <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html#method.buffer_lint"><code>Session</code></a> and <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html#method.buffer_lint"><code>ParseSess</code></a> both have
|
||
<code>buffer_lint</code> methods that allow you to buffer a lint for later. The linting
|
||
system automatically takes care of handling buffered lints later.</p>
|
||
<p>Thus, to define a lint that runs early in the compilation, one defines a lint
|
||
like normal but invokes the lint with <code>buffer_lint</code>.</p>
|
||
<h4 id="linting-even-earlier-in-the-compiler"><a class="header" href="#linting-even-earlier-in-the-compiler">Linting even earlier in the compiler</a></h4>
|
||
<p>The parser (<code>rustc_ast</code>) is interesting in that it cannot have dependencies on
|
||
any of the other <code>rustc*</code> crates. In particular, it cannot depend on
|
||
<code>rustc_middle::lint</code> or <code>rustc_lint</code>, where all of the compiler linting
|
||
infrastructure is defined. That's troublesome!</p>
|
||
<p>To solve this, <code>rustc_ast</code> defines its own buffered lint type, which
|
||
<code>ParseSess::buffer_lint</code> uses. After macro expansion, these buffered lints are
|
||
then dumped into the <code>Session::buffered_lints</code> used by the rest of the compiler.</p>
|
||
<h2 id="json-diagnostic-output"><a class="header" href="#json-diagnostic-output">JSON diagnostic output</a></h2>
|
||
<p>The compiler accepts an <code>--error-format json</code> flag to output
|
||
diagnostics as JSON objects (for the benefit of tools such as <code>cargo fix</code>). It looks like this:</p>
|
||
<pre><code class="language-console">$ rustc json_error_demo.rs --error-format json
|
||
{"message":"cannot add `&str` to `{integer}`","code":{"code":"E0277","explanation":"\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail,E0277\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func<T: Foo>(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func<T: Foo>(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n\n```compile_fail,E0277\nfn some_func<T>(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func<T: fmt::Debug>(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n```\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n"},"level":"error","spans":[{"file_name":"json_error_demo.rs","byte_start":50,"byte_end":51,"line_start":4,"line_end":4,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" a + b","highlight_start":7,"highlight_end":8}],"label":"no implementation for `{integer} + &str`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the trait `std::ops::Add<&str>` is not implemented for `{integer}`","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":"error[E0277]: cannot add `&str` to `{integer}`\n --> json_error_demo.rs:4:7\n |\n4 | a + b\n | ^ no implementation for `{integer} + &str`\n |\n = help: the trait `std::ops::Add<&str>` is not implemented for `{integer}`\n\n"}
|
||
{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error\n\n"}
|
||
{"message":"For more information about this error, try `rustc --explain E0277`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0277`.\n"}
|
||
</code></pre>
|
||
<p>Note that the output is a series of lines, each of which is a JSON
|
||
object, but the series of lines taken together is, unfortunately, not
|
||
valid JSON, thwarting tools and tricks (such as <a href="https://docs.python.org/3/library/json.html#module-json.tool">piping to <code>python3 -m json.tool</code></a>)
|
||
that require such. (One speculates that this was intentional for LSP
|
||
performance purposes, so that each line/object can be sent as
|
||
it is flushed?)</p>
|
||
<p>Also note the "rendered" field, which contains the "human" output as a
|
||
string; this was introduced so that UI tests could both make use of
|
||
the structured JSON and see the "human" output (well, <em>sans</em> colors)
|
||
without having to compile everything twice.</p>
|
||
<p>The "human" readable and the json format emitter can be found under
|
||
<code>rustc_errors</code>, both were moved from the <code>rustc_ast</code> crate to the
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html">rustc_errors crate</a>.</p>
|
||
<p>The JSON emitter defines <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/json/struct.Diagnostic.html">its own <code>Diagnostic</code>
|
||
struct</a>
|
||
(and sub-structs) for the JSON serialization. Don't confuse this with
|
||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html"><code>errors::Diag</code></a>!</p>
|
||
<h2 id="rustc_on_unimplemented"><a class="header" href="#rustc_on_unimplemented"><code>#[rustc_on_unimplemented]</code></a></h2>
|
||
<p>This attribute allows trait definitions to modify error messages when an implementation was
|
||
expected but not found. The string literals in the attribute are format strings and can be
|
||
formatted with named parameters. See the Formatting
|
||
section below for what parameters are permitted.</p>
|
||
<pre><code class="language-rust ignore">#[rustc_on_unimplemented(message = "an iterator over \
|
||
elements of type `{A}` cannot be built from a \
|
||
collection of type `{Self}`")]
|
||
trait MyIterator<A> {
|
||
fn next(&mut self) -> A;
|
||
}
|
||
|
||
fn iterate_chars<I: MyIterator<char>>(i: I) {
|
||
// ...
|
||
}
|
||
|
||
fn main() {
|
||
iterate_chars(&[1, 2, 3][..]);
|
||
}</code></pre>
|
||
<p>When the user compiles this, they will see the following;</p>
|
||
<pre><code class="language-txt">error[E0277]: an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
|
||
--> src/main.rs:13:19
|
||
|
|
||
13 | iterate_chars(&[1, 2, 3][..]);
|
||
| ------------- ^^^^^^^^^^^^^^ the trait `MyIterator<char>` is not implemented for `&[{integer}]`
|
||
| |
|
||
| required by a bound introduced by this call
|
||
|
|
||
note: required by a bound in `iterate_chars`
|
||
</code></pre>
|
||
<p>You can modify the contents of:</p>
|
||
<ul>
|
||
<li>the main error message (<code>message</code>)</li>
|
||
<li>the label (<code>label</code>)</li>
|
||
<li>the note(s) (<code>note</code>)</li>
|
||
</ul>
|
||
<p>For example, the following attribute</p>
|
||
<pre><code class="language-rust ignore">#[rustc_on_unimplemented(message = "message", label = "label", note = "note")]
|
||
trait MyIterator<A> {
|
||
fn next(&mut self) -> A;
|
||
}</code></pre>
|
||
<p>Would generate the following output:</p>
|
||
<pre><code class="language-text">error[E0277]: message
|
||
--> <file>:10:19
|
||
|
|
||
10 | iterate_chars(&[1, 2, 3][..]);
|
||
| ------------- ^^^^^^^^^^^^^^ label
|
||
| |
|
||
| required by a bound introduced by this call
|
||
|
|
||
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
|
||
= note: note
|
||
note: required by a bound in `iterate_chars`
|
||
</code></pre>
|
||
<p>The functionality discussed so far is also available with
|
||
<a href="https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnosticon_unimplemented-attribute"><code>#[diagnostic::on_unimplemented]</code></a>.
|
||
If you can, you should use that instead.</p>
|
||
<h3 id="filtering"><a class="header" href="#filtering">Filtering</a></h3>
|
||
<p>To allow more targeted error messages, it is possible to filter the
|
||
application of these fields with <code>on</code>.</p>
|
||
<p>You can filter on the following boolean flags:</p>
|
||
<ul>
|
||
<li><code>crate_local</code>: whether the code causing the trait bound to not be
|
||
fulfilled is part of the user's crate. This is used to avoid suggesting
|
||
code changes that would require modifying a dependency.</li>
|
||
<li><code>direct</code>: whether this is an user-specified rather than derived obligation.</li>
|
||
<li><code>from_desugaring</code>: whether we are in some kind of desugaring, like <code>?</code>
|
||
or a <code>try</code> block for example. This flag can also be matched on, see below.</li>
|
||
</ul>
|
||
<p>You can match on the following names and values, using <code>name = "value"</code>:</p>
|
||
<ul>
|
||
<li><code>cause</code>: Match against one variant of the <code>ObligationCauseCode</code>
|
||
enum. Only <code>"MainFunctionType"</code> is supported.</li>
|
||
<li><code>from_desugaring</code>: Match against a particular variant of the <code>DesugaringKind</code>
|
||
enum. The desugaring is identified by its variant name, for example
|
||
<code>"QuestionMark"</code> for <code>?</code> desugaring or <code>"TryBlock"</code> for <code>try</code> blocks.</li>
|
||
<li><code>Self</code> and any generic arguments of the trait, like <code>Self = "alloc::string::String"</code>
|
||
or <code>Rhs="i32"</code>.</li>
|
||
</ul>
|
||
<p>The compiler can provide several values to match on, for example:</p>
|
||
<ul>
|
||
<li>the self_ty, pretty printed with and without type arguments resolved.</li>
|
||
<li><code>"{integral}"</code>, if self_ty is an integral of which the type is known.</li>
|
||
<li><code>"[]"</code>, <code>"[{ty}]"</code>, <code>"[{ty}; _]"</code>, <code>"[{ty}; $N]"</code> when applicable.</li>
|
||
<li>references to said slices and arrays.</li>
|
||
<li><code>"fn"</code>, <code>"unsafe fn"</code> or <code>"#[target_feature] fn"</code> when self is a function.</li>
|
||
<li><code>"{integer}"</code> and <code>"{float}"</code> if the type is a number but we haven't inferred it yet.</li>
|
||
<li>combinations of the above, like <code>"[{integral}; _]"</code>.</li>
|
||
</ul>
|
||
<p>For example, the <code>Iterator</code> trait can be filtered in the following way:</p>
|
||
<pre><code class="language-rust ignore">#[rustc_on_unimplemented(
|
||
on(Self = "&str", note = "call `.chars()` or `.as_bytes()` on `{Self}`"),
|
||
message = "`{Self}` is not an iterator",
|
||
label = "`{Self}` is not an iterator",
|
||
note = "maybe try calling `.iter()` or a similar method"
|
||
)]
|
||
pub trait Iterator {}</code></pre>
|
||
<p>Which would produce the following outputs:</p>
|
||
<pre><code class="language-text">error[E0277]: `Foo` is not an iterator
|
||
--> src/main.rs:4:16
|
||
|
|
||
4 | for foo in Foo {}
|
||
| ^^^ `Foo` is not an iterator
|
||
|
|
||
= note: maybe try calling `.iter()` or a similar method
|
||
= help: the trait `std::iter::Iterator` is not implemented for `Foo`
|
||
= note: required by `std::iter::IntoIterator::into_iter`
|
||
|
||
error[E0277]: `&str` is not an iterator
|
||
--> src/main.rs:5:16
|
||
|
|
||
5 | for foo in "" {}
|
||
| ^^ `&str` is not an iterator
|
||
|
|
||
= note: call `.chars()` or `.bytes() on `&str`
|
||
= help: the trait `std::iter::Iterator` is not implemented for `&str`
|
||
= note: required by `std::iter::IntoIterator::into_iter`
|
||
</code></pre>
|
||
<p>The <code>on</code> filter accepts <code>all</code>, <code>any</code> and <code>not</code> predicates similar to the <code>cfg</code> attribute:</p>
|
||
<pre><code class="language-rust ignore">#[rustc_on_unimplemented(on(
|
||
all(Self = "&str", T = "alloc::string::String"),
|
||
note = "you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
|
||
))]
|
||
pub trait From<T>: Sized {
|
||
/* ... */
|
||
}</code></pre>
|
||
<h3 id="formatting"><a class="header" href="#formatting">Formatting</a></h3>
|
||
<p>The string literals are format strings that accept parameters wrapped in braces
|
||
but positional and listed parameters and format specifiers are not accepted.
|
||
The following parameter names are valid:</p>
|
||
<ul>
|
||
<li><code>Self</code> and all generic parameters of the trait.</li>
|
||
<li><code>This</code>: the name of the trait the attribute is on, without generics.</li>
|
||
<li><code>Trait</code>: the name of the "sugared" trait. See <code>TraitRefPrintSugared</code>.</li>
|
||
<li><code>ItemContext</code>: the kind of <code>hir::Node</code> we're in, things like <code>"an async block"</code>,
|
||
<code>"a function"</code>, <code>"an async function"</code>, etc.</li>
|
||
</ul>
|
||
<p>Something like:</p>
|
||
<pre><code class="language-rust ignore">#![feature(rustc_attrs)]
|
||
|
||
#[rustc_on_unimplemented(message = "Self = `{Self}`, \
|
||
T = `{T}`, this = `{This}`, trait = `{Trait}`, \
|
||
context = `{ItemContext}`")]
|
||
pub trait From<T>: Sized {
|
||
fn from(x: T) -> Self;
|
||
}
|
||
|
||
fn main() {
|
||
let x: i8 = From::from(42_i32);
|
||
}</code></pre>
|
||
<p>Will format the message into</p>
|
||
<pre><code class="language-text">"Self = `i8`, T = `i32`, this = `From`, trait = `From<i32>`, context = `a function`"
|
||
</code></pre>
|
||
<hr>
|
||
<ol class="footnote-definition"><li id="footnote-estebank">
|
||
<p>This rule of thumb was suggested by <strong>@estebank</strong> <a href="https://github.com/rust-lang/rustc-dev-guide/pull/967#issuecomment-733218283">here</a>. <a href="#fr-estebank-1">↩</a></p>
|
||
</li>
|
||
</ol>
|
||
</main>
|
||
|
||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||
<!-- Mobile navigation buttons -->
|
||
<a rel="prev" href="rustc-driver/getting-diagnostics.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="diagnostics/diagnostic-structs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
|
||
<div style="clear: both"></div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||
<a rel="prev" href="rustc-driver/getting-diagnostics.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="diagnostics/diagnostic-structs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
</nav>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<script>
|
||
window.playground_copyable = true;
|
||
</script>
|
||
|
||
|
||
<script src="elasticlunr.min.js"></script>
|
||
<script src="mark.min.js"></script>
|
||
<script src="searcher.js"></script>
|
||
|
||
<script src="clipboard.min.js"></script>
|
||
<script src="highlight.js"></script>
|
||
<script src="book.js"></script>
|
||
|
||
<!-- Custom JS scripts -->
|
||
<script src="mermaid.min.js"></script>
|
||
<script src="mermaid-init.js"></script>
|
||
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|