Skip to content

Commit 01bf489

Browse files
authored
[verus_spec] avoid rewrite exec code when external/external_body (verus-lang#2317)
1 parent fc697a7 commit 01bf489

3 files changed

Lines changed: 65 additions & 26 deletions

File tree

source/builtin_macros/src/attr_rewrite.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use syn::{Expr, Item, ItemConst, parse2, spanned::Spanned};
4343
use crate::{
4444
EraseGhost,
4545
attr_block_trait::{AnyAttrBlock, AnyFnOrLoop},
46-
syntax::{self, mk_verifier_attr_syn, mk_verus_attr_syn},
46+
syntax::{self, has_external_code_syn, mk_verifier_attr_syn, mk_verus_attr_syn},
4747
syntax_trait,
4848
unerased_proxies::VERUS_UNERASED_PROXY,
4949
};
@@ -159,7 +159,7 @@ pub(crate) fn rewrite_verus_attribute(
159159
spec_f.sig.ident = ident.clone();
160160
spec_f.attrs = vec![mk_verus_attr_syn(f.span(), quote! { spec })];
161161
// remove proof-related macros
162-
replace_block(EraseGhost::Erase, spec_f.block_mut().unwrap());
162+
replace_block(EraseGhost::Erase, spec_f.block_mut().unwrap(), false);
163163
spec_fun = Some(spec_f);
164164

165165
attributes
@@ -194,6 +194,7 @@ pub(crate) fn rewrite_verus_attribute(
194194

195195
struct ExecReplacer {
196196
erase: EraseGhost,
197+
inside_external_code: bool,
197198
}
198199

199200
impl VisitMut for ExecReplacer {
@@ -202,7 +203,7 @@ impl VisitMut for ExecReplacer {
202203
fn visit_macro_mut(&mut self, mac: &mut syn::Macro) {
203204
syn::visit_mut::visit_macro_mut(self, mac);
204205
// Only replace in verification mode
205-
if !self.erase.keep() {
206+
if !self.erase.keep() || self.inside_external_code {
206207
return;
207208
}
208209
if let Some(x) = mac.path.segments.first_mut() {
@@ -291,7 +292,7 @@ impl VisitMut for ExecReplacer {
291292
fn visit_expr_for_loop_mut(&mut self, for_loop: &mut syn::ExprForLoop) {
292293
syn::visit_mut::visit_expr_for_loop_mut(self, for_loop);
293294

294-
if !self.erase.keep() {
295+
if !self.erase.keep() || self.inside_external_code {
295296
return;
296297
}
297298

@@ -370,13 +371,17 @@ fn is_verus_proof_stmt(stmt: &syn::Stmt) -> bool {
370371
// TODO: when tracked/ghost is supported, we need to clear verus-related
371372
// attributes for expression so that unverfied `cargo build` does not need to
372373
// enable unstable feature for macro.
373-
pub(crate) fn replace_block(erase: EraseGhost, fblock: &mut syn::Block) {
374-
let mut replacer = ExecReplacer { erase };
374+
pub(crate) fn replace_block(
375+
erase: EraseGhost,
376+
fblock: &mut syn::Block,
377+
inside_external_code: bool,
378+
) {
379+
let mut replacer = ExecReplacer { erase, inside_external_code };
375380
replacer.visit_block_mut(fblock);
376381
}
377382

378383
pub(crate) fn replace_expr(erase: EraseGhost, expr: &mut syn::Expr) {
379-
let mut replacer = ExecReplacer { erase };
384+
let mut replacer = ExecReplacer { erase, inside_external_code: false };
380385
replacer.visit_expr_mut(expr);
381386
}
382387

@@ -637,7 +642,8 @@ pub(crate) fn rewrite_verus_spec_on_fun_or_loop(
637642
let _ = fun.block_mut().unwrap().stmts.splice(0..0, new_stmts);
638643

639644
// Parse and replace proof_xxx!() inside function and replace panic.
640-
replace_block(erase, fun.block_mut().unwrap());
645+
let inside_external_code = has_external_code_syn(&fun.attrs);
646+
replace_block(erase, fun.block_mut().unwrap(), inside_external_code);
641647
fun.to_tokens(&mut new_stream);
642648
proc_macro::TokenStream::from(new_stream)
643649
}
@@ -974,7 +980,8 @@ fn rewrite_const_ret_proxy(const_fun: &mut syn::ItemFn) -> syn::ItemFn {
974980
// But just do it to be safe and consistent with verus macro.
975981
let span = const_fun.sig.constness.unwrap().span();
976982
let mut proxy_fun = const_fun.clone();
977-
replace_block(EraseGhost::Erase, const_fun.block_mut().unwrap());
983+
let inside_external_code = has_external_code_syn(&const_fun.attrs);
984+
replace_block(EraseGhost::Erase, const_fun.block_mut().unwrap(), inside_external_code);
978985
const_fun.attrs.push(mk_verifier_attr_syn(span, quote! { external }));
979986
const_fun.attrs.push(mk_verus_attr_syn(span, quote! { uses_unerased_proxy }));
980987
const_fun.attrs.push(mk_verus_attr_syn(span, quote! { encoded_const }));

source/builtin_macros/src/syntax.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5267,24 +5267,30 @@ pub(crate) fn proof_macro_explicit_exprs(
52675267
proc_macro::TokenStream::from(new_stream)
52685268
}
52695269

5270-
pub(crate) fn has_external_code(attrs: &Vec<Attribute>) -> bool {
5271-
attrs.iter().any(|attr| {
5272-
// verifier::external
5273-
attr.path().segments.len() == 2
5274-
&& attr.path().segments[0].ident == "verifier"
5275-
&& (attr.path().segments[1].ident == "external"
5276-
|| attr.path().segments[1].ident == "external_body")
5277-
// verifier(external)
5278-
|| attr.path().segments.len() == 1
5279-
&& attr.path().segments[0].ident == "verifier"
5280-
&& match &attr.meta {
5281-
verus_syn::Meta::List(list) => {
5282-
matches!(list.tokens.to_string().as_str(), "external" | "external_body")
5283-
}
5284-
_ => false,
5285-
}
5286-
})
5270+
macro_rules! declare_has_external_code {
5271+
($name:ident, $s:ident) => {
5272+
pub(crate) fn $name(attrs: &Vec<$s::Attribute>) -> bool {
5273+
attrs.iter().any(|attr| {
5274+
// verifier::external
5275+
attr.path().segments.len() == 2
5276+
&& attr.path().segments[0].ident == "verifier"
5277+
&& (attr.path().segments[1].ident == "external"
5278+
|| attr.path().segments[1].ident == "external_body")
5279+
// verifier(external) or verus_verify(external)
5280+
|| attr.path().segments.len() == 1
5281+
&& matches!(attr.path().segments[0].ident.to_string().as_str(), "verifier" | "verus_verify")
5282+
&& match &attr.meta {
5283+
$s::Meta::List(list) => {
5284+
matches!(list.tokens.to_string().as_str(), "external" | "external_body")
5285+
}
5286+
_ => false,
5287+
}
5288+
})
5289+
}
5290+
};
52875291
}
5292+
declare_has_external_code!(has_external_code, verus_syn);
5293+
declare_has_external_code!(has_external_code_syn, syn);
52885294

52895295
pub(crate) fn is_encoded_const(attrs: &Vec<Attribute>) -> bool {
52905296
attrs.iter().any(|attr| match &attr.meta {

source/rust_verify_test/tests/syntax_attr.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,32 @@ test_verify_one_file! {
12961296
} => Ok(())
12971297
}
12981298

1299+
test_verify_one_file! {
1300+
#[test] test_skip_desugar_loop_with_external_body code!{
1301+
use vstd::prelude::*;
1302+
1303+
#[verus_verify]
1304+
struct A;
1305+
1306+
impl Iterator for A {
1307+
type Item = u32;
1308+
fn next(&mut self) -> Option<Self::Item> {
1309+
None
1310+
}
1311+
}
1312+
1313+
#[verus_verify(external_body)]
1314+
#[verus_spec(ensures false)]
1315+
fn test_for_loop()
1316+
{
1317+
let a = A;
1318+
for i in a
1319+
{
1320+
}
1321+
}
1322+
} => Ok(())
1323+
}
1324+
12991325
test_verify_one_file! {
13001326
#[test] test_proof_with_struct code!{
13011327
use vstd::prelude::*;

0 commit comments

Comments
 (0)