Skip to content

Commit 5db6d3a

Browse files
committed
contracts: fix lowering final declaration without trailing semicolon
Lowering for contract delcarations incorrectly handled the final declaration statement when it didn't end in a semicolon. This change fixes the issue.
1 parent da2544b commit 5db6d3a

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

compiler/rustc_ast_lowering/src/contract.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
2323
// The order in which things are lowered is important! I.e to
2424
// refer to variables in contract_decls from postcond/precond,
2525
// we must lower it first!
26-
let contract_decls = self.lower_stmts(&contract.declarations).0;
26+
let contract_decls = self.lower_decls(contract);
2727

2828
match (&contract.requires, &contract.ensures) {
2929
(Some(req), Some(ens)) => {
@@ -124,6 +124,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
124124
}
125125
}
126126

127+
fn lower_decls(&mut self, contract: &rustc_ast::FnContract) -> &'hir [rustc_hir::Stmt<'hir>] {
128+
let (decls, decls_tail) = self.lower_stmts(&contract.declarations);
129+
130+
if let Some(e) = decls_tail {
131+
// include the tail expression in the declaration statements
132+
let tail = self.stmt_expr(e.span, *e);
133+
self.arena.alloc_from_iter(decls.into_iter().map(|d| *d).chain([tail].into_iter()))
134+
} else {
135+
decls
136+
}
137+
}
138+
127139
/// Lower the precondition check intrinsic.
128140
fn lower_precond(&mut self, req: &Box<rustc_ast::Expr>) -> rustc_hir::Stmt<'hir> {
129141
let lowered_req = self.lower_expr_mut(&req);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ run-pass
2+
//@ compile-flags: -Zcontract-checks=yes
3+
4+
#![feature(contracts)]
5+
//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
6+
extern crate core;
7+
use core::contracts::requires;
8+
9+
// Compound statements (those using [ExpressionWithBlock]
10+
// (https://doc.rust-lang.org/beta/reference/expressions.html#railroad-ExpressionWithBlock))
11+
// like blocks, if-expressions, and loops require no trailing semicolon. This
12+
// regression test captures the case where the last statement in the contract
13+
// declarations has no trailing semicolon.
14+
#[requires(
15+
{}
16+
true
17+
)]
18+
fn foo() {}
19+
20+
fn main() {
21+
foo()
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/requires-block-stmt.rs:4:12
3+
|
4+
LL | #![feature(contracts)]
5+
| ^^^^^^^^^
6+
|
7+
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+

0 commit comments

Comments
 (0)