about summary refs log tree commit diff
path: root/library/core
diff options
context:
space:
mode:
authorCelina G. Val <celinval@amazon.com>2025-01-17 14:49:10 -0800
committerCelina G. Val <celinval@amazon.com>2025-02-03 13:55:15 -0800
commit2bb1464cb6b46d175f92943cb0f9ab534e6cc6eb (patch)
treed40d2600e97c5d55a55f2ab38df73a3ed367037b /library/core
parent804cce47d96d7b30f3798b51a1377c6697011c54 (diff)
downloadrust-2bb1464cb6b46d175f92943cb0f9ab534e6cc6eb.tar.gz
rust-2bb1464cb6b46d175f92943cb0f9ab534e6cc6eb.zip
Improve contracts intrisics and remove wrapper function
1. Document the new intrinsics.
2. Make the intrinsics actually check the contract if enabled, and
   remove `contract::check_requires` function.
3. Use panic with no unwind in case contract is using to check for
   safety, we probably don't want to unwind. Following the same
   reasoning as UB checks.
Diffstat (limited to 'library/core')
-rw-r--r--library/core/src/contracts.rs27
-rw-r--r--library/core/src/intrinsics/mod.rs22
2 files changed, 23 insertions, 26 deletions
diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs
index b155dbc213e..0668cacb92c 100644
--- a/library/core/src/contracts.rs
+++ b/library/core/src/contracts.rs
@@ -1,38 +1,21 @@
 //! Unstable module containing the unstable contracts lang items and attribute macros.
+#![cfg(not(bootstrap))]
 
-#[cfg(not(bootstrap))]
-pub use crate::macros::builtin::contracts_ensures as ensures;
-#[cfg(not(bootstrap))]
-pub use crate::macros::builtin::contracts_requires as requires;
-
-/// Emitted by rustc as a desugaring of `#[requires(PRED)] fn foo(x: X) { ... }`
-/// into: `fn foo(x: X) { check_requires(|| PRED) ... }`
-#[cfg(not(bootstrap))]
-#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)]
-#[lang = "contract_check_requires"]
-#[track_caller]
-pub fn check_requires<C: FnOnce() -> bool>(c: C) {
-    if core::intrinsics::contract_checks() {
-        assert!(core::intrinsics::contract_check_requires(c), "failed requires check");
-    }
-}
+pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
 
 /// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
 /// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
 /// (including the implicit return of the tail expression, if any).
-#[cfg(not(bootstrap))]
 #[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)]
 #[lang = "contract_build_check_ensures"]
 #[track_caller]
-pub fn build_check_ensures<Ret, C>(c: C) -> impl (FnOnce(Ret) -> Ret) + Copy
+pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
 where
-    C: for<'a> FnOnce(&'a Ret) -> bool + Copy + 'static,
+    C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
 {
     #[track_caller]
     move |ret| {
-        if core::intrinsics::contract_checks() {
-            assert!(core::intrinsics::contract_check_ensures(&ret, c), "failed ensures check");
-        }
+        crate::intrinsics::contract_check_ensures(&ret, cond);
         ret
     }
 }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index a7f0f09f0c6..14f8645d6f1 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -4062,18 +4062,32 @@ pub const fn contract_checks() -> bool {
     false
 }
 
+/// Check if the pre-condition `cond` has been met.
+///
+/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
+/// returns false.
 #[cfg(not(bootstrap))]
 #[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)]
+#[lang = "contract_check_requires"]
 #[rustc_intrinsic]
-pub fn contract_check_requires<C: FnOnce() -> bool>(c: C) -> bool {
-    c()
+pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
+    if contract_checks() && !cond() {
+        // Emit no unwind panic in case this was a safety requirement.
+        crate::panicking::panic_nounwind("failed requires check");
+    }
 }
 
+/// Check if the post-condition `cond` has been met.
+///
+/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
+/// returns false.
 #[cfg(not(bootstrap))]
 #[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)]
 #[rustc_intrinsic]
-pub fn contract_check_ensures<'a, Ret, C: FnOnce(&'a Ret) -> bool>(ret: &'a Ret, c: C) -> bool {
-    c(ret)
+pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
+    if contract_checks() && !cond(ret) {
+        crate::panicking::panic_nounwind("failed ensures check");
+    }
 }
 
 /// The intrinsic will return the size stored in that vtable.