Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: add `build_error` crate

The `build_error` crate provides a function `build_error` which
will panic at compile-time if executed in const context and,
by default, will cause a build error if not executed at compile
time and the optimizer does not optimise away the call.

The `CONFIG_RUST_BUILD_ASSERT_ALLOW` kernel option allows to
relax the default build failure and convert it to a runtime
check. If the runtime check fails, `panic!` will be called.

Its functionality will be exposed to users as a couple macros in
the `kernel` crate in the following patch, thus some documentation
here refers to them for simplicity.

Signed-off-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Gary Guo and committed by
Miguel Ojeda
ecaa6ddf ef9e3797

+76 -6
+16
lib/Kconfig.debug
··· 2801 2801 2802 2802 If unsure, say Y. 2803 2803 2804 + config RUST_BUILD_ASSERT_ALLOW 2805 + bool "Allow unoptimized build-time assertions" 2806 + depends on RUST 2807 + help 2808 + Controls how are `build_error!` and `build_assert!` handled during build. 2809 + 2810 + If calls to them exist in the binary, it may indicate a violated invariant 2811 + or that the optimizer failed to verify the invariant during compilation. 2812 + 2813 + This should not happen, thus by default the build is aborted. However, 2814 + as an escape hatch, you can choose Y here to ignore them during build 2815 + and let the check be carried at runtime (with `panic!` being called if 2816 + the check fails). 2817 + 2818 + If unsure, say N. 2819 + 2804 2820 endmenu # "Rust" 2805 2821 2806 2822 source "Documentation/Kconfig"
+17 -5
rust/Makefile
··· 19 19 always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \ 20 20 exports_kernel_generated.h 21 21 22 + ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW 23 + obj-$(CONFIG_RUST) += build_error.o 24 + else 25 + always-$(CONFIG_RUST) += build_error.o 26 + endif 27 + 22 28 obj-$(CONFIG_RUST) += exports.o 23 29 24 30 # Avoids running `$(RUSTC)` for the sysroot when it may not be available. ··· 114 108 $(call if_changed,rustdoc) 115 109 116 110 rustdoc-kernel: private rustc_target_flags = --extern alloc \ 117 - --extern macros=$(objtree)/$(obj)/libmacros.so \ 111 + --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \ 118 112 --extern bindings 119 113 rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \ 120 114 rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \ ··· 131 125 --sysroot $(objtree)/$(obj)/test/sysroot \ 132 126 -L$(objtree)/$(obj)/test \ 133 127 --crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $< 128 + 129 + rusttestlib-build_error: $(src)/build_error.rs rusttest-prepare FORCE 130 + $(call if_changed,rustc_test_library) 134 131 135 132 rusttestlib-macros: private rustc_target_flags = --extern proc_macro 136 133 rusttestlib-macros: private rustc_test_library_proc = yes ··· 225 216 $(call if_changed,rustdoc_test) 226 217 227 218 rusttest-kernel: private rustc_target_flags = --extern alloc \ 228 - --extern macros --extern bindings 219 + --extern build_error --extern macros --extern bindings 229 220 rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \ 230 - rusttestlib-macros rusttestlib-bindings FORCE 221 + rusttestlib-build_error rusttestlib-macros rusttestlib-bindings FORCE 231 222 $(call if_changed,rustc_test) 232 223 $(call if_changed,rustc_test_library) 233 224 ··· 375 366 $(obj)/alloc.o: $(src)/alloc/lib.rs $(obj)/compiler_builtins.o FORCE 376 367 $(call if_changed_dep,rustc_library) 377 368 369 + $(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE 370 + $(call if_changed_dep,rustc_library) 371 + 378 372 $(obj)/bindings.o: $(src)/bindings/lib.rs \ 379 373 $(obj)/compiler_builtins.o \ 380 374 $(obj)/bindings/bindings_generated.rs \ ··· 385 373 $(call if_changed_dep,rustc_library) 386 374 387 375 $(obj)/kernel.o: private rustc_target_flags = --extern alloc \ 388 - --extern macros --extern bindings 389 - $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o \ 376 + --extern build_error --extern macros --extern bindings 377 + $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \ 390 378 $(obj)/libmacros.so $(obj)/bindings.o FORCE 391 379 $(call if_changed_dep,rustc_library) 392 380
+31
rust/build_error.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Build-time error. 4 + //! 5 + //! This crate provides a [const function][const-functions] `build_error`, which will panic in 6 + //! compile-time if executed in [const context][const-context], and will cause a build error 7 + //! if not executed at compile time and the optimizer does not optimise away the call. 8 + //! 9 + //! It is used by `build_assert!` in the kernel crate, allowing checking of 10 + //! conditions that could be checked statically, but could not be enforced in 11 + //! Rust yet (e.g. perform some checks in [const functions][const-functions], but those 12 + //! functions could still be called in the runtime). 13 + //! 14 + //! For details on constant evaluation in Rust, please see the [Reference][const-eval]. 15 + //! 16 + //! [const-eval]: https://doc.rust-lang.org/reference/const_eval.html 17 + //! [const-functions]: https://doc.rust-lang.org/reference/const_eval.html#const-functions 18 + //! [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context 19 + 20 + #![no_std] 21 + 22 + /// Panics if executed in [const context][const-context], or triggers a build error if not. 23 + /// 24 + /// [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context 25 + #[inline(never)] 26 + #[cold] 27 + #[export_name = "rust_build_error"] 28 + #[track_caller] 29 + pub const fn build_error(msg: &'static str) -> ! { 30 + panic!("{}", msg); 31 + }
+5
rust/exports.c
··· 19 19 #include "exports_alloc_generated.h" 20 20 #include "exports_bindings_generated.h" 21 21 #include "exports_kernel_generated.h" 22 + 23 + // For modules using `rust/build_error.rs`. 24 + #ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW 25 + EXPORT_SYMBOL_RUST_GPL(rust_build_error); 26 + #endif
+7 -1
scripts/generate_rust_analyzer.py
··· 68 68 crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so" 69 69 70 70 append_crate( 71 + "build_error", 72 + srctree / "rust" / "build_error.rs", 73 + ["core", "compiler_builtins"], 74 + ) 75 + 76 + append_crate( 71 77 "bindings", 72 78 srctree / "rust"/ "bindings" / "lib.rs", 73 79 ["core"], ··· 84 78 append_crate( 85 79 "kernel", 86 80 srctree / "rust" / "kernel" / "lib.rs", 87 - ["core", "alloc", "macros", "bindings"], 81 + ["core", "alloc", "macros", "build_error", "bindings"], 88 82 cfg=cfg, 89 83 ) 90 84 crates[-1]["source"] = {