summaryrefslogtreecommitdiffstats
path: root/Documentation/rust/coding-guidelines.rst
blob: a2e326b42410f8d27f706b4a00e2ad0339be62ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
.. SPDX-License-Identifier: GPL-2.0

Coding Guidelines
=================

This document describes how to write Rust code in the kernel.


Style & formatting
------------------

The code should be formatted using ``rustfmt``. In this way, a person
contributing from time to time to the kernel does not need to learn and
remember one more style guide. More importantly, reviewers and maintainers
do not need to spend time pointing out style issues anymore, and thus
less patch roundtrips may be needed to land a change.

.. note:: Conventions on comments and documentation are not checked by
  ``rustfmt``. Thus those are still needed to be taken care of.

The default settings of ``rustfmt`` are used. This means the idiomatic Rust
style is followed. For instance, 4 spaces are used for indentation rather
than tabs.

It is convenient to instruct editors/IDEs to format while typing,
when saving or at commit time. However, if for some reason reformatting
the entire kernel Rust sources is needed at some point, the following can be
run::

	make LLVM=1 rustfmt

It is also possible to check if everything is formatted (printing a diff
otherwise), for instance for a CI, with::

	make LLVM=1 rustfmtcheck

Like ``clang-format`` for the rest of the kernel, ``rustfmt`` works on
individual files, and does not require a kernel configuration. Sometimes it may
even work with broken code.


Comments
--------

