Skip to content

Commit e88e4d8

Browse files
add while let loop transformation
1 parent 8adc279 commit e88e4d8

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

kani-compiler/src/kani_middle/transform/loop_contracts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ impl LoopContractPass {
701701
for stmt in &new_body.blocks()[bb_idx].statements {
702702
if let StatementKind::Assign(place, rvalue) = &stmt.kind {
703703
match rvalue {
704-
Rvalue::Ref(_,_,rplace) | Rvalue::CopyForDeref(rplace) => {
704+
Rvalue::Ref(_,_,rplace) | Rvalue::CopyForDeref(rplace) | Rvalue::Use(Operand::Copy(rplace)) => {
705705
if supported_vars.contains(&rplace.local) {
706706
supported_vars.push(place.local);
707707
} }

library/kani_macros/src/sysroot/loop_contracts/mod.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
77
use proc_macro::TokenStream;
88
use proc_macro_error2::abort_call_site;
9-
use quote::{format_ident, quote};
9+
use quote::{format_ident, quote, quote_spanned};
1010
use syn::punctuated::Punctuated;
1111
use syn::spanned::Spanned;
1212
use syn::token::AndAnd;
1313
use syn::{
14-
BinOp, Block, Expr, ExprBinary, Ident, Stmt, Token, parse_macro_input, parse_quote,
14+
BinOp, Block, Expr, ExprBinary, ExprWhile, Ident, Stmt, Token, parse_macro_input, parse_quote,
1515
visit_mut::VisitMut,
1616
};
1717

@@ -232,9 +232,32 @@ fn transform_break_continue(block: &mut Block) {
232232
block.stmts.push(return_stmt);
233233
}
234234

235+
fn while_let_rewrite(loopexpr: Stmt) -> Stmt {
236+
if let Stmt::Expr(ref expr, _) = loopexpr {
237+
if let Expr::While(ExprWhile { cond, body, .. }) = expr {
238+
if let Expr::Let(ref let_expr) = **cond {
239+
let pat = &let_expr.pat;
240+
let scrutinee = &let_expr.expr;
241+
242+
// Transform to loop with match
243+
return parse_quote! {
244+
loop {
245+
match #scrutinee {
246+
#pat => #body,
247+
_ => break,
248+
}
249+
};
250+
};
251+
}
252+
}
253+
}
254+
return loopexpr.clone();
255+
}
256+
235257
pub fn loop_invariant(attr: TokenStream, item: TokenStream) -> TokenStream {
236258
// parse the stmt of the loop
237259
let mut loop_stmt: Stmt = syn::parse(item.clone()).unwrap();
260+
loop_stmt = while_let_rewrite(loop_stmt);
238261

239262
// name of the loop invariant as closure of the form
240263
// __kani_loop_invariant_#startline_#startcol_#endline_#endcol
@@ -244,6 +267,7 @@ pub fn loop_invariant(attr: TokenStream, item: TokenStream) -> TokenStream {
244267

245268
// expr of the loop invariant
246269
let mut inv_expr: Expr = syn::parse(attr).unwrap();
270+
let original_span = inv_expr.span();
247271

248272
// adding on_entry variables
249273
let mut onentry_var_prefix: String = "__kani_onentry_var".to_owned();
@@ -302,7 +326,7 @@ pub fn loop_invariant(attr: TokenStream, item: TokenStream) -> TokenStream {
302326
&mut Stmt::Expr(ref mut e, _) => match *e {
303327
Expr::While(ref mut ew) => {
304328
let new_cond: Expr = syn::parse(
305-
quote!(
329+
quote_spanned!(original_span =>
306330
#register_ident(&||->bool{#inv_expr}, 0))
307331
.into(),
308332
)
@@ -316,7 +340,9 @@ pub fn loop_invariant(attr: TokenStream, item: TokenStream) -> TokenStream {
316340
}
317341
Expr::Loop(ref mut el) => {
318342
//let retexpr = get_return_statement(&el.body);
319-
let invstmt: Stmt = syn::parse(quote!(if !(#register_ident(&||->bool{#inv_expr}, 0)) {assert!(false); unreachable!()};).into()).unwrap();
343+
let invstmt: Stmt = syn::parse(quote_spanned!(original_span =>
344+
if !(#register_ident(&||->bool{#inv_expr}, 0)) {assert!(false); unreachable!()};)
345+
.into()).unwrap();
320346
let mut new_stmts: Vec<Stmt> = Vec::new();
321347
new_stmts.push(invstmt);
322348
new_stmts.extend(el.body.stmts.clone());
@@ -334,7 +360,7 @@ pub fn loop_invariant(attr: TokenStream, item: TokenStream) -> TokenStream {
334360
}
335361

336362
if has_prev {
337-
quote!(
363+
quote_spanned!(original_span =>
338364
{
339365
if (#loop_guard) {
340366
#(#onentry_decl_stms)*
@@ -363,7 +389,7 @@ pub fn loop_invariant(attr: TokenStream, item: TokenStream) -> TokenStream {
363389
})
364390
.into()
365391
} else {
366-
quote!(
392+
quote_spanned!(original_span =>
367393
{
368394
#(#onentry_decl_stms)*
369395
// Dummy function used to force the compiler to capture the environment.

0 commit comments

Comments
 (0)