| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- .. 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
|