Received: by 2002:a05:6358:d09b:b0:dc:cd0c:909e with SMTP id jc27csp2329906rwb; Fri, 2 Dec 2022 08:21:24 -0800 (PST) X-Google-Smtp-Source: AA0mqf5mekuy+FMxVfTAQkT/YcSwaplxtoGmgp78DBGzHOl/ThPfNBqrRvApmviyV4QiX9l/Vze3 X-Received: by 2002:a17:906:dfef:b0:7ae:db2:f10a with SMTP id lc15-20020a170906dfef00b007ae0db2f10amr46978274ejc.709.1669998084577; Fri, 02 Dec 2022 08:21:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669998084; cv=none; d=google.com; s=arc-20160816; b=xfP6V9f8LdGb056W3G1E446Jiz1C3kj3DF3Chm08Kk3R7Biz9XHD/N9beCEgsEcTIe YvmMxj+IY6hotalL3qWBO7+DWZgA9y54TwcQiTNSfPPpCkiKFcdE7EWWEFs5kC/H78i7 7e9NJNNzbYmboSKCaSplP4IxrfTtEoFymgAHoGTav9xNgOJwgAwttglOc+pzTYbHtk+D CaZwcB/6Kn0O2VCpMIPM56n90NrhIsTIOFeUd0RHXVKhfSEfvDrB561awo1rMznPJV4D +4YF65MvPA2cOk8Kd1pCbzXJ+A+2v1q6lQRPHN6mhiq9G9T6jK/dAzClXKwEeD6WkuRx ASAA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ED+gUV3tYJ0qkuZw8mwTENY+M3JbW5VyR4VjDB4YNMc=; b=OYRc4GDZwSDGV8PvJm6BSp4cOvEKkEp/9H5il6MUR0qXW4UjWt+yIery3ldInl0qtG sL5T0s2enWBuUHcSpXDaYxHnAYR22ybEH9vBs0su3lpqAc4N9VgSueEeRylbNz//ylH1 MIydLTQP/YU4x0FOV0Mg28aAiHWGCLqpC3HvzbLK4YVvmRgN5aNMLwp+/ggNePeoaZtx 7V5+efukPZ1p0CaopkRpCTCDBVmyEY0wxVAdTTuvOBuBTGAAAMJeLff7XBoPTT6k9QbS EfomE8hr4Bjtu3JUqDf4jNIrm3FDlQ8cFABV2GM1GJvzzmNVyhi9XOU0Ze5jLMlwsM2j A7ag== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=WjzCHS3A; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id hz4-20020a1709072ce400b007c0c0cb9f25si2187677ejc.3.2022.12.02.08.21.03; Fri, 02 Dec 2022 08:21:24 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=WjzCHS3A; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233728AbiLBQSb (ORCPT + 82 others); Fri, 2 Dec 2022 11:18:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233944AbiLBQR0 (ORCPT ); Fri, 2 Dec 2022 11:17:26 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E52ABE346E; Fri, 2 Dec 2022 08:16:42 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 062AF62325; Fri, 2 Dec 2022 16:16:42 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6A5FEC433D6; Fri, 2 Dec 2022 16:16:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1669997801; bh=qf1L1f1lloAHjax2Q2sSNkOySbNmdgvi1HaQZKetkYY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WjzCHS3ANJYDqZrQ1IviFl1Ud5lXAOhenxU8ghqXN/mYT6AI55VhO4q9g1G9mrL1F ZQ4jDtc6AffEVqiRMiy5kJLphb/244aEflV/t9SWPY2+aTKo7//vojphYskIh3VU8i VYxhqMWJbNHgYGbWVFWDVq/him1fQMyTfd6ifXX0nwh6hnFJ7YqPZK8x7Tq4JmaM4M +cEPAQdrv5m1FC8xIASmAiiDdrILsj4e9kPRm29RW33nxwlYwCnFPb11XIAl/31qp2 LTjUJ9iYrUJOs+Yq6LKCdtNiRMdk8IXxZoVjSJfH3EHbXJwreyUxQFj0X9NVr3BKe9 uTBASa7Q6VrdA== From: ojeda@kernel.org To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev Subject: [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros Date: Fri, 2 Dec 2022 17:14:57 +0100 Message-Id: <20221202161502.385525-27-ojeda@kernel.org> In-Reply-To: <20221202161502.385525-1-ojeda@kernel.org> References: <20221202161502.385525-1-ojeda@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Gary Guo Add the `build_error!` and `build_assert!` macros which leverage the previously introduced `build_error` crate. Do so in a new module, called `build_assert`. The former fails the build if the code path calling it can possibly be executed. The latter asserts that a boolean expression is `true` at compile time. In particular, `build_assert!` can be used in some contexts where `static_assert!` cannot: fn f1() { static_assert!(N > 1);` // Error. build_assert!(N > 1); // Build-time check. assert!(N > 1); // Run-time check. } #[inline] fn f2(n: usize) { static_assert!(n > 1); // Error. build_assert!(n > 1); // Build-time check. assert!(n > 1); // Run-time check. } Signed-off-by: Gary Guo [Reworded, adapted for upstream and applied latest changes] Signed-off-by: Miguel Ojeda --- rust/kernel/build_assert.rs | 82 +++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 4 ++ rust/kernel/prelude.rs | 2 + 3 files changed, 88 insertions(+) create mode 100644 rust/kernel/build_assert.rs diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs new file mode 100644 index 000000000000..659542393c09 --- /dev/null +++ b/rust/kernel/build_assert.rs @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Build-time assert. + +/// Fails the build if the code path calling `build_error!` can possibly be executed. +/// +/// If the macro is executed in const context, `build_error!` will panic. +/// If the compiler or optimizer cannot guarantee that `build_error!` can never +/// be called, a build error will be triggered. +/// +/// # Examples +/// +/// ``` +/// # use kernel::build_error; +/// #[inline] +/// fn foo(a: usize) -> usize { +/// a.checked_add(1).unwrap_or_else(|| build_error!("overflow")) +/// } +/// +/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK. +/// // foo(usize::MAX); // Fails to compile. +/// ``` +#[macro_export] +macro_rules! build_error { + () => {{ + $crate::build_error("") + }}; + ($msg:expr) => {{ + $crate::build_error($msg) + }}; +} + +/// Asserts that a boolean expression is `true` at compile time. +/// +/// If the condition is evaluated to `false` in const context, `build_assert!` +/// will panic. If the compiler or optimizer cannot guarantee the condition will +/// be evaluated to `true`, a build error will be triggered. +/// +/// [`static_assert!`] should be preferred to `build_assert!` whenever possible. +/// +/// # Examples +/// +/// These examples show that different types of [`assert!`] will trigger errors +/// at different stage of compilation. It is preferred to err as early as +/// possible, so [`static_assert!`] should be used whenever possible. +/// ```ignore +/// fn foo() { +/// static_assert!(1 > 1); // Compile-time error +/// build_assert!(1 > 1); // Build-time error +/// assert!(1 > 1); // Run-time error +/// } +/// ``` +/// +/// When the condition refers to generic parameters or parameters of an inline function, +/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario. +/// ``` +/// fn foo() { +/// // `static_assert!(N > 1);` is not allowed +/// build_assert!(N > 1); // Build-time check +/// assert!(N > 1); // Run-time check +/// } +/// +/// #[inline] +/// fn bar(n: usize) { +/// // `static_assert!(n > 1);` is not allowed +/// build_assert!(n > 1); // Build-time check +/// assert!(n > 1); // Run-time check +/// } +/// ``` +#[macro_export] +macro_rules! build_assert { + ($cond:expr $(,)?) => {{ + if !$cond { + $crate::build_error(concat!("assertion failed: ", stringify!($cond))); + } + }}; + ($cond:expr, $msg:expr) => {{ + if !$cond { + $crate::build_error($msg); + } + }}; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 9b83ef736298..a3abc110ff97 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -23,6 +23,7 @@ compile_error!("Missing kernel configuration for conditional compilation"); #[cfg(not(test))] #[cfg(not(testlib))] mod allocator; +mod build_assert; pub mod error; pub mod prelude; pub mod print; @@ -35,6 +36,9 @@ pub mod str; pub use bindings; pub use macros; +#[doc(hidden)] +pub use build_error::build_error; + /// Prefix to appear before log messages printed from within the `kernel` crate. const __LOG_PREFIX: &[u8] = b"rust_kernel\0"; diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 178fe8e6cb6d..7a90249ee9b9 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -17,6 +17,8 @@ pub use alloc::{boxed::Box, vec::Vec}; pub use macros::{module, vtable}; +pub use super::build_assert; + pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; pub use super::static_assert; -- 2.38.1