@@ -227,3 +227,149 @@ The equivalent in Rust may look like (ignoring documentation):
227
227
That is, the equivalent of ``GPIO_LINE_DIRECTION_IN `` would be referred to as
228
228
``gpio::LineDirection::In ``. In particular, it should not be named
229
229
``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN ``.
230
+
231
+
232
+ Lints
233
+ -----
234
+
235
+ In Rust, it is possible to ``allow `` particular warnings (diagnostics, lints)
236
+ locally, making the compiler ignore instances of a given warning within a given
237
+ function, module, block, etc.
238
+
239
+ It is similar to ``#pragma GCC diagnostic push `` + ``ignored `` + ``pop `` in C
240
+ [# ]_:
241
+
242
+ .. code-block :: c
243
+
244
+ #pragma GCC diagnostic push
245
+ #pragma GCC diagnostic ignored "-Wunused-function"
246
+ static void f(void) {}
247
+ #pragma GCC diagnostic pop
248
+
249
+ .. [# ] In this particular case, the kernel's ``__{always,maybe}_unused ``
250
+ attributes (C23's ``[[maybe_unused]] ``) may be used; however, the example
251
+ is meant to reflect the equivalent lint in Rust discussed afterwards.
252
+
253
+ But way less verbose:
254
+
255
+ .. code-block :: rust
256
+
257
+ #[allow(dead_code)]
258
+ fn f() {}
259
+
260
+ By that virtue, it makes it possible to comfortably enable more diagnostics by
261
+ default (i.e. outside ``W= `` levels). In particular, those that may have some
262
+ false positives but that are otherwise quite useful to keep enabled to catch
263
+ potential mistakes.
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 ``expect `` over ``allow `` unless:
300
+
301
+ - Conditional compilation triggers the warning in some cases but not others.
302
+
303
+ If there are only a few cases where the warning triggers (or does not
304
+ trigger) compared to the total number of cases, then one may consider using
305
+ a conditional ``expect `` (i.e. ``cfg_attr(..., expect(...)) ``). Otherwise,
306
+ it is likely simpler to just use ``allow ``.
307
+
308
+ - Inside macros, when the different invocations may create expanded code that
309
+ triggers the warning in some cases but not in others.
310
+
311
+ - When code may trigger a warning for some architectures but not others, such
312
+ as an ``as `` cast to a C FFI type.
313
+
314
+ As a more developed example, consider for instance this program:
315
+
316
+ .. code-block :: rust
317
+
318
+ fn g() {}
319
+
320
+ fn main() {
321
+ #[cfg(CONFIG_X)]
322
+ g();
323
+ }
324
+
325
+ Here, function ``g() `` is dead code if ``CONFIG_X `` is not set. Can we use
326
+ ``expect `` here?
327
+
328
+ .. code-block :: rust
329
+
330
+ #[expect(dead_code)]
331
+ fn g() {}
332
+
333
+ fn main() {
334
+ #[cfg(CONFIG_X)]
335
+ g();
336
+ }
337
+
338
+ This would emit a lint if ``CONFIG_X `` is set, since it is not dead code in that
339
+ configuration. Therefore, in cases like this, we cannot use ``expect `` as-is.
340
+
341
+ A simple possibility is using ``allow ``:
342
+
343
+ .. code-block :: rust
344
+
345
+ #[allow(dead_code)]
346
+ fn g() {}
347
+
348
+ fn main() {
349
+ #[cfg(CONFIG_X)]
350
+ g();
351
+ }
352
+
353
+ An alternative would be using a conditional ``expect ``:
354
+
355
+ .. code-block :: rust
356
+
357
+ #[cfg_attr(not(CONFIG_X), expect(dead_code))]
358
+ fn g() {}
359
+
360
+ fn main() {
361
+ #[cfg(CONFIG_X)]
362
+ g();
363
+ }
364
+
365
+ This would ensure that, if someone introduces another call to ``g() `` somewhere
366
+ (e.g. unconditionally), then it would be spotted that it is not dead code
367
+ anymore. However, the ``cfg_attr `` is more complex than a simple ``allow ``.
368
+
369
+ Therefore, it is likely that it is not worth using conditional ``expect ``\ s when
370
+ more than one or two configurations are involved or when the lint may be
371
+ triggered due to non-local changes (such as ``dead_code ``).
372
+
373
+ For more information about diagnostics in Rust, please see:
374
+
375
+ https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
0 commit comments