Pull rust fixes from Miguel Ojeda: "Toolchain and infrastructure: - Disallow BTF generation with Rust + LTO - Improve rust-analyzer support 'kernel' crate: - 'init' module: remove 'Zeroable' implementation for a couple types that should not have it - 'alloc' module: fix macOS failure in host test by satisfying POSIX alignment requirement - Add missing '\n's to 'pr_*!()' calls And a couple other minor cleanups" * tag 'rust-fixes-6.14-3' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: scripts: generate_rust_analyzer: add uapi crate scripts: generate_rust_analyzer: add missing include_dirs scripts: generate_rust_analyzer: add missing macros deps rust: Disallow BTF generation with Rust + LTO rust: task: fix `SAFETY` comment in `Task::wake_up` rust: workqueue: add missing newline to pr_info! examples rust: sync: add missing newline in locked_by log example rust: init: add missing newline to pr_info! calls rust: error: add missing newline to pr_warn! calls rust: docs: add missing newline to printing macro examples rust: alloc: satisfy POSIX alignment requirement rust: init: fix `Zeroable` implementation for `Option<NonNull<T>>` and `Option<KBox<T>>` rust: remove leftover mentions of the `alloc` crate
Unified · Split
| @@ -145,7 +145,7 @@ Rust standard library source · 144 unmodified lines | |||
| 145 | **************************** | 145 | **************************** |
| 146 | 146 | ||
| 147 | The Rust standard library source is required because the build system will | 147 | The Rust standard library source is required because the build system will |
| 148 | cross-compile ``core`` and ``alloc``. | 148 | cross-compile ``core``. |
| 149 | 149 | ||
| 150 | If ``rustup`` is being used, run:: | 150 | If ``rustup`` is being used, run:: |
| 151 | 151 | ||
| @@ -97,7 +97,7 @@ operator are also supported as usual, e.g.: · 96 unmodified lines | |||
| 97 | 97 | ||
| 98 | /// ``` | 98 | /// ``` |
| 99 | /// # use kernel::{spawn_work_item, workqueue}; | 99 | /// # use kernel::{spawn_work_item, workqueue}; |
| 100 | /// spawn_work_item!(workqueue::system(), || pr_info!("x"))?; | 100 | /// spawn_work_item!(workqueue::system(), || pr_info!("x\n"))?; |
| 101 | /// # Ok::<(), Error>(()) | 101 | /// # Ok::<(), Error>(()) |
| 102 | /// ``` | 102 | /// ``` |
| 103 | 103 | ||
| @@ -1973,7 +1973,7 @@ config RUST · 1972 unmodified lines | |||
| 1973 | depends on !MODVERSIONS || GENDWARFKSYMS | 1973 | depends on !MODVERSIONS || GENDWARFKSYMS |
| 1974 | depends on !GCC_PLUGIN_RANDSTRUCT | 1974 | depends on !GCC_PLUGIN_RANDSTRUCT |
| 1975 | depends on !RANDSTRUCT | 1975 | depends on !RANDSTRUCT |
| 1976 | depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE | 1976 | depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && !LTO) |
| 1977 | depends on !CFI_CLANG || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC | 1977 | depends on !CFI_CLANG || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC |
| 1978 | select CFI_ICALL_NORMALIZE_INTEGERS if CFI_CLANG | 1978 | select CFI_ICALL_NORMALIZE_INTEGERS if CFI_CLANG |
| 1979 | depends on !CALL_PADDING || RUSTC_VERSION >= 108100 | 1979 | depends on !CALL_PADDING || RUSTC_VERSION >= 108100 |
| @@ -62,6 +62,24 @@ unsafe impl Allocator for Cmalloc { · 61 unmodified lines | |||
| 62 | )); | 62 | )); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | // ISO C (ISO/IEC 9899:2011) defines `aligned_alloc`: | ||
| 66 | // | ||
| 67 | // > The value of alignment shall be a valid alignment supported by the implementation | ||
| 68 | // [...]. | ||
| 69 | // | ||
| 70 | // As an example of the "supported by the implementation" requirement, POSIX.1-2001 (IEEE | ||
| 71 | // 1003.1-2001) defines `posix_memalign`: | ||
| 72 | // | ||
| 73 | // > The value of alignment shall be a power of two multiple of sizeof (void *). | ||
| 74 | // | ||
| 75 | // and POSIX-based implementations of `aligned_alloc` inherit this requirement. At the time | ||
| 76 | // of writing, this is known to be the case on macOS (but not in glibc). | ||
| 77 | // | ||
| 78 | // Satisfy the stricter requirement to avoid spurious test failures on some platforms. | ||
| 79 | let min_align = core::mem::size_of::<*const crate::ffi::c_void>(); | ||
| 80 | let layout = layout.align_to(min_align).map_err(|_| AllocError)?; | ||
| 81 | let layout = layout.pad_to_align(); | ||
| 82 | |||
| 65 | // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or | 83 | // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or |
| 66 | // exceeds the given size and alignment requirements. | 84 | // exceeds the given size and alignment requirements. |
| 67 | let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8; | 85 | let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8; |
| @@ -107,7 +107,7 @@ impl Error { · 106 unmodified lines | |||
| 107 | } else { | 107 | } else { |
| 108 | // TODO: Make it a `WARN_ONCE` once available. | 108 | // TODO: Make it a `WARN_ONCE` once available. |
| 109 | crate::pr_warn!( | 109 | crate::pr_warn!( |
| 110 | "attempted to create `Error` with out of range `errno`: {}", | 110 | "attempted to create `Error` with out of range `errno`: {}\n", |
| 111 | errno | 111 | errno |
| 112 | ); | 112 | ); |
| 113 | code::EINVAL | 113 | code::EINVAL |
| @@ -259,7 +259,7 @@ pub mod macros; · 258 unmodified lines | |||
| 259 | /// }, | 259 | /// }, |
| 260 | /// })); | 260 | /// })); |
| 261 | /// let foo: Pin<&mut Foo> = foo; | 261 | /// let foo: Pin<&mut Foo> = foo; |
| 262 | /// pr_info!("a: {}", &*foo.a.lock()); | 262 | /// pr_info!("a: {}\n", &*foo.a.lock()); |
| 263 | /// ``` | 263 | /// ``` |
| 264 | /// | 264 | /// |
| 265 | /// # Syntax | 265 | /// # Syntax |
| @@ -319,7 +319,7 @@ macro_rules! stack_pin_init { · 53 unmodified lines | |||
| 319 | /// }, GFP_KERNEL)?, | 319 | /// }, GFP_KERNEL)?, |
| 320 | /// })); | 320 | /// })); |
| 321 | /// let foo = foo.unwrap(); | 321 | /// let foo = foo.unwrap(); |
| 322 | /// pr_info!("a: {}", &*foo.a.lock()); | 322 | /// pr_info!("a: {}\n", &*foo.a.lock()); |
| 323 | /// ``` | 323 | /// ``` |
| 324 | /// | 324 | /// |
| 325 | /// ```rust,ignore | 325 | /// ```rust,ignore |
| @@ -352,7 +352,7 @@ macro_rules! stack_pin_init { · 26 unmodified lines | |||
| 352 | /// x: 64, | 352 | /// x: 64, |
| 353 | /// }, GFP_KERNEL)?, | 353 | /// }, GFP_KERNEL)?, |
| 354 | /// })); | 354 | /// })); |
| 355 | /// pr_info!("a: {}", &*foo.a.lock()); | 355 | /// pr_info!("a: {}\n", &*foo.a.lock()); |
| 356 | /// # Ok::<_, AllocError>(()) | 356 | /// # Ok::<_, AllocError>(()) |
| 357 | /// ``` | 357 | /// ``` |
| 358 | /// | 358 | /// |
| @@ -882,7 +882,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { · 523 unmodified lines | |||
| 882 | /// | 882 | /// |
| 883 | /// impl Foo { | 883 | /// impl Foo { |
| 884 | /// fn setup(self: Pin<&mut Self>) { | 884 | /// fn setup(self: Pin<&mut Self>) { |
| 885 | /// pr_info!("Setting up foo"); | 885 | /// pr_info!("Setting up foo\n"); |
| 886 | /// } | 886 | /// } |
| 887 | /// } | 887 | /// } |
| 888 | /// | 888 | /// |
| @@ -986,7 +986,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> { · 97 unmodified lines | |||
| 986 | /// | 986 | /// |
| 987 | /// impl Foo { | 987 | /// impl Foo { |
| 988 | /// fn setup(&mut self) { | 988 | /// fn setup(&mut self) { |
| 989 | /// pr_info!("Setting up foo"); | 989 | /// pr_info!("Setting up foo\n"); |
| 990 | /// } | 990 | /// } |
| 991 | /// } | 991 | /// } |
| 992 | /// | 992 | /// |
| @@ -1336,7 +1336,7 @@ impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> { · 343 unmodified lines | |||
| 1336 | /// #[pinned_drop] | 1336 | /// #[pinned_drop] |
| 1337 | /// impl PinnedDrop for Foo { | 1337 | /// impl PinnedDrop for Foo { |
| 1338 | /// fn drop(self: Pin<&mut Self>) { | 1338 | /// fn drop(self: Pin<&mut Self>) { |
| 1339 | /// pr_info!("Foo is being dropped!"); | 1339 | /// pr_info!("Foo is being dropped!\n"); |
| 1340 | /// } | 1340 | /// } |
| 1341 | /// } | 1341 | /// } |
| 1342 | /// ``` | 1342 | /// ``` |
| @@ -1418,17 +1418,14 @@ impl_zeroable! { · 75 unmodified lines | |||
| 1418 | // SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`. | 1418 | // SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`. |
| 1419 | {<T: ?Sized + Zeroable>} UnsafeCell<T>, | 1419 | {<T: ?Sized + Zeroable>} UnsafeCell<T>, |
| 1420 | 1420 | ||
| 1421 | // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). | 1421 | // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee: |
| 1422 | // https://doc.rust-lang.org/stable/std/option/index.html#representation). | ||
| 1422 | Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>, | 1423 | Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>, |
| 1423 | Option<NonZeroU128>, Option<NonZeroUsize>, | 1424 | Option<NonZeroU128>, Option<NonZeroUsize>, |
| 1424 | Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>, | 1425 | Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>, |
| 1425 | Option<NonZeroI128>, Option<NonZeroIsize>, | 1426 | Option<NonZeroI128>, Option<NonZeroIsize>, |
| 1426 | 1427 | {<T>} Option<NonNull<T>>, | |
| 1427 | // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). | 1428 | {<T>} Option<KBox<T>>, |
| 1428 | // | ||
| 1429 | // In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant. | ||
| 1430 | {<T: ?Sized>} Option<NonNull<T>>, | ||
| 1431 | {<T: ?Sized>} Option<KBox<T>>, | ||
| 1432 | 1429 | ||
| 1433 | // SAFETY: `null` pointer is valid. | 1430 | // SAFETY: `null` pointer is valid. |
| 1434 | // | 1431 | // |
| @@ -45,7 +45,7 @@ · 44 unmodified lines | |||
| 45 | //! #[pinned_drop] | 45 | //! #[pinned_drop] |
| 46 | //! impl PinnedDrop for Foo { | 46 | //! impl PinnedDrop for Foo { |
| 47 | //! fn drop(self: Pin<&mut Self>) { | 47 | //! fn drop(self: Pin<&mut Self>) { |
| 48 | //! pr_info!("{self:p} is getting dropped."); | 48 | //! pr_info!("{self:p} is getting dropped.\n"); |
| 49 | //! } | 49 | //! } |
| 50 | //! } | 50 | //! } |
| 51 | //! | 51 | //! |
| @@ -412,7 +412,7 @@ · 360 unmodified lines | |||
| 412 | //! #[pinned_drop] | 412 | //! #[pinned_drop] |
| 413 | //! impl PinnedDrop for Foo { | 413 | //! impl PinnedDrop for Foo { |
| 414 | //! fn drop(self: Pin<&mut Self>) { | 414 | //! fn drop(self: Pin<&mut Self>) { |
| 415 | //! pr_info!("{self:p} is getting dropped."); | 415 | //! pr_info!("{self:p} is getting dropped.\n"); |
| 416 | //! } | 416 | //! } |
| 417 | //! } | 417 | //! } |
| 418 | //! ``` | 418 | //! ``` |
| @@ -423,7 +423,7 @@ · 4 unmodified lines | |||
| 423 | //! // `unsafe`, full path and the token parameter are added, everything else stays the same. | 423 | //! // `unsafe`, full path and the token parameter are added, everything else stays the same. |
| 424 | //! unsafe impl ::kernel::init::PinnedDrop for Foo { | 424 | //! unsafe impl ::kernel::init::PinnedDrop for Foo { |
| 425 | //! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) { | 425 | //! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) { |
| 426 | //! pr_info!("{self:p} is getting dropped."); | 426 | //! pr_info!("{self:p} is getting dropped.\n"); |
| 427 | //! } | 427 | //! } |
| 428 | //! } | 428 | //! } |
| 429 | //! ``` | 429 | //! ``` |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | |||
| 6 | //! usage by Rust code in the kernel and is shared by all of them. | 6 | //! usage by Rust code in the kernel and is shared by all of them. |
| 7 | //! | 7 | //! |
| 8 | //! In other words, all the rest of the Rust code in the kernel (e.g. kernel | 8 | //! In other words, all the rest of the Rust code in the kernel (e.g. kernel |
| 9 | //! modules written in Rust) depends on [`core`], [`alloc`] and this crate. | 9 | //! modules written in Rust) depends on [`core`] and this crate. |
| 10 | //! | 10 | //! |
| 11 | //! If you need a kernel C API that is not ported or wrapped yet here, then | 11 | //! If you need a kernel C API that is not ported or wrapped yet here, then |
| 12 | //! do so first instead of bypassing this crate. | 12 | //! do so first instead of bypassing this crate. |
| @@ -55,7 +55,7 @@ use core::{cell::UnsafeCell, mem::size_of, ptr}; · 54 unmodified lines | |||
| 55 | /// fn print_bytes_used(dir: &Directory, file: &File) { | 55 | /// fn print_bytes_used(dir: &Directory, file: &File) { |
| 56 | /// let guard = dir.inner.lock(); | 56 | /// let guard = dir.inner.lock(); |
| 57 | /// let inner_file = file.inner.access(&guard); | 57 | /// let inner_file = file.inner.access(&guard); |
| 58 | /// pr_info!("{} {}", guard.bytes_used, inner_file.bytes_used); | 58 | /// pr_info!("{} {}\n", guard.bytes_used, inner_file.bytes_used); |
| 59 | /// } | 59 | /// } |
| 60 | /// | 60 | /// |
| 61 | /// /// Increments `bytes_used` for both the directory and file. | 61 | /// /// Increments `bytes_used` for both the directory and file. |
| @@ -320,7 +320,7 @@ impl Task { · 319 unmodified lines | |||
| 320 | 320 | ||
| 321 | /// Wakes up the task. | 321 | /// Wakes up the task. |
| 322 | pub fn wake_up(&self) { | 322 | pub fn wake_up(&self) { |
| 323 | // SAFETY: It's always safe to call `signal_pending` on a valid task, even if the task | 323 | // SAFETY: It's always safe to call `wake_up_process` on a valid task, even if the task |
| 324 | // running. | 324 | // running. |
| 325 | unsafe { bindings::wake_up_process(self.as_ptr()) }; | 325 | unsafe { bindings::wake_up_process(self.as_ptr()) }; |
| 326 | } | 326 | } |
| @@ -60,7 +60,7 @@ · 59 unmodified lines | |||
| 60 | //! type Pointer = Arc<MyStruct>; | 60 | //! type Pointer = Arc<MyStruct>; |
| 61 | //! | 61 | //! |
| 62 | //! fn run(this: Arc<MyStruct>) { | 62 | //! fn run(this: Arc<MyStruct>) { |
| 63 | //! pr_info!("The value is: {}", this.value); | 63 | //! pr_info!("The value is: {}\n", this.value); |
| 64 | //! } | 64 | //! } |
| 65 | //! } | 65 | //! } |
| 66 | //! | 66 | //! |
| @@ -108,7 +108,7 @@ · 41 unmodified lines | |||
| 108 | //! type Pointer = Arc<MyStruct>; | 108 | //! type Pointer = Arc<MyStruct>; |
| 109 | //! | 109 | //! |
| 110 | //! fn run(this: Arc<MyStruct>) { | 110 | //! fn run(this: Arc<MyStruct>) { |
| 111 | //! pr_info!("The value is: {}", this.value_1); | 111 | //! pr_info!("The value is: {}\n", this.value_1); |
| 112 | //! } | 112 | //! } |
| 113 | //! } | 113 | //! } |
| 114 | //! | 114 | //! |
| @@ -116,7 +116,7 @@ · 1 unmodified line | |||
| 116 | //! type Pointer = Arc<MyStruct>; | 116 | //! type Pointer = Arc<MyStruct>; |
| 117 | //! | 117 | //! |
| 118 | //! fn run(this: Arc<MyStruct>) { | 118 | //! fn run(this: Arc<MyStruct>) { |
| 119 | //! pr_info!("The second value is: {}", this.value_2); | 119 | //! pr_info!("The second value is: {}\n", this.value_2); |
| 120 | //! } | 120 | //! } |
| 121 | //! } | 121 | //! } |
| 122 | //! | 122 | //! |
| @@ -57,14 +57,26 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): · 56 unmodified lines | |||
| 57 | crates_indexes[display_name] = len(crates) | 57 | crates_indexes[display_name] = len(crates) |
| 58 | crates.append(crate) | 58 | crates.append(crate) |
| 59 | 59 | ||
| 60 | # First, the ones in `rust/` since they are a bit special. | 60 | def append_sysroot_crate( |
| 61 | append_crate( | 61 | display_name, |
| 62 | "core", | 62 | deps, |
| 63 | sysroot_src / "core" / "src" / "lib.rs", | 63 | cfg=[], |
| 64 | [], | 64 | ): |
| 65 | cfg=crates_cfgs.get("core", []), | 65 | append_crate( |
| 66 | is_workspace_member=False, | 66 | display_name, |
| 67 | ) | 67 | sysroot_src / display_name / "src" / "lib.rs", |
| 68 | deps, | ||
| 69 | cfg, | ||
| 70 | is_workspace_member=False, | ||
| 71 | ) | ||
| 72 | |||
| 73 | # NB: sysroot crates reexport items from one another so setting up our transitive dependencies | ||
| 74 | # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth | ||
| 75 | # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`. | ||
| 76 | append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", [])) | ||
| 77 | append_sysroot_crate("alloc", ["core"]) | ||
| 78 | append_sysroot_crate("std", ["alloc", "core"]) | ||
| 79 | append_sysroot_crate("proc_macro", ["core", "std"]) | ||
| 68 | 80 | ||
| 69 | append_crate( | 81 | append_crate( |
| 70 | "compiler_builtins", | 82 | "compiler_builtins", |
| @@ -75,7 +87,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): · 4 unmodified lines | |||
| 75 | append_crate( | 87 | append_crate( |
| 76 | "macros", | 88 | "macros", |
| 77 | srctree / "rust" / "macros" / "lib.rs", | 89 | srctree / "rust" / "macros" / "lib.rs", |
| 78 | [], | 90 | ["std", "proc_macro"], |
| 79 | is_proc_macro=True, | 91 | is_proc_macro=True, |
| 80 | ) | 92 | ) |
| 81 | 93 | ||
| @@ -85,27 +97,28 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): · 3 unmodified lines | |||
| 85 | ["core", "compiler_builtins"], | 97 | ["core", "compiler_builtins"], |
| 86 | ) | 98 | ) |
| 87 | 99 | ||
| 88 | append_crate( | 100 | def append_crate_with_generated( |
| 89 | "bindings", | 101 | display_name, |
| 90 | srctree / "rust"/ "bindings" / "lib.rs", | 102 | deps, |
| 91 | ["core"], | 103 | ): |
| 92 | cfg=cfg, | 104 | append_crate( |
| 93 | ) | 105 | display_name, |
| 94 | crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) | 106 | srctree / "rust"/ display_name / "lib.rs", |
| 107 | deps, | ||
| 108 | cfg=cfg, | ||
| 109 | ) | ||
| 110 | crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) | ||
| 111 | crates[-1]["source"] = { | ||
| 112 | "include_dirs": [ | ||
| 113 | str(srctree / "rust" / display_name), | ||
| 114 | str(objtree / "rust") | ||
| 115 | ], | ||
| 116 | "exclude_dirs": [], | ||
| 117 | } | ||
| 95 | 118 | ||
| 96 | append_crate( | 119 | append_crate_with_generated("bindings", ["core"]) |
| 97 | "kernel", | 120 | append_crate_with_generated("uapi", ["core"]) |
| 98 | srctree / "rust" / "kernel" / "lib.rs", | 121 | append_crate_with_generated("kernel", ["core", "macros", "build_error", "bindings", "uapi"]) |
| 99 | ["core", "macros", "build_error", "bindings"], | ||
| 100 | cfg=cfg, | ||
| 101 | ) | ||
| 102 | crates[-1]["source"] = { | ||
| 103 | "include_dirs": [ | ||
| 104 | str(srctree / "rust" / "kernel"), | ||
| 105 | str(objtree / "rust") | ||
| 106 | ], | ||
| 107 | "exclude_dirs": [], | ||
| 108 | } | ||
| 109 | 122 | ||
| 110 | def is_root_crate(build_file, target): | 123 | def is_root_crate(build_file, target): |
| 111 | try: | 124 | try: |
| @@ -15,8 +15,8 @@ · 14 unmodified lines | |||
| 15 | //! - Test code should be able to define functions and call them, without having to carry | 15 | //! - Test code should be able to define functions and call them, without having to carry |
| 16 | //! the context. | 16 | //! the context. |
| 17 | //! | 17 | //! |
| 18 | //! - Later on, we may want to be able to test non-kernel code (e.g. `core`, `alloc` or | 18 | //! - Later on, we may want to be able to test non-kernel code (e.g. `core` or third-party |
| 19 | //! third-party crates) which likely use the standard library `assert*!` macros. | 19 | //! crates) which likely use the standard library `assert*!` macros. |
| 20 | //! | 20 | //! |
| 21 | //! For this reason, instead of the passed context, `kunit_get_current_test()` is used instead | 21 | //! For this reason, instead of the passed context, `kunit_get_current_test()` is used instead |
| 22 | //! (i.e. `current->kunit_test`). | 22 | //! (i.e. `current->kunit_test`). |