"Normal" comments (i.e. ``//``, rather than code documentation which starts
with ``///`` or ``//!``) are written in Markdown the same way as documentation
comments are, even though they will not be rendered. This improves consistency,
simplifies the rules and allows to move content between the two kinds of
comments more easily. For instance:

.. code-block:: rust

	// `object` is ready to be handled now.
	f(object);

Furthermore, just like documentation, comments are capitalized at the beginning
of a sentence and ended with a period (even if it is a single sentence). This
includes ``// SAFETY:``, ``// TODO:`` and other "tagged" comments, e.g.:

.. code-block:: rust

	// FIXME: The error should be handled properly.

Comments should not be used for documentation purposes: comments are intended
for implementation details, not users. This distinction is useful even if the
reader of the source file is both an implementor and a user of an API. In fact,
sometimes it is useful to use both comments and documentation at the same time.
For instance, for a ``TODO`` list or to comment on the documentation itself.
For the latter case, comments can be inserted in the middle; that is, closer to
the line of documentation to be commented. For any other case, comments are
written after the documentation, e.g.:

.. code-block:: rust

	/// Returns a new [`Foo`].
	///
	/// # Examples
	///
	// TODO: Find a better example.
	/// ```
	/// let foo = f(42);
	/// ```
	// FIXME: Use fallible approach.
	pub fn f(x: i32) -> Foo {
	    // ...
	}

One special kind of comments are the ``// SAFETY:`` comments. These must appear
before every ``unsafe`` block, and they explain why the code inside the block is
correct/sound, i.e. why it cannot trigger undefined behavior in any case, e.g.:

.. code-block:: rust

	// SAFETY: `p` is valid by the safety requirements.
	unsafe { *p = 0; }

``// SAFETY:`` comments are not to be confused with the ``# Safety`` sections
in code documentation. ``# Safety`` sections specify the contract that callers
(for functions) or implementors (for traits) need to abide by. ``// SAFETY:``
comments show why a call (for functions) or implementation (for traits) actually
respects the preconditions stated in a ``# Safety`` section or the language
reference.


Code documentation
------------------

Rust kernel code is not documented like C kernel code (i.e. via kernel-doc).
Instead, the usual system for documenting Rust code is used: the ``rustdoc``
tool, which uses Markdown (a lightweight markup language).

To learn Markdown, there are many guides available out there. For instance,
the one at:

	https://commonmark.org/help/

This is how a well-documented Rust function may look like:

.. code-block:: rust

	/// Returns the contained [`Some`] value, consuming the `self` value,
	/// without checking that the value is not [`None`].
	///
	/// # Safety
	///
	/// Calling this method on [`None`] is *[undefined behavior]*.
	///
	/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
	///
	/// # Examples
	///
	/// ```
	/// let x = Some("air");
	/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
	/// ```
	pub unsafe fn unwrap_unchecked(self) -> T {
	    match self {
	        Some(val) => val,

	        // SAFETY: The safety contract must be upheld by the caller.
	        None => unsafe { hint::unreachable_unchecked() },
	    }
	}

This example showcases a few ``rustdoc`` features and some conventions followed
in the kernel:

- The first paragraph must be a single sentence briefly describing what
  the documented item does. Further explanations must go in extra paragraphs.

- Unsafe functions must document their safety preconditions under
  a ``# Safety`` section.

- While not shown here, if a function may panic, the conditions under which
  that happens must be described under a ``# Panics`` section.

  Please note that panicking should be very rare and used only with a good
  reason. In almost all cases, a fallible approach should be used, typically
  returning a ``Result``.

- If providing examples of usage would help readers, they must be written in
  a section called ``# Examples``.

- Rust items (functions, types, constants...) must be linked appropriately
  (``rustdoc`` will create a link automatically).

- Any ``unsafe`` block must be preceded by a ``// SAFETY:`` comment
  describing why the code inside is sound.

  While sometimes the reason might look trivial and therefore unneeded,
  writing these comments is not just a good way of documenting what has been
  taken into account, but most importantly, it provides a way to know that
  there are no *extra* implicit constraints.

To learn more about how to write documentation for Rust and extra features,
please take a look at the ``rustdoc`` book at:

	https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html

In addition, the kernel supports creating links relative to the source tree by
prefixing the link destination with ``srctree/``. For instance:

.. code-block:: rust

	//! C header: [`include/linux/printk.h`](srctree/include/linux/printk.h)

or:

.. code-block:: rust

	/// [`struct mutex`]: srctree/include/linux/mutex.h


Naming
------

Rust kernel code follows the usual Rust naming conventions:

	https://rust-lang.github.io/api-guidelines/naming.html

When existing C concepts (e.g. macros, functions, objects...) are wrapped into
a Rust abstraction, a name as close as reasonably possible to the C side should
be used in order to avoid confusion and to improve readability when switching
back and forth between the C and Rust sides. For instance, macros such as
``pr_info`` from C are named the same in the Rust side.

Having said that, casing should be adjusted to follow the Rust naming
conventions, and namespacing introduced by modules and types should not be
repeated in the item names. For instance, when wrapping constants like:

.. code-block:: c

	#define GPIO_LINE_DIRECTION_IN	0
	#define GPIO_LINE_DIRECTION_OUT	1

The equivalent in Rust may look like (ignoring documentation):

.. code-block:: rust

	pub mod gpio {
	    pub enum LineDirection {
	        In = bindings::GPIO_LINE_DIRECTION_IN as _,
	        Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
	    }
	}

That is, the equivalent of ``GPIO_LINE_DIRECTION_IN`` would be referred to as
``gpio::LineDirection::In``. In particular, it should not be named
``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN``.


Lints
-----

In Rust, it is possible to ``allow`` particular warnings (diagnostics, lints)
locally, making the compiler ignore instances of a given warning within a given
function, module, block, etc.

It is similar to ``#pragma GCC diagnostic push`` + ``ignored`` + ``pop`` in C
[#]_:

.. code-block:: c

	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wunused-function"
	static void f(void) {}
	#pragma GCC diagnostic pop

.. [#] In this particular case, the kernel's ``__{always,maybe}_unused``
       attributes (C23's ``[[maybe_unused]]``) may be used; however, the example
       is meant to reflect the equivalent lint in Rust discussed afterwards.

But way less verbose:

.. code-block:: rust

	#[allow(dead_code)]
	fn f() {}

By that virtue, it makes it possible to comfortably enable more diagnostics by
default (i.e. outside ``W=`` levels). In particular, those that may have some
false positives but that are otherwise quite useful to keep enabled to catch
potential mistakes.

On top of that, Rust provides the ``expect`` attribute which takes this further.
It makes the compiler warn if the warning was not produced. For instance, the
following will ensure that, when ``f()`` is called somewhere, we will have to
remove the attribute:

.. code-block:: rust

	#[expect(dead_code)]
	fn f() {}

If we do not, we get a warning from the compiler::

	warning: this lint expectation is unfulfilled
	 --> x.rs:3:10
	  |
	3 | #[expect(dead_code)]
	  |          ^^^^^^^^^
	  |
	  = note: `#[warn(unfulfilled_lint_expectations)]` on by default

This means that ``expect``\ s do not get forgotten when they are not needed, which
may happen in several situations, e.g.:

- Temporary attributes added while developing.

- Improvements in lints in the compiler, Clippy or custom tools which may
  remove a false positive.

- When the lint is not needed anymore because it was expected that it would be
  removed at some point, such as the ``dead_code`` example above.

It also increases the visibility of the remaining ``allow``\ s and reduces the
chance of misapplying one.

Thus prefer ``expect`` over ``allow`` unless:

- Conditional compilation triggers the warning in some cases but not others.

  If there are only a few cases where the warning triggers (or does not
  trigger) compared to the total number of cases, then one may consider using
  a conditional ``expect`` (i.e. ``cfg_attr(..., expect(...))``). Otherwise,
  it is likely simpler to just use ``allow``.

- Inside macros, when the different invocations may create expanded code that
  triggers the warning in some cases but not in others.

- When code may trigger a warning for some architectures but not others, such
  as an ``as`` cast to a C FFI type.

As a more developed example, consider for instance this program:

.. code-block:: rust

	fn g() {}

	fn main() {
	    #[cfg(CONFIG_X)]
	    g();
	}

Here, function ``g()`` is dead code if ``CONFIG_X`` is not set. Can we use
``expect`` here?

.. code-block:: rust

	#[expect(dead_code)]
	fn g() {}

	fn main() {
	    #[cfg(CONFIG_X)]
	    g();
	}

This would emit a lint if ``CONFIG_X`` is set, since it is not dead code in that
configuration. Therefore, in cases like this, we cannot use ``expect`` as-is.

A simple possibility is using ``allow``:

.. code-block:: rust

	#[allow(dead_code)]
	fn g() {}

	fn main() {
	    #[cfg(CONFIG_X)]
	    g();
	}

An alternative would be using a conditional ``expect``:

.. code-block:: rust

	#[cfg_attr(not(CONFIG_X), expect(dead_code))]
	fn g() {}

	fn main() {
	    #[cfg(CONFIG_X)]
	    g();
	}

This would ensure that, if someone introduces another call to ``g()`` somewhere
(e.g. unconditionally), then it would be spotted that it is not dead code
anymore. However, the ``cfg_attr`` is more complex than a simple ``allow``.

Therefore, it is likely that it is not worth using conditional ``expect``\ s when
more than one or two configurations are involved or when the lint may be
triggered due to non-local changes (such as ``dead_code``).

For more information about diagnostics in Rust, please see:

	https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html