Rust (2024 edition) Module 1 – Getting started: rustup, Cargo and compiler messages
Reading rustc errors and using --explain
Read every part of a rustc error, look up its code with rustc --explain, fix errors in the order the compiler finds them, and choose lint levels.
What you will learn
- Read the parts of a rustc diagnostic: level, code, primary label, notes and help
- Find an error code's explanation with rustc --explain and the error index
- Fix errors in the order rustc reports them, using cargo check for fast feedback
- Change a warning's level with an attribute, the [lints] table or Cargo's build.warnings
Before you start
What you’ll learn · Before you start
What you will learn
- Read the parts of a rustc diagnostic: level, code, primary label, notes and help
- Find an error code's explanation with rustc --explain and the error index
- Fix errors in the order rustc reports them, using cargo check for fast feedback
- Change a warning's level with an attribute, the [lints] table or Cargo's build.warnings
Before you start
On this page
A six-line program that uses a list after handing it to another variable gets an error of 18 lines, and each part of it means something: what went wrong, where, how it came about, and one way to fix it. Rust’s compiler errors are long because they explain, and learning to read them pays off every day you write Rust.
This lesson takes one error apart, looks its code up with rustc --explain, and follows a package through three rounds
of cargo check to show why fixing one error can uncover another. Then it turns to warnings: each one names a lint: A named check that the compiler or Clippy runs on code that compiles, such as unused_variables. Its level, allow, warn, deny or forbid, decides whether it is silent, a warning or an error.,
and you decide whether that lint warns, fails the build or stays quiet.
Every rustc error has the same parts
Here is the six-line program and the error the compiler printed for it:
fn main() {
let names = vec![String::from("Asha"), String::from("Ravi")];
let roster = names;
println!("{} names", names.len());
println!("{roster:?}");
} Output (exit status 1)
Printed as an error (standard error)
error[E0382]: borrow of moved value: `names`
--> roster.rs:4:26
|
2 | let names = vec![String::from("Asha"), String::from("Ravi")];
| ----- move occurs because `names` has type `Vec<String>`, which does not implement the `Copy` trait
3 | let roster = names;
| ----- value moved here
4 | println!("{} names", names.len());
| ^^^^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
3 | let roster = names.clone();
| ++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0382`.
Recorded with rustc 1.99.0 (b940084d7) on macOS 26 arm64. To run it yourself: rustc --edition 2024 -O roster.rs && ./roster
That is a diagnostic: A message from the compiler about your code: an error, which stops the build, or a warning, which does not. It gives a level, often a code such as E0382, the place, labels on the source and, when it can, help., and every one has the same parts in the same places. Step through them on this error:
The drawing shows the whole scene; its 8 steps are listed below.
Every step as text
- Level and code. error means rustc built nothing; warning would mean it built the code anyway. E0382 is the code, the key to look the error up by.
- The message. borrow of moved value:
namessays what went wrong, and names the value it is about. - Where. The --> line gives the place the error is about: file roster.rs, line 4, column 26. Editors and terminals can jump straight there.
- The primary label. Under the code, ^^^^^ marks the exact place the message is about, with a label: value borrowed here after move. This is the line to change, or the line whose cause to find.
- Secondary labels. Lines marked ----- tell how it came about: line 2 says names is a Vec, which is not Copy, and line 3 says the value was moved there, into roster.
- The help. A help line suggests a fix and shows it as an edit: + marks what to add. Here it suggests names.clone(); whether copying is the right fix is still your decision.
- The last lines. aborting due to 1 previous error says how many errors there were, and the final line names the command for the long explanation: rustc --explain E0382.
- In reading order. Read every error the same way: code and message, place, the ^^^ label, the --- labels that explain it, then help and notes. Then decide the fix yourself.
The part to read first is the primary label, the line marked ^^^^^, because it says exactly what rustc refuses; the
----- labels then explain how the code got there. Not every error has secondary labels or a suggested edit, and some
carry their advice as = help: lines instead. This one, for two mutable references into the same list, has a note of
that kind:
fn main() {
let mut scores = vec![72, 85, 64];
let first = &mut scores[0];
let last = &mut scores[2];
*first += 5;
*last += 5;
println!("{scores:?}");
} Output (exit status 1)
Printed as an error (standard error)
error[E0499]: cannot borrow `scores` as mutable more than once at a time --> scores.rs:4:21 | 3 | let first = &mut scores[0]; | ------ first mutable borrow occurs here 4 | let last = &mut scores[2]; | ^^^^^^ second mutable borrow occurs here 5 | *first += 5; | ----------- first borrow later used here | = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0499`.
Recorded with rustc 1.99.0 (b940084d7) on macOS 26 arm64. To run it yourself: rustc --edition 2024 -O scores.rs && ./scores
The primary label marks the second &mut scores, a secondary label the first one, and another the line that still uses
the first. The = help: line names a method of the standard library made for this case, split_at_mut. Whatever the
advice, rustc only suggests: here the simplest fix is to finish with first before creating last.
Checkpoint
Check: The parts of a diagnostic
Every error code has a long explanation built into rustc
The error code is the most stable part of a diagnostic. Every code has a page in the Rust error codes index, and the
same text is built into the compiler, so rustc --explain prints it without a network connection. The last line of
every error says which command to type. Here is the explanation of the code that scores.rs received:
from session import run
# The long explanation of the error the compiler gave scores.rs.
run("""
rustc --explain E0499
""") Output
$ rustc --explain E0499 A variable was borrowed as mutable more than once. Erroneous code example: ``` let mut i = 0; let mut x = &mut i; let mut a = &mut i; x; // error: cannot borrow `i` as mutable more than once at a time ``` Please note that in Rust, you can either have many immutable references, or one mutable reference. For more details you may want to read the [References & Borrowing][references-and-borrowing] section of the Book. [references-and-borrowing]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html Example: ``` let mut i = 0; let mut x = &mut i; // ok! // or: let mut i = 0; let a = &i; // ok! let b = &i; // still ok! let c = &i; // still ok! b; a; ```
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 explain_session.py
It states the rule in one sentence, “a variable was borrowed as mutable more than once”, shows a shorter program with the same error, explains the rule behind it (many shared references, or one mutable reference), links the chapter of the Rust book that teaches it, and ends with versions that compile. The lines between triple backticks are code examples, written in Markdown as the error index pages are. Some explanations are much longer: E0382’s is over a hundred lines, with several ways to fix the error.
When the Rust project asked in its 2025 survey whether these explanations help, the result went against what the project had expected: many users find them useful. They are worth the habit, especially for a code you meet for the first time.
Checkpoint
Check: rustc --explain and the error index
Fix the first error, then check again
cargo check is the command for this loop: it runs the compiler’s checks and skips generating code, so it answers
fastest. The order of fixing matters for two reasons, and this program shows the first:
fn main() {
let prices = [40, 25, 15];
let totl: u32 = prices.iter().sum();
let tip = total / 10;
println!("bill {} with tip {}", total, tip);
} Output (exit status 1)
Printed as an error (standard error)
error[E0425]: cannot find value `total` in this scope
--> typo.rs:4:15
|
4 | let tip = total / 10;
| ^^^^^
|
help: a local variable with a similar name exists
|
4 - let tip = total / 10;
4 + let tip = totl / 10;
|
error[E0425]: cannot find value `total` in this scope
--> typo.rs:5:37
|
5 | println!("bill {} with tip {}", total, tip);
| ^^^^^
|
help: a local variable with a similar name exists
|
5 - println!("bill {} with tip {}", total, tip);
5 + println!("bill {} with tip {}", totl, tip);
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.
Recorded with rustc 1.99.0 (b940084d7) on macOS 26 arm64. To run it yourself: rustc --edition 2024 -O typo.rs && ./typo
Two errors, both E0425, and neither points at the cause: the misspelled totl on line 3, which only the help lines
name. Fixing line 3 removes both errors. Errors further down a list are often consequences of the first, so fix from the
top and check again, rather than working through a long list at once.
The second reason is that the compiler checks a program in stages. The Rust compiler development guide describes them:
it parses the code, resolves names, infers and checks types, and checks borrows on a later form of the program, before
any code is generated. A stage that finds errors usually ends the check, so the errors of later stages stay hidden until
you fix it. Step through three rounds of cargo check on one package:
The drawing shows the whole scene; its 4 steps are listed below.
Every step as text
- Round 1. The cart parses and every name resolves, but count: u32 = cart.len() mixes types: len() returns usize. rustc reports E0308 and stops before checking borrows.
- Fix and check again. Fix 1 lets count keep the usize. Nothing else changed, and cargo check runs the stages again from the start.
- Round 2. Types pass now, so the borrow checker runs for the first time and finds E0502: cart.push needs cart while first still borrows it. The error was there all along.
- Round 3. Fix 2 prints first before the push. Every stage passes, so cargo check reports nothing, and cargo run goes on to generate code and run the program.
This is the session the figure follows:
from session import run
# Fix the error rustc reports, check again, and repeat until the package is clean.
run("""
cd cart
!cargo check
# fix 1: let count = cart.len(); keeps the usize that len() returns
cp ../fixes/cart_2.rs src/main.rs
!cargo check
# fix 2: print first while it is still borrowed, push afterwards
cp ../fixes/cart_3.rs src/main.rs
cargo check
cargo run
""") Output
$ cd cart
$ cargo check
Checking cart v0.1.0 (~/cart)
error[E0308]: mismatched types
--> src/main.rs:4:22
|
4 | let count: u32 = cart.len();
| --- ^^^^^^^^^^ expected `u32`, found `usize`
| |
| expected due to this
|
help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
|
4 | let count: u32 = cart.len().try_into().unwrap();
| ++++++++++++++++++++
For more information about this error, try `rustc --explain E0308`.
error: could not compile `cart` (bin "cart") due to 1 previous error
[exit status 101]
# fix 1: let count = cart.len(); keeps the usize that len() returns
$ cp ../fixes/cart_2.rs src/main.rs
$ cargo check
Checking cart v0.1.0 (~/cart)
error[E0502]: cannot borrow `cart` as mutable because it is also borrowed as immutable
--> src/main.rs:5:5
|
3 | let first = &cart[0];
| ---- immutable borrow occurs here
4 | let count = cart.len();
5 | cart.push(String::from("lassi"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
6 | println!("{first} and {count} items");
| ----- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `cart` (bin "cart") due to 1 previous error
[exit status 101]
# fix 2: print first while it is still borrowed, push afterwards
$ cp ../fixes/cart_3.rs src/main.rs
$ cargo check
Checking cart v0.1.0 (~/cart)
Finished `dev` profile [unoptimized + debuginfo] target(s) in …
$ cargo run
Compiling cart v0.1.0 (~/cart)
Finished `dev` profile [unoptimized + debuginfo] target(s) in …
Running `target/debug/cart`
chai and 2 items
now 3 items
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rounds_session.py
The first round reported only E0308. After fix 1, the same command reported E0502, an error that had been in the code from the start, on the line right after the first. Only the third round was clean. One error became another not because the fix broke anything, but because the borrow checker could finally run.
Key idea
Fix the first error first and check again: later errors are often caused by it, and errors of later stages, such as borrow errors, appear only once the earlier stages pass.
Checkpoint
Check: Fixing errors in order
Warnings name their lint, and you choose its level
A warning means the code compiled but probably does not do what you meant. Every warning comes from a lint, a named check, and the warning names it. This program is meant to add up the marks of the students who passed, and it compiles with three warnings:
use std::fmt::Write;
// Meant to add up the marks of those who passed.
fn main() {
let mut marks = vec![72, 35, 91];
let pass_mark = 40;
let total: u32 = marks.iter().sum();
let mut report = String::new();
write!(report, "total of passing marks: {total}");
println!("{report}");
} from session import run
# Three warnings, each with its lint, and what cargo fix does about them.
run("""
cd tally
cargo check
!cargo fix
cargo fix --allow-no-vcs
cat src/main.rs
""") Output
$ cd tally
$ cargo check
Checking tally v0.1.0 (~/tally)
warning: variable does not need to be mutable
--> src/main.rs:5:9
|
5 | let mut marks = vec![72, 35, 91];
| ----^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default
warning: unused variable: `pass_mark`
--> src/main.rs:6:9
|
6 | let pass_mark = 40;
| ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_pass_mark`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
warning: unused `Result` that must be used
--> src/main.rs:9:5
|
9 | write!(report, "total of passing marks: {total}");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this `Result` may be an `Err` variant, which should be handled
= note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
help: use `let _ = ...` to ignore the resulting value
|
9 | let _ = write!(report, "total of passing marks: {total}");
| +++++++
warning: `tally` (bin "tally") generated 3 warnings (run `cargo fix --bin "tally" -p tally` to apply 2 suggestions)
Finished `dev` profile [unoptimized + debuginfo] target(s) in …
$ cargo fix
error: no VCS found for this package and `cargo fix` can potentially perform destructive changes; if you'd like to suppress this error pass `--allow-no-vcs`
[exit status 101]
$ cargo fix --allow-no-vcs
Checking tally v0.1.0 (~/tally)
Fixed src/main.rs (2 fixes)
warning: unused `Result` that must be used
--> src/main.rs:9:5
|
9 | write!(report, "total of passing marks: {total}");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this `Result` may be an `Err` variant, which should be handled
= note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
help: use `let _ = ...` to ignore the resulting value
|
9 | let _ = write!(report, "total of passing marks: {total}");
| +++++++
warning: `tally` (bin "tally") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in …
$ cat src/main.rs
use std::fmt::Write;
// Meant to add up the marks of those who passed.
fn main() {
let marks = vec![72, 35, 91];
let _pass_mark = 40;
let total: u32 = marks.iter().sum();
let mut report = String::new();
write!(report, "total of passing marks: {total}");
println!("{report}");
}
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 lints_session.py
Each note names a lint: unused_mut, unused_variables and unused_must_use, all three part of the group unused,
all “on by default”, which means at the warn level. cargo fix applies the compiler’s suggestions to the files, so it
refuses to run where no version control could undo its changes, unless you pass --allow-no-vcs. It then made 2 fixes
and left the third, because ignoring a Result is a decision, not an edit.
Look at what the fixes did. let _pass_mark silenced a warning that was pointing at a bug: the pass mark was never used,
so the total still counts the 35 of a student who failed. A warning is a question about your code, and the fixed
package answers both of its real questions: it filters by the pass mark, and it builds the report with format!,
which has no Result to ignore.
The level of a lint is yours to set. These are the five levels an attribute can set, from the weakest to the strongest;
a sixth, force-warn, exists only as a command-line option:
| Level | Effect |
|---|---|
allow |
The lint does nothing |
expect |
Quiet, but warns if the lint stops firing there |
warn |
A warning; the build goes on |
deny |
An error; the build fails |
forbid |
Like deny, and nothing inside may lower it |
Set it for one item with an attribute such as #[expect(unused_variables, reason = "used on Windows only")], for a
whole package in the [lints] table of Cargo.toml, or for every warning of a build with Cargo’s build.warnings
setting, CARGO_BUILD_WARNINGS=deny on the command line:
from session import run
# Warnings that fail the build, then the package with both bugs fixed and an ignored Result made an error.
run("""
cd tally
!CARGO_BUILD_WARNINGS=deny cargo check
cd ../tally-fixed
cat Cargo.toml
cargo check
cargo run
""") Output
$ cd tally
$ CARGO_BUILD_WARNINGS=deny cargo check
Checking tally v0.1.0 (~/tally)
warning: variable does not need to be mutable
--> src/main.rs:5:9
|
5 | let mut marks = vec![72, 35, 91];
| ----^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default
warning: unused variable: `pass_mark`
--> src/main.rs:6:9
|
6 | let pass_mark = 40;
| ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_pass_mark`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
warning: unused `Result` that must be used
--> src/main.rs:9:5
|
9 | write!(report, "total of passing marks: {total}");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this `Result` may be an `Err` variant, which should be handled
= note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
help: use `let _ = ...` to ignore the resulting value
|
9 | let _ = write!(report, "total of passing marks: {total}");
| +++++++
error: `tally` (bin "tally") generated 3 warnings (run `cargo fix --bin "tally" -p tally` to apply 2 suggestions)
error: warnings are denied by `build.warnings` configuration
[exit status 101]
$ cd ../tally-fixed
$ cat Cargo.toml
[package]
name = "tally-fixed"
version = "0.1.0"
edition = "2024"
[dependencies]
# In this package an ignored Result is an error, not a warning.
[lints.rust]
unused_must_use = "deny"
$ cargo check
Checking tally-fixed v0.1.0 (~/tally-fixed)
Finished `dev` profile [unoptimized + debuginfo] target(s) in …
$ cargo run
Compiling tally-fixed v0.1.0 (~/tally-fixed)
Finished `dev` profile [unoptimized + debuginfo] target(s) in …
Running `target/debug/tally-fixed`
total of passing marks: 163
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 levels_session.py
With build.warnings set to deny, the same three warnings made cargo check fail with exit status 101. The fixed
package passes cleanly, prints the right total, 163, and its [lints.rust] table makes any ignored Result an error
from now on.
Silencing a warning without reading it
#[allow(…)], a leading underscore or cargo fix make a warning disappear, but the warning may be the only sign of
a bug, as _pass_mark was. Read what it says first; when you do mean to keep the code, prefer #[expect(…)] with a
reason, which warns again if the code changes so that the lint no longer fires.
Checkpoint
Check: Lints and their levels
Diagnostics change their words between releases, not their codes
The wording of a diagnostic is not fixed. Rust 1.91 added a warning for functions that return a raw pointer to one of
their own local variables, and its announcement shows the warning as “a dangling pointer will be produced because the
local variable x will be dropped”. Here is the same warning from rustc 1.99.0:
// Returns the address of a local variable, which no longer exists once the function returns.
fn rate() -> *const u32 {
let percent = 18;
&percent
}
fn main() {
println!("null pointer? {}", rate().is_null());
} from session import run
# A warning added in Rust 1.91, as rustc 1.99.0 words it.
run("""
rustc --edition 2024 dangling.rs
./dangling
""") Output
$ rustc --edition 2024 dangling.rs
warning: function returns a dangling pointer to dropped local variable `percent`
--> dangling.rs:4:5
|
2 | fn rate() -> *const u32 {
| ---------- return type is `*const u32`
3 | let percent = 18;
| ------- local variable `percent` is dropped at the end of the function
4 | &percent
| ^^^^^^^^
|
= note: a dangling pointer is safe, but dereferencing one is undefined behavior
= note: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: `#[warn(dangling_pointers_from_locals)]` on by default
warning: 1 warning emitted
$ ./dangling
null pointer? false
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 wording_session.py
The sentence is now “function returns a dangling pointer to dropped local variable percent”, with labels for the
return type and for where the variable is dropped. The lint’s name, dangling_pointers_from_locals, stayed the same, as
error codes do. So search for the code or the lint name rather than the sentence, and when a page shows an error in
other words, compare its code first. Every diagnostic shown in this track comes from rustc 1.99.0; another release
may word some of them differently.
Checkpoint
Check: Codes stay, words change
Practise: predict the diagnostic
Each question shows a short program that does not compile. Decide which error code rustc reports and which line it points at, before you look at the answer. The explanation of each answer quotes what rustc 1.99.0 reported, and the drills you miss return before the others:
Practice that adapts to you
Practise this lesson
14 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Here is what rustc 1.99.0 printed for the five drill programs, the first two lines of each, the code and the place:
from session import run
# The first two lines of what rustc 1.99.0 printed for each drill: the error and where it points.
run("""
rustc --edition 2024 drills/drill_1.rs 2>&1 | head -n 2
rustc --edition 2024 drills/drill_2.rs 2>&1 | head -n 2
rustc --edition 2024 drills/drill_3.rs 2>&1 | head -n 2
rustc --edition 2024 drills/drill_4.rs 2>&1 | head -n 2
rustc --edition 2024 drills/drill_5.rs 2>&1 | head -n 2
""") Output
$ rustc --edition 2024 drills/drill_1.rs 2>&1 | head -n 2 error[E0384]: cannot assign twice to immutable variable `count` --> drills/drill_1.rs:3:5 $ rustc --edition 2024 drills/drill_2.rs 2>&1 | head -n 2 error[E0382]: borrow of moved value: `name` --> drills/drill_2.rs:4:16 $ rustc --edition 2024 drills/drill_3.rs 2>&1 | head -n 2 error[E0308]: mismatched types --> drills/drill_3.rs:2:20 $ rustc --edition 2024 drills/drill_4.rs 2>&1 | head -n 2 error[E0502]: cannot borrow `marks` as mutable because it is also borrowed as immutable --> drills/drill_4.rs:4:5 $ rustc --edition 2024 drills/drill_5.rs 2>&1 | head -n 2 error[E0425]: cannot find value `totl` in this scope --> drills/drill_5.rs:3:16
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 drills_session.py
Interview questions
Warm-up: what are the parts of a rustc error message?
A rustc diagnostic starts with its level and code, such as error[E0382], and a one-line message. The --> line gives
the file, line and column. Under it the compiler shows the source: ^^^^^ marks the primary label, the exact place the
message is about, and ----- lines mark secondary labels that explain how the code got there, such as where a value
was moved. Notes and help lines follow: = note: adds facts, and help: suggests a fix, often as an edit marked with
+ and -. The last lines count the errors and name rustc --explain with the code, which prints the long
explanation, the same text as the error index page. For a warning, a note also names its lint, which tells you how to
change its level.
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Fresher to mid
After a refactor, a junior colleague's branch has 40 compiler errors. They are fixing them from the bottom of the list up and running cargo build after each fix. How do you coach them through it?
-
Mid to senior
Your codebase has 300 #[allow(...)] attributes, and nobody knows which are still needed. What policy would you set for silencing lints, and how would you clean up the existing ones?
Key takeaways
- A rustc diagnostic has a level and code, a message, a location, a primary
^^^label, secondary---labels, and notes and help; read the primary label first, and treat a suggested edit as a suggestion. rustc --explainprints the long explanation of an error code without a network connection, the same text as the error index.- Fix the first error and check again with
cargo check: later errors are often consequences, and borrow errors appear only after the type errors are gone. - Every warning names its lint; set its level with an attribute, the
[lints]table ofCargo.tomlor Cargo’sbuild.warnings, and read a warning beforecargo fixorallowsilence it. - The words of a diagnostic can change between releases while its code and lint name stay, so search by code.
Terms in this lesson
- diagnostic
- A message from the compiler about your code: an error, which stops the build, or a warning, which does not. It gives a level, often a code such as E0382, the place, labels on the source and, when it can, help.
- lint
- A named check that the compiler or Clippy runs on code that compiles, such as unused_variables. Its level, allow, warn, deny or forbid, decides whether it is silent, a warning or an error.
References
- Rust error codes index (The Rust Project)
- Rust error codes index: E0382 (The Rust Project)
- Rust error codes index: E0499 (The Rust Project)
- The rustc book: Lints (The Rust Project)
- The rustc book: Lint Levels (The Rust Project)
- The Rust Reference: Diagnostic attributes (The Rust Project)
- The Cargo Book: cargo fix (The Rust Project)
- The Cargo Book: cargo check (The Rust Project)
- The Cargo Book: The [lints] section (The Rust Project)
- The Cargo Book: Configuration, build.warnings (The Rust Project)
- Rust Compiler Development Guide: Overview of the compiler (The Rust Project)
- Announcing Rust 1.91.0 (The Rust Project)
- 2025 State of Rust Survey Results (The Rust Project)
Report a problem with this lesson
Kept only in this browser. Your Learn progress