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