Skip to content

Commit 6905678

Browse files
committed
Documentation: rust: discuss #[expect(...)] in the guidelines
Discuss `#[expect(...)]` in the Lints sections of the coding guidelines document, which is an upcoming feature in Rust 1.81.0, and explain that it is generally to be preferred over `allow` unless there is a reason not to use it (e.g. conditional compilation being involved). Signed-off-by: Miguel Ojeda <[email protected]>
1 parent b36bca5 commit 6905678

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

Documentation/rust/coding-guidelines.rst

+110
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,113 @@ By that virtue, it makes it possible to comfortably enable more diagnostics by
256256
default (i.e. outside ``W=`` levels). In particular, those that may have some
257257
false positives but that are otherwise quite useful to keep enabled to catch
258258
potential mistakes.
259+
260+
On top of that, Rust provides the ``expect`` attribute which takes this further.
261+
It makes the compiler warn if the warning was not produced. For instance, the
262+
following will ensure that, when ``f()`` is called somewhere, we will have to
263+
remove the attribute:
264+
265+
.. code-block:: rust
266+
267+
#[expect(dead_code)]
268+
fn f() {}
269+
270+
If we do not, we get a warning from the compiler::
271+
272+
warning: this lint expectation is unfulfilled
273+
--> x.rs:3:10
274+
|
275+
3 | #[expect(dead_code)]
276+
| ^^^^^^^^^
277+
|
278+
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
279+
280+
This means that ``expect``s do not get forgotten when they are not needed, which
281+
may happen in several situations, e.g.:
282+
283+
- Temporary attributes added while developing.
284+
285+
- Improvements in lints in the compiler, Clippy or custom tools which may
286+
remove a false positive.
287+
288+
- When the lint is not needed anymore because it was expected that it would be
289+
removed at some point, such as the ``dead_code`` example above.
290+
291+
It also increases the visibility of the remaining ``allow``s and reduces the
292+
chance of misapplying one.
293+
294+
Thus prefer ``except`` over ``allow`` unless:
295+
296+
- The lint attribute is intended to be temporary, e.g. while developing.
297+
298+
- Conditional compilation triggers the warning in some cases but not others.
299+
300+
If there are only a few cases where the warning triggers (or does not
301+
trigger) compared to the total number of cases, then one may consider using
302+
a conditional ``expect`` (i.e. ``cfg_attr(..., expect(...))``). Otherwise,
303+
it is likely simpler to just use ``allow``.
304+
305+
- Inside macros, when the different invocations may create expanded code that
306+
triggers the warning in some cases but not in others.
307+
308+
- When code may trigger a warning for some architectures but not others, such
309+
as an ``as`` cast to a C FFI type.
310+
311+
As a more developed example, consider for instance this program:
312+
313+
.. code-block:: rust
314+
315+
fn g() {}
316+
317+
fn main() {
318+
#[cfg(CONFIG_X)]
319+
g();
320+
}
321+
322+
Here, function ``g()`` is dead code if ``CONFIG_X`` is not set. Can we use
323+
``expect`` here?
324+
325+
.. code-block:: rust
326+
327+
#[expect(dead_code)]
328+
fn g() {}
329+
330+
fn main() {
331+
#[cfg(CONFIG_X)]
332+
g();
333+
}
334+
335+
This would emit a lint if ``CONFIG_X`` is set, since it is not dead code in that
336+
configuration. Therefore, in cases like this, we cannot use ``expect`` as-is.
337+
338+
A simple possibility is using ``allow``:
339+
340+
.. code-block:: rust
341+
342+
#[allow(dead_code)]
343+
fn g() {}
344+
345+
fn main() {
346+
#[cfg(CONFIG_X)]
347+
g();
348+
}
349+
350+
An alternative would be using a conditional ``expect``:
351+
352+
.. code-block:: rust
353+
354+
#[cfg_attr(not(CONFIG_X), expect(dead_code))]
355+
fn g() {}
356+
357+
fn main() {
358+
#[cfg(CONFIG_X)]
359+
g();
360+
}
361+
362+
This would ensure that, if someone introduces another call to ``g()`` somewhere
363+
(e.g. unconditionally), then it would be spotted that it is not dead code
364+
anymore. However, the ``cfg_attr`` is more complex than a simple ``allow``.
365+
366+
Therefore, it is likely that it is not worth using conditional ``expect``s when
367+
more than one or two configurations are involved or when the lint may be
368+
triggered due to non-local changes (such as ``dead_code``).

0 commit comments

Comments
 (0)