@@ -262,6 +262,116 @@ default (i.e. outside ``W=`` levels). In particular, those that may have some
262
262
false positives but that are otherwise quite useful to keep enabled to catch
263
263
potential mistakes.
264
264
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
+
265
375
For more information about diagnostics in Rust, please see:
266
376
267
377
https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
0 commit comments