forked from mirrors/linux
		
	 562cc3cd0c
			
		
	
	
		562cc3cd0c
		
	
	
	
	
		
			
			Add error handling sections to the documentation and use it to link to the existing code documentation. This will allow to extend that documentation, use intra-doc links and test the examples. Suggested-by: Miguel Ojeda <ojeda@kernel.org> Link: https://lore.kernel.org/rust-for-linux/CANiq72keOdXy0LFKk9SzYWwSjiD710v=hQO4xi+5E4xNALa6cA@mail.gmail.com/ Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com> Link: https://lore.kernel.org/r/20250115062552.1970768-1-dirk.behme@de.bosch.com [ Slightly tweaked wording. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
		
			
				
	
	
		
			383 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			383 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. 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
 | |
| 
 | |
| Error handling
 | |
| --------------
 | |
| 
 | |
| For some background and guidelines about Rust for Linux specific error handling,
 | |
| please see:
 | |
| 
 | |
| 	https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
 |