Skip to content

Commit 82d65cc

Browse files
committed
Add tests and implement support for alloc consts
1 parent 408cd6f commit 82d65cc

7 files changed

Lines changed: 113 additions & 17 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use task_encoder::TaskEncoder;
2+
use vir::{Function, FunctionIdn, ViperIdent};
3+
4+
pub struct AddrUseEnc;
5+
6+
#[derive(Debug, Clone)]
7+
pub struct AddrUse<'vir> {
8+
pub ref_from_addr: vir::FunctionIdn<'vir, vir::Int, vir::Ref>,
9+
}
10+
11+
#[derive(Debug, Clone)]
12+
pub struct AddrLocal<'vir> {
13+
pub ref_from_addr: Function<'vir>,
14+
}
15+
16+
impl TaskEncoder for AddrUseEnc {
17+
task_encoder::encoder_cache!(AddrUseEnc);
18+
type TaskDescription<'vir> = ();
19+
type OutputFullLocal<'vir> = AddrLocal<'vir>;
20+
type OutputFullDependency<'vir> = AddrUse<'vir>;
21+
22+
type TaskKey<'vir> = Self::TaskDescription<'vir>;
23+
24+
fn task_to_key<'vir>(_task: &Self::TaskDescription<'vir>) -> Self::TaskKey<'vir> {}
25+
26+
fn do_encode_full<'vir>(
27+
task_key: &Self::TaskKey<'vir>,
28+
deps: &mut task_encoder::TaskEncoderDependencies<'vir, Self>,
29+
) -> task_encoder::EncodeFullResult<'vir, Self> {
30+
let ref_from_addr = FunctionIdn::new(
31+
ViperIdent::new("ref_from_addr"),
32+
vir::TYPE_INT,
33+
vir::TYPE_REF,
34+
);
35+
deps.emit_output_ref(*task_key, ())?;
36+
Ok((
37+
AddrLocal {
38+
ref_from_addr: vir::with_vcx(|vcx| {
39+
let arg_decl = vcx.mk_local_decl("arg", vir::TYPE_INT);
40+
vcx.mk_function(ref_from_addr, (arg_decl,), &[], &[], None, None)
41+
}),
42+
},
43+
AddrUse { ref_from_addr },
44+
))
45+
}
46+
47+
fn emit_outputs<'vir>(program: &mut task_encoder::Program<'vir>) {
48+
let outputs = AddrUseEnc::all_outputs_local_no_errors();
49+
for output in outputs {
50+
program.add_function(output.ref_from_addr);
51+
}
52+
}
53+
}

