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.
This commit is contained in:
Dawid Lachowicz 2025-12-06 19:16:00 +00:00
parent da2544bfbe
commit d54fee82f4
No known key found for this signature in database
GPG key ID: C3DF0179A96A684D
2 changed files with 35 additions and 1 deletions

View file

@ -23,7 +23,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// The order in which things are lowered is important! I.e to
// refer to variables in contract_decls from postcond/precond,
// we must lower it first!
let contract_decls = self.lower_stmts(&contract.declarations).0;
let contract_decls = self.lower_decls(contract);
match (&contract.requires, &contract.ensures) {
(Some(req), Some(ens)) => {
@ -124,6 +124,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
fn lower_decls(&mut self, contract: &rustc_ast::FnContract) -> &'hir [rustc_hir::Stmt<'hir>] {
let (decls, decls_tail) = self.lower_stmts(&contract.declarations);
if let Some(e) = decls_tail {
// include the tail expression in the declaration statements
let tail = self.stmt_expr(e.span, *e);
self.arena.alloc_from_iter(decls.into_iter().map(|d| *d).chain([tail].into_iter()))
} else {
decls
}
}
/// Lower the precondition check intrinsic.
fn lower_precond(&mut self, req: &Box<rustc_ast::Expr>) -> rustc_hir::Stmt<'hir> {
let lowered_req = self.lower_expr_mut(&req);

View file

@ -0,0 +1,22 @@
//@ run-pass
//@ compile-flags: -Zcontract-checks=yes
#![expect(incomplete_features)]
#![feature(contracts)]
extern crate core;
use core::contracts::requires;
// Compound statements (those using [ExpressionWithBlock]
// (https://doc.rust-lang.org/beta/reference/expressions.html#railroad-ExpressionWithBlock))
// like blocks, if-expressions, and loops require no trailing semicolon. This
// regression test captures the case where the last statement in the contract
// declarations has no trailing semicolon.
#[requires(
{}
true
)]
fn foo() {}
fn main() {
foo()
}