Skip to content

Commit 3feac59

Browse files
committed
Fix unreachable expression warning
Invert the order that we pass the arguments to the `contract_check_ensures` function to avoid the warning when the tail of the function is unreachable. Note that the call itself is also unreachable, but we have already handled that case by ignoring unreachable call for contract calls.
1 parent b9754f9 commit 3feac59

16 files changed

+39
-66
lines changed

Diff for: compiler/rustc_ast_lowering/src/expr.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
401401
cond_hir_id: HirId,
402402
) -> &'hir hir::Expr<'hir> {
403403
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
404-
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
405404
let call_expr = self.expr_call_lang_item_fn_mut(
406405
span,
407406
hir::LangItem::ContractCheckEnsures,
408-
arena_vec![self; *expr, *cond_fn],
407+
arena_vec![self; *cond_fn, *expr],
409408
);
410409
self.arena.alloc(call_expr)
411410
}

Diff for: compiler/rustc_ast_lowering/src/item.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1209,8 +1209,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
12091209
let precond = if let Some(req) = &contract.requires {
12101210
// Lower the precondition check intrinsic.
12111211
let lowered_req = this.lower_expr_mut(&req);
1212+
let req_span = this.mark_span_with_reason(
1213+
DesugaringKind::Contract,
1214+
lowered_req.span,
1215+
None,
1216+
);
12121217
let precond = this.expr_call_lang_item_fn_mut(
1213-
req.span,
1218+
req_span,
12141219
hir::LangItem::ContractCheckRequires,
12151220
&*arena_vec![this; lowered_req],
12161221
);
@@ -1220,6 +1225,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
12201225
};
12211226
let (postcond, body) = if let Some(ens) = &contract.ensures {
12221227
let ens_span = this.lower_span(ens.span);
1228+
let ens_span =
1229+
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
12231230
// Set up the postcondition `let` statement.
12241231
let check_ident: Ident =
12251232
Ident::from_str_and_span("__ensures_checker", ens_span);

Diff for: compiler/rustc_hir_analysis/src/check/intrinsic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ pub fn check_intrinsic_type(
236236
// where C: for<'a> Fn(&'a Ret) -> bool,
237237
//
238238
// so: two type params, 0 lifetime param, 0 const params, two inputs, no return
239-
(2, 0, 0, vec![param(0), param(1)], param(0), hir::Safety::Safe)
239+
(2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
240240
} else {
241241
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
242242
let (n_tps, n_cts, inputs, output) = match intrinsic_name {

Diff for: library/core/src/contracts.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@
22
33
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
44

5-
/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
6-
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
7-
/// (including the implicit return of the tail expression, if any).
5+
/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute.
86
///
9-
/// This call helps with type inference for the predicate.
7+
/// This is an existing hack to allow users to omit the type of the return value in their ensures
8+
/// attribute.
9+
///
10+
/// Ideally, rustc should be able to generate the type annotation.
11+
/// The existing lowering logic makes it rather hard to add the explicit type annotation,
12+
/// while the function call is fairly straight forward.
1013
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
14+
// Similar to `contract_check_requires`, we need to use the user-facing
15+
// `contracts` feature rather than the perma-unstable `contracts_internals`.
16+
// Const-checking doesn't honor allow internal unstable logic used by contract expansion.
1117
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
1218
#[lang = "contract_build_check_ensures"]
13-
#[track_caller]
1419
pub const fn build_check_ensures<Ret, C>(cond: C) -> C
1520
where
1621
C: Fn(&Ret) -> bool + Copy + 'static,

Diff for: library/core/src/intrinsics/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -3453,6 +3453,10 @@ pub const fn contract_checks() -> bool {
34533453
///
34543454
/// Note that this function is a no-op during constant evaluation.
34553455
#[unstable(feature = "contracts_internals", issue = "128044")]
3456+
// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of
3457+
// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking
3458+
// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
3459+
// `contracts` feature rather than the perma-unstable `contracts_internals`
34563460
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
34573461
#[lang = "contract_check_requires"]
34583462
#[rustc_intrinsic]
@@ -3478,12 +3482,15 @@ pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
34783482
/// Note that this function is a no-op during constant evaluation.
34793483
#[cfg(not(bootstrap))]
34803484
#[unstable(feature = "contracts_internals", issue = "128044")]
3485+
// Similar to `contract_check_requires`, we need to use the user-facing
3486+
// `contracts` feature rather than the perma-unstable `contracts_internals`.
3487+
// Const-checking doesn't honor allow internal unstable logic used by contract expansion.
34813488
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
34823489
#[lang = "contract_check_ensures"]
34833490
#[rustc_intrinsic]
3484-
pub const fn contract_check_ensures<Ret, C: Fn(&Ret) -> bool + Copy>(ret: Ret, cond: C) -> Ret {
3491+
pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
34853492
const_eval_select!(
3486-
@capture[Ret, C: Fn(&Ret) -> bool + Copy] { ret: Ret, cond: C } -> Ret :
3493+
@capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
34873494
if const {
34883495
// Do nothing
34893496
ret

Diff for: tests/ui/contracts/contract-attributes-nest.chk_pass.stderr

+1-12
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,5 @@ LL | #![feature(contracts)]
77
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10-
warning: unreachable expression
11-
--> $DIR/contract-attributes-nest.rs:23:1
12-
|
13-
LL | #[core::contracts::ensures(|ret| *ret > 100)]
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression
15-
...
16-
LL | return x.baz + 50;
17-
| ----------------- any code following this expression is unreachable
18-
|
19-
= note: `#[warn(unreachable_code)]` on by default
20-
21-
warning: 2 warnings emitted
10+
warning: 1 warning emitted
2211

Diff for: tests/ui/contracts/contract-attributes-nest.rs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
#[core::contracts::requires(x.baz > 0)]
2323
#[core::contracts::ensures(|ret| *ret > 100)]
24-
//~^ WARN unreachable expression [unreachable_code]
2524
fn nest(x: Baz) -> i32
2625
{
2726
loop {

Diff for: tests/ui/contracts/contract-attributes-nest.unchk_fail_post.stderr

+1-12
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,5 @@ LL | #![feature(contracts)]
77
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10-
warning: unreachable expression
11-
--> $DIR/contract-attributes-nest.rs:23:1
12-
|
13-
LL | #[core::contracts::ensures(|ret| *ret > 100)]
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression
15-
...
16-
LL | return x.baz + 50;
17-
| ----------------- any code following this expression is unreachable
18-
|
19-
= note: `#[warn(unreachable_code)]` on by default
20-
21-
warning: 2 warnings emitted
10+
warning: 1 warning emitted
2211

Diff for: tests/ui/contracts/contract-attributes-nest.unchk_fail_pre.stderr

+1-12
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,5 @@ LL | #![feature(contracts)]
77
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10-
warning: unreachable expression
11-
--> $DIR/contract-attributes-nest.rs:23:1
12-
|
13-
LL | #[core::contracts::ensures(|ret| *ret > 100)]
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression
15-
...
16-
LL | return x.baz + 50;
17-
| ----------------- any code following this expression is unreachable
18-
|
19-
= note: `#[warn(unreachable_code)]` on by default
20-
21-
warning: 2 warnings emitted
10+
warning: 1 warning emitted
2211

Diff for: tests/ui/contracts/contract-attributes-nest.unchk_pass.stderr

+1-12
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,5 @@ LL | #![feature(contracts)]
77
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10-
warning: unreachable expression
11-
--> $DIR/contract-attributes-nest.rs:23:1
12-
|
13-
LL | #[core::contracts::ensures(|ret| *ret > 100)]
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression
15-
...
16-
LL | return x.baz + 50;
17-
| ----------------- any code following this expression is unreachable
18-
|
19-
= note: `#[warn(unreachable_code)]` on by default
20-
21-
warning: 2 warnings emitted
10+
warning: 1 warning emitted
2211

Diff for: tests/ui/contracts/contract-captures-via-closure-noncopy.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz
1616
| | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`
1717
| | this tail expression is of type `{[email protected]:12:42}`
1818
| unsatisfied trait bound
19+
| required by a bound introduced by this call
1920
|
2021
= help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`, the trait `std::marker::Copy` is not implemented for `Baz`
2122
note: required because it's used within this closure

Diff for: tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
fn nest(x: Baz) -> i32
2222
contract_requires(|| x.baz > 0)
2323
contract_ensures(|ret| *ret > 100)
24-
//~^ WARN unreachable expression [unreachable_code]
2524
{
2625
loop {
2726
return x.baz + 50;

Diff for: tests/ui/contracts/internal_machinery/contract-intrinsics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ fn main() {
2828

2929
let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old };
3030
// Always pass
31-
core::intrinsics::contract_check_ensures(1, doubles_to_two);
31+
core::intrinsics::contract_check_ensures(doubles_to_two, 1);
3232

3333
// Fail if enabled
3434
#[cfg(any(default, unchk_pass, chk_fail_ensures))]
35-
core::intrinsics::contract_check_ensures(2, doubles_to_two);
35+
core::intrinsics::contract_check_ensures(doubles_to_two, 2);
3636
}

Diff for: tests/ui/contracts/internal_machinery/contract-lang-items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn foo(x: Baz) -> i32 {
2222
};
2323

2424
let ret = x.baz + 50;
25-
core::intrinsics::contract_check_ensures(ret, injected_checker)
25+
core::intrinsics::contract_check_ensures(injected_checker, ret)
2626
}
2727

2828
struct Baz { baz: i32 }

Diff for: tests/ui/contracts/internal_machinery/internal-feature-gating.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn main() {
66
//~^ ERROR use of unstable library feature `contracts_internals`
77
core::intrinsics::contract_check_requires(|| true);
88
//~^ ERROR use of unstable library feature `contracts_internals`
9-
core::intrinsics::contract_check_ensures(&1, |_|true);
9+
core::intrinsics::contract_check_ensures( |_|true, &1);
1010
//~^ ERROR use of unstable library feature `contracts_internals`
1111

1212
core::contracts::build_check_ensures(|_: &()| true);

Diff for: tests/ui/contracts/internal_machinery/internal-feature-gating.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ LL | core::intrinsics::contract_check_requires(|| true);
4141
error[E0658]: use of unstable library feature `contracts_internals`
4242
--> $DIR/internal-feature-gating.rs:9:5
4343
|
44-
LL | core::intrinsics::contract_check_ensures(&1, |_|true);
44+
LL | core::intrinsics::contract_check_ensures( |_|true, &1);
4545
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4646
|
4747
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information

0 commit comments

Comments
 (0)