Skip to content

Commit 8600932

Browse files
committed
Conditionally compile contracts instead of deciding at run-time
The initial implementation of contracts, despite requiring a compiler flag to enable runtime checking of contracts, still compiled contracts into function definitions, even when the compiler flag was disabled. This meant that contracts could not be safely added to functions without breaking optimisations, or even without potentially changing the behaviour of the function. This change guards macro expansion of the built-in contract macros with the contract-checks compiler flag. Additionally, it removes the contract_checks compiler intrinsic that was used to determine whether contract checks should be executed at runtime. Now, when contracts checks are compiled into the body of a function, they will always be executed.
1 parent 8712e45 commit 8600932

28 files changed

+176
-124
lines changed

compiler/rustc_builtin_macros/src/contracts.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ impl AttrProcMacro for ExpandRequires {
1717
annotation: TokenStream,
1818
annotated: TokenStream,
1919
) -> Result<TokenStream, ErrorGuaranteed> {
20-
expand_requires_tts(ecx, span, annotation, annotated)
20+
if ecx.sess.contract_checks() {
21+
expand_requires_tts(ecx, span, annotation, annotated)
22+
} else {
23+
Ok(annotated)
24+
}
2125
}
2226
}
2327

@@ -29,7 +33,11 @@ impl AttrProcMacro for ExpandEnsures {
2933
annotation: TokenStream,
3034
annotated: TokenStream,
3135
) -> Result<TokenStream, ErrorGuaranteed> {
32-
expand_ensures_tts(ecx, span, annotation, annotated)
36+
if ecx.sess.contract_checks() {
37+
expand_ensures_tts(ecx, span, annotation, annotated)
38+
} else {
39+
Ok(annotated)
40+
}
3341
}
3442
}
3543

library/core/src/intrinsics/mod.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,23 +2557,6 @@ pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 {
25572557
ptr
25582558
}
25592559

2560-
/// Returns whether we should perform contract-checking at runtime.
2561-
///
2562-
/// This is meant to be similar to the ub_checks intrinsic, in terms
2563-
/// of not prematurely committing at compile-time to whether contract
2564-
/// checking is turned on, so that we can specify contracts in libstd
2565-
/// and let an end user opt into turning them on.
2566-
#[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
2567-
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
2568-
#[inline(always)]
2569-
#[rustc_intrinsic]
2570-
pub const fn contract_checks() -> bool {
2571-
// FIXME: should this be `false` or `cfg!(contract_checks)`?
2572-
2573-
// cfg!(contract_checks)
2574-
false
2575-
}
2576-
25772560
/// Check if the pre-condition `cond` has been met.
25782561
///
25792562
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
@@ -2594,7 +2577,7 @@ pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
25942577
if const {
25952578
// Do nothing
25962579
} else {
2597-
if contract_checks() && !cond() {
2580+
if !cond() {
25982581
// Emit no unwind panic in case this was a safety requirement.
25992582
crate::panicking::panic_nounwind("failed requires check");
26002583
}
@@ -2622,7 +2605,7 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, re
26222605
// Do nothing
26232606
ret
26242607
} else {
2625-
if contract_checks() && !cond(&ret) {
2608+
if !cond(&ret) {
26262609
// Emit no unwind panic in case this was a safety requirement.
26272610
crate::panicking::panic_nounwind("failed ensures check");
26282611
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Ensure we don't ICE when contract present on an associated item but
2+
// contract-checks are disabled.
3+
4+
//@ compile-flags: --crate-type=lib
5+
//@ check-pass
6+
7+
#![feature(contracts)]
8+
//~^ WARN the feature `contracts` is incomplete and may not be safe to use
9+
10+
extern crate core;
11+
12+
use core::contracts::requires;
13+
14+
struct Foo;
15+
16+
impl Foo {
17+
#[requires(align > 0 && (align & (align - 1)) == 0)]
18+
pub fn foo(align: i32) {}
19+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
2-
--> $DIR/contract-lang-items.rs:15:12
2+
--> $DIR/associated-item-disabled.rs:7:12
33
|
4-
LL | #![feature(contracts)] // to access core::contracts
4+
LL | #![feature(contracts)]
55
| ^^^^^^^^^
66
|
77
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information

tests/ui/contracts/associated-item.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Ensure we don't ICE when lowering contracts on an associated item.
22

33
//@ compile-flags: --crate-type=lib
4+
//@ compile-flags: -Zcontract-checks=yes
45
//@ check-pass
56

67
#![feature(contracts)]

tests/ui/contracts/associated-item.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
2-
--> $DIR/associated-item.rs:6:12
2+
--> $DIR/associated-item.rs:7:12
33
|
44
LL | #![feature(contracts)]
55
| ^^^^^^^^^

tests/ui/contracts/contract-annotation-limitations.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Test for some of the existing limitations and the current error messages.
22
//! Some of these limitations may be removed in the future.
33
4+
//@ compile-flags: -Zcontract-checks=yes
5+
46
#![feature(contracts)]
57
//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
68
#![allow(dead_code)]

tests/ui/contracts/contract-annotation-limitations.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
error: contract annotations is only supported in functions with bodies
2-
--> $DIR/contract-annotation-limitations.rs:18:5
2+
--> $DIR/contract-annotation-limitations.rs:20:5
33
|
44
LL | #[core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

77
error: contract annotations is only supported in functions with bodies
8-
--> $DIR/contract-annotation-limitations.rs:22:5
8+
--> $DIR/contract-annotation-limitations.rs:24:5
99
|
1010
LL | #[core::contracts::ensures(|ret| ret.is_none_or(Stars::is_valid))]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

1313
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
14-
--> $DIR/contract-annotation-limitations.rs:4:12
14+
--> $DIR/contract-annotation-limitations.rs:6:12
1515
|
1616
LL | #![feature(contracts)]
1717
| ^^^^^^^^^
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-pass
2+
#![feature(contracts)]
3+
//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
4+
5+
extern crate core;
6+
use core::contracts::ensures;
7+
8+
#[ensures({*x = 0; |_ret| true})]
9+
fn buggy_add(x: &mut u32, y: u32) {
10+
*x = *x + y;
11+
}
12+
13+
fn main() {
14+
let mut x = 10;
15+
buggy_add(&mut x, 100);
16+
assert_eq!(x, 110);
17+
}

tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr renamed to tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
2-
--> $DIR/contract-lang-items.rs:15:12
2+
--> $DIR/contracts-disabled-side-effect-ensures.rs:2:12
33
|
4-
LL | #![feature(contracts)] // to access core::contracts
4+
LL | #![feature(contracts)]
55
| ^^^^^^^^^
66
|
77
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information

0 commit comments

Comments
 (0)