prusti-encoder/src/encoders/const.rs

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use prusti_interface::PrustiError;
21
use prusti_rustc_interface::{
2+
const_eval::interpret::AllocRange,
33
middle::{
44
mir::{
55
self, ConstValue,
@@ -14,6 +14,7 @@ use vir::CastType;
1414

1515
use crate::encoders::{
1616
MirPureEnc, MirPureEncTask, PureKind,
17+
addr::AddrUseEnc,
1718
ty::{
1819
RustTyDecomposition,
1920
generics::{GParams, GenericParamsEnc},
@@ -70,7 +71,7 @@ impl ConstEnc {
7071
val: ConstValue,
7172
ty: ty::Ty<'vir>,
7273
context: GParams<'vir>,
73-
span: Option<Span>,
74+
_span: Option<Span>,
7475
) -> Result<vir::ExprCSnap<'vir>, EncodeFullError<'vir, Self>> {
7576
vir::with_vcx(|vcx| {
7677
let ty_task = RustTyDecomposition::from_ty(ty, vcx.tcx(), context);
@@ -87,22 +88,41 @@ impl ConstEnc {
8788
GlobalAlloc::Function { .. } => todo!(),
8889
GlobalAlloc::VTable(_, _) => todo!(),
8990
GlobalAlloc::Static(_) => todo!(),
90-
GlobalAlloc::Memory(_mem) => {
91-
// If the `unwrap` ever panics we need a different way to get the inner type
92-
// let inner_ty = ty.builtin_deref(true).map(|t| t.ty).unwrap_or(ty);
93-
let _inner_ty = ty.builtin_deref(true).unwrap();
94-
vcx.with_span(span.unwrap(), |vcx| {
95-
vcx.handle_error(
96-
"application.precondition:assertion.false",
97-
move |_| {
98-
Some(vec![PrustiError::verification(
99-
format!("unsupported const {val:?} might be reached"),
100-
span.unwrap().into(),
101-
)])
91+
GlobalAlloc::Memory(mem) => {
92+
let inner_ty = ty.builtin_deref(true).unwrap();
93+
let inner_ty_task =
94+
RustTyDecomposition::from_ty(inner_ty, vcx.tcx(), context);
95+
let inner_kind = deps
96+
.require_dep::<TyUsePureEnc>(inner_ty_task)?
97+
.expect_primitive();
98+
let bytes = mem
99+
.0
100+
.0
101+
.read_scalar(
102+
&vcx.tcx(),
103+
AllocRange {
104+
start: ptr.prov_and_relative_offset().1,
105+
size: mem.0.0.size(),
102106
},
103-
);
104-
kind.unreachable_to_snap().downcast_ty()
105-
})
107+
false,
108+
)
109+
.unwrap();
110+
let addr_to_ref = deps.require_dep::<AddrUseEnc>(())?.ref_from_addr;
111+
let (prov, offset) = ptr.prov_and_relative_offset();
112+
let alloc_id = prov.alloc_id().0;
113+
let rel_addr =
114+
((alloc_id.get() as u128) << 64) | offset.bytes() as u128;
115+
116+
kind.expect_immref().prim_to_snap(
117+
(addr_to_ref)(
118+
vcx.mk_const_expr(vir::ConstData::Int(rel_addr))
119+
.downcast_ty(),
120+
),
121+
((inner_kind.prim_to_snap)(vcx.mk_const_expr(
122+
vir::ConstData::Int(bytes.to_bits(mem.0.0.size()).unwrap()),
123+
)))
124+
.upcast_ty(),
125+
)
106126
}
107127
GlobalAlloc::TypeId { .. } => todo!(),
108128
}

prusti-encoder/src/encoders/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod impure;
1212
/// Encoders for Rust functions (pure and impure)
1313
pub mod mir_fn;
1414
pub mod custom;
15+
pub mod addr;
1516

1617
pub use r#const::ConstEnc;
1718
pub use impure::fn_wand::{WandEnc, WandEncOutput, WandEncTask};

prusti-encoder/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use task_encoder::TaskEncoder;
2020

2121
use crate::encoders::{
2222
Impure, Pure,
23+
addr::AddrUseEnc,
2324
custom::PairUseEnc,
2425
ty::{
2526
generics::{GArgsCastEnc, trait_impls::TraitImplEnc, traits::TraitEnc},
@@ -106,6 +107,7 @@ pub fn test_entrypoint<'tcx>(
106107
PairUseEnc::emit_outputs(&mut program);
107108
TraitEnc::emit_outputs(&mut program);
108109
TraitImplEnc::emit_outputs(&mut program);
110+
AddrUseEnc::emit_outputs(&mut program);
109111

110112
if std::env::var("LOCAL_TESTING").is_ok() {
111113
std::fs::write("local-testing/simple.vpr", program.code()).unwrap();

prusti-rustc-interface/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ pub extern crate rustc_hir as hir;
3131
pub extern crate rustc_middle as middle;
3232
pub extern crate rustc_mir_dataflow as dataflow;
3333
pub extern crate rustc_trait_selection as trait_selection;
34+
35+
pub extern crate rustc_const_eval as const_eval;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn fail() {
2+
assert_eq!(1, 8);
3+
}
4+
5+
fn fail2() {
6+
let x = 5;
7+
let y = 4 - 1;
8+
assert_eq!(x, y);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn pass() {
2+
assert_eq!(1, 1);
3+
}
4+
5+
fn pass2() {
6+
let x = 5;
7+
let y = 4 + 1;
8+
assert_eq!(x, y);
9+
}

0 commit comments

Comments
 (0)