Skip to content

Commit 29b03a8

Browse files
authored
Merge pull request #859 from xldenis/cdsat-final
2 parents 72337b7 + 55d2485 commit 29b03a8

File tree

25 files changed

+515
-274
lines changed

25 files changed

+515
-274
lines changed

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
{
22
"rust-analyzer.rustc.source": "discover",
3+
"rust-analyzer.diagnostics.disabled": [
4+
"unresolved-proc-macro",
5+
"unresolved-extern-crate"
6+
]
37
}

Cargo.lock

Lines changed: 27 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,14 @@
22

33
*Le marteau-pilon, forges et aciéries de Saint-Chamond, Joseph-Fortuné LAYRAUD, 1889*
44

5-
----
6-
7-
📢 Are you interested in verifying Rust code? Don't know where to start? Please contact me, I'm always looking for case-studies. 📢
8-
9-
----
10-
115
# About
126

13-
**Creusot** is a tool for *deductive verification* of Rust code. It allows you to annotate your code with specifications, invariants and assertions and then *verify* them formally and automatically, *proving*, mathematically, that your code satisfies your specifications.
7+
**Creusot** is a *deductive verifier* for Rust code. It verifies your code is safe from panics, overflows, and assertion failures. By adding annotations you can take it further and verify your code does the *correct* thing.
148

159
Creusot works by translating Rust code to WhyML, the verification and specification language of [Why3](https://why3.lri.fr). Users can then leverage the full power of Why3 to (semi)-automatically discharge the verification conditions!
1610

1711
See [ARCHITECTURE.md](ARCHITECTURE.md) for technical details.
1812

19-
:warning: This is _research_ software, and favors _progress_ over stability :warning:
20-
2113
## Citing Creusot
2214

2315
If you would like to cite Creusot in academic contexts, we encourage you to use our [ICFEM'22 publication](https://hal.inria.fr/hal-03737878/file/main.pdf).

creusot-contracts/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ edition = "2018"
99
[dependencies]
1010
creusot-contracts-proc = { path = "../creusot-contracts-proc", version = "*" }
1111
creusot-contracts-dummy = { path = "../creusot-contracts-dummy", version = "*" }
12-
12+
num-rational = "0.3.2"
1313

1414
[features]
1515
default = []

creusot-contracts/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ pub mod logic;
166166
#[cfg_attr(not(creusot), allow(unused))]
167167
pub mod std;
168168

169+
#[cfg(creusot)]
170+
pub mod num_rational;
171+
169172
#[cfg(creusot)]
170173
pub mod ghost;
171174

creusot-contracts/src/logic/ord.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,55 @@ ord_logic_impl!(i64);
190190
ord_logic_impl!(i128);
191191
ord_logic_impl!(isize);
192192

193+
impl OrdLogic for bool {
194+
#[open]
195+
#[ghost]
196+
fn cmp_log(self, o: Self) -> Ordering {
197+
match (self, o) {
198+
(false, false) => Ordering::Equal,
199+
(true, true) => Ordering::Equal,
200+
(false, true) => Ordering::Less,
201+
(true, false) => Ordering::Greater,
202+
}
203+
}
204+
205+
#[ghost]
206+
#[open(self)]
207+
fn cmp_le_log(_: Self, _: Self) {}
208+
209+
#[ghost]
210+
#[open(self)]
211+
fn cmp_lt_log(_: Self, _: Self) {}
212+
213+
#[ghost]
214+
#[open(self)]
215+
fn cmp_ge_log(_: Self, _: Self) {}
216+
217+
#[ghost]
218+
#[open(self)]
219+
fn cmp_gt_log(_: Self, _: Self) {}
220+
221+
#[ghost]
222+
#[open(self)]
223+
fn refl(_: Self) {}
224+
225+
#[ghost]
226+
#[open(self)]
227+
fn trans(_: Self, _: Self, _: Self, _: Ordering) {}
228+
229+
#[ghost]
230+
#[open(self)]
231+
fn antisym1(_: Self, _: Self) {}
232+
233+
#[ghost]
234+
#[open(self)]
235+
fn antisym2(_: Self, _: Self) {}
236+
237+
#[ghost]
238+
#[open(self)]
239+
fn eq_cmp(_: Self, _: Self) {}
240+
}
241+
193242
impl<A: OrdLogic, B: OrdLogic> OrdLogic for (A, B) {
194243
#[ghost]
195244
#[open]

creusot-contracts/src/logic/seq.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ impl<T> Seq<T> {
144144
}
145145
}
146146

147+
impl<T> Seq<&T> {
148+
#[logic]
149+
#[open]
150+
#[trusted]
151+
#[creusot::builtins = "prelude.Seq.to_owned"]
152+
pub fn to_owned(self) -> Seq<T> {
153+
pearlite! {absurd}
154+
}
155+
}
156+
147157
impl<T> IndexLogic<Int> for Seq<T> {
148158
type Item = T;
149159

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use std::marker::PhantomData;
2+
3+
use crate::{ghost, open, trusted, DeepModel, OrdLogic};
4+
use num_rational::BigRational;
5+
use std::cmp::Ordering;
6+
7+
#[cfg_attr(creusot, creusot::builtins = "prelude.Real.real")]
8+
#[trusted]
9+
pub struct Real(PhantomData<*mut ()>);
10+
11+
#[cfg(creusot)]
12+
impl DeepModel for BigRational {
13+
type DeepModelTy = Real;
14+
15+
#[ghost]
16+
#[open(self)]
17+
#[trusted]
18+
fn deep_model(self) -> Self::DeepModelTy {
19+
absurd
20+
}
21+
}
22+
23+
impl OrdLogic for Real {
24+
#[ghost]
25+
#[open]
26+
fn cmp_log(self, o: Self) -> Ordering {
27+
if self < o {
28+
Ordering::Less
29+
} else if self == o {
30+
Ordering::Equal
31+
} else {
32+
Ordering::Greater
33+
}
34+
}
35+
36+
#[trusted]
37+
#[open]
38+
#[ghost]
39+
#[creusot::builtins = "prelude.Real.(<=)"]
40+
fn le_log(self, _: Self) -> bool {
41+
true
42+
}
43+
44+
#[trusted]
45+
#[open]
46+
#[ghost]
47+
#[creusot::builtins = "prelude.Real.(<)"]
48+
fn lt_log(self, _: Self) -> bool {
49+
true
50+
}
51+
52+
#[trusted]
53+
#[open]
54+
#[ghost]
55+
#[creusot::builtins = "prelude.Real.(>=)"]
56+
fn ge_log(self, _: Self) -> bool {
57+
true
58+
}
59+
60+
#[trusted]
61+
#[open]
62+
#[ghost]
63+
#[creusot::builtins = "prelude.Real.(>)"]
64+
fn gt_log(self, _: Self) -> bool {
65+
true
66+
}
67+
68+
#[ghost]
69+
#[open(self)]
70+
fn cmp_le_log(_: Self, _: Self) {
71+
()
72+
}
73+
74+
#[ghost]
75+
#[open(self)]
76+
fn cmp_lt_log(_: Self, _: Self) {
77+
()
78+
}
79+
80+
#[ghost]
81+
#[open(self)]
82+
fn cmp_ge_log(_: Self, _: Self) {
83+
()
84+
}
85+
86+
#[ghost]
87+
#[open(self)]
88+
fn cmp_gt_log(_: Self, _: Self) {
89+
()
90+
}
91+
92+
#[ghost]
93+
#[open(self)]
94+
fn refl(_: Self) {
95+
()
96+
}
97+
98+
#[ghost]
99+
#[open(self)]
100+
fn trans(_: Self, _: Self, _: Self, _: Ordering) {
101+
()
102+
}
103+
104+
#[ghost]
105+
#[open(self)]
106+
fn antisym1(_: Self, _: Self) {
107+
()
108+
}
109+
110+
#[ghost]
111+
#[open(self)]
112+
fn antisym2(_: Self, _: Self) {
113+
()
114+
}
115+
116+
#[ghost]
117+
#[open(self)]
118+
fn eq_cmp(_: Self, _: Self) {
119+
()
120+
}
121+
}

creusot/src/backend/logic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ fn body_module<'tcx>(ctx: &mut Why3Generator<'tcx>, def_id: DefId) -> (Module, C
162162
let term = ctx.term(def_id).unwrap().clone();
163163
let body = lower_pure(ctx, &mut names, term);
164164

165-
if sig_contract.contract.variant.is_empty() {
165+
if sig_contract.contract.variant.is_empty() && body.is_pure() {
166166
let decl = match util::item_type(ctx.tcx, def_id) {
167167
ItemType::Ghost | ItemType::Logic => Decl::LogicDefn(Logic { sig, body }),
168168
ItemType::Predicate => Decl::PredDecl(Predicate { sig, body }),

creusot/src/backend/term.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,18 @@ impl<'tcx> Lower<'_, 'tcx> {
260260
("final".into(), self.lower_term(*fin)),
261261
],
262262
},
263+
TermKind::Assert { cond } => {
264+
let cond = self.lower_term(*cond);
265+
if self.pure == Purity::Program && !cond.is_pure() {
266+
Exp::Let {
267+
pattern: Pat::VarP("a".into()),
268+
arg: Box::new(cond),
269+
body: Box::new(Exp::Assert(Box::new(Exp::impure_var("a".into())))),
270+
}
271+
} else {
272+
Exp::Assert(Box::new(cond))
273+
}
274+
}
263275
}
264276
}
265277

0 commit comments

Comments
 (0)