Skip to content

Commit 08f4aaf

Browse files
committed
Try to make Prusti compile.
1 parent 010f6bb commit 08f4aaf

File tree

17 files changed

+299
-143
lines changed

17 files changed

+299
-143
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ members = [
2525
exclude = [
2626
"docs/dummy"
2727
]
28+
resolver = "2"
2829

2930
[profile.dev]
3031
debug = 1

prusti-contracts/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ members = [
55
"prusti-specs",
66
"prusti-std",
77
]
8+
resolver = "2"
89

910
# This should not be built as part of Prusti (instead being build by `prusti-contracts-build`)
1011
# It would require setting the `build.rustc-wrapper` in a `../.cargo/config.toml` correctly

prusti-interface/src/environment/body.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,11 @@ impl<'tcx> EnvBody<'tcx> {
168168
{
169169
let monomorphised = if let Some(caller_def_id) = caller_def_id {
170170
let param_env = self.tcx.param_env(caller_def_id);
171-
self.tcx
172-
.subst_and_normalize_erasing_regions(
173-
substs,
174-
param_env,
175-
ty::EarlyBinder::bind(body.0),
176-
)
171+
self.tcx.subst_and_normalize_erasing_regions(
172+
substs,
173+
param_env,
174+
ty::EarlyBinder::bind(body.0),
175+
)
177176
} else {
178177
ty::EarlyBinder::bind(body.0).subst(self.tcx, substs)
179178
};

prusti-interface/src/environment/mir_body/patch/compiler.rs

Lines changed: 106 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ pub struct MirPatch<'tcx> {
2626
pub new_blocks: Vec<BasicBlockData<'tcx>>,
2727
pub new_statements: Vec<(Location, StatementKind<'tcx>)>,
2828
pub new_locals: Vec<LocalDecl<'tcx>>,
29-
pub resume_block: BasicBlock,
29+
pub resume_block: Option<BasicBlock>,
30+
// Only for unreachable in cleanup path.
31+
pub unreachable_cleanup_block: Option<BasicBlock>,
32+
pub terminate_block: Option<BasicBlock>,
33+
pub body_span: Span,
3034
pub next_local: usize,
3135
}
3236

@@ -38,51 +42,87 @@ impl<'tcx> MirPatch<'tcx> {
3842
new_statements: vec![],
3943
new_locals: vec![],
4044
next_local: body.local_decls.len(),
41-
resume_block: START_BLOCK,
45+
resume_block: None,
46+
unreachable_cleanup_block: None,
47+
terminate_block: None,
48+
body_span: body.span,
4249
};
4350

44-
// make sure the MIR we create has a resume block. It is
45-
// completely legal to convert jumps to the resume block
46-
// to jumps to None, but we occasionally have to add
47-
// instructions just before that.
48-
49-
let mut resume_block = None;
50-
let mut resume_stmt_block = None;
5151
for (bb, block) in body.basic_blocks.iter_enumerated() {
52-
if let TerminatorKind::Resume = block.terminator().kind {
53-
if !block.statements.is_empty() {
54-
assert!(resume_stmt_block.is_none());
55-
resume_stmt_block = Some(bb);
56-
} else {
57-
resume_block = Some(bb);
58-
}
59-
break;
52+
// Check if we already have a resume block
53+
if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
54+
result.resume_block = Some(bb);
55+
continue;
56+
}
57+
58+
// Check if we already have an unreachable block
59+
if let TerminatorKind::Unreachable = block.terminator().kind
60+
&& block.statements.is_empty()
61+
&& block.is_cleanup
62+
{
63+
result.unreachable_cleanup_block = Some(bb);
64+
continue;
6065
}
66+
67+
// Check if we already have a terminate block
68+
if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() {
69+
result.terminate_block = Some(bb);
70+
continue;
71+
}
72+
}
73+
74+
result
75+
}
76+
77+
pub fn resume_block(&mut self) -> BasicBlock {
78+
if let Some(bb) = self.resume_block {
79+
return bb;
6180
}
62-
let resume_block = resume_block.unwrap_or_else(|| {
63-
result.new_block(BasicBlockData {
64-
statements: vec![],
65-
terminator: Some(Terminator {
66-
source_info: SourceInfo::outermost(body.span),
67-
kind: TerminatorKind::Resume,
68-
}),
69-
is_cleanup: true,
70-
})
81+
82+
let bb = self.new_block(BasicBlockData {
83+
statements: vec![],
84+
terminator: Some(Terminator {
85+
source_info: SourceInfo::outermost(self.body_span),
86+
kind: TerminatorKind::Resume,
87+
}),
88+
is_cleanup: true,
7189
});
72-
result.resume_block = resume_block;
73-
if let Some(resume_stmt_block) = resume_stmt_block {
74-
result.patch_terminator(
75-
resume_stmt_block,
76-
TerminatorKind::Goto {
77-
target: resume_block,
78-
},
79-
);
90+
self.resume_block = Some(bb);
91+
bb
92+
}
93+
94+
pub fn unreachable_cleanup_block(&mut self) -> BasicBlock {
95+
if let Some(bb) = self.unreachable_cleanup_block {
96+
return bb;
8097
}
81-
result
98+
99+
let bb = self.new_block(BasicBlockData {
100+
statements: vec![],
101+
terminator: Some(Terminator {
102+
source_info: SourceInfo::outermost(self.body_span),
103+
kind: TerminatorKind::Unreachable,
104+
}),
105+
is_cleanup: true,
106+
});
107+
self.unreachable_cleanup_block = Some(bb);
108+
bb
82109
}
83110

84-
pub fn resume_block(&self) -> BasicBlock {
85-
self.resume_block
111+
pub fn terminate_block(&mut self) -> BasicBlock {
112+
if let Some(bb) = self.terminate_block {
113+
return bb;
114+
}
115+
116+
let bb = self.new_block(BasicBlockData {
117+
statements: vec![],
118+
terminator: Some(Terminator {
119+
source_info: SourceInfo::outermost(self.body_span),
120+
kind: TerminatorKind::Terminate,
121+
}),
122+
is_cleanup: true,
123+
});
124+
self.terminate_block = Some(bb);
125+
bb
86126
}
87127

88128
pub fn is_patched(&self, bb: BasicBlock) -> bool {
@@ -94,10 +134,21 @@ impl<'tcx> MirPatch<'tcx> {
94134
Some(index) => self.new_blocks[index].statements.len(),
95135
None => body[bb].statements.len(),
96136
};
97-
Location {
98-
block: bb,
99-
statement_index: offset,
100-
}
137+
Location { block: bb, statement_index: offset }
138+
}
139+
140+
pub fn new_internal_with_info(
141+
&mut self,
142+
ty: Ty<'tcx>,
143+
span: Span,
144+
local_info: LocalInfo<'tcx>,
145+
) -> Local {
146+
let index = self.next_local;
147+
self.next_local += 1;
148+
let mut new_decl = LocalDecl::new(ty, span).internal();
149+
**new_decl.local_info.as_mut().assert_crate_local() = local_info;
150+
self.new_locals.push(new_decl);
151+
Local::new(index)
101152
}
102153

103154
pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
@@ -114,7 +165,6 @@ impl<'tcx> MirPatch<'tcx> {
114165
Local::new(index)
115166
}
116167

117-
#[tracing::instrument(level = "debug", skip(self))]
118168
pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
119169
let block = BasicBlock::new(self.patch_map.len());
120170
debug!("MirPatch: new_block: {:?}: {:?}", block, data);
@@ -123,22 +173,21 @@ impl<'tcx> MirPatch<'tcx> {
123173
block
124174
}
125175

126-
#[tracing::instrument(level = "debug", skip(self))]
127176
pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
128177
assert!(self.patch_map[block].is_none());
178+
debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
129179
self.patch_map[block] = Some(new);
130180
}
131181

132-
#[tracing::instrument(level = "debug", skip(self))]
133182
pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) {
183+
debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt);
134184
self.new_statements.push((loc, stmt));
135185
}
136186

137187
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
138188
self.add_statement(loc, StatementKind::Assign(Box::new((place, rv))));
139189
}
140190

141-
#[tracing::instrument(level = "debug", skip_all)]
142191
pub fn apply(self, body: &mut Body<'tcx>) {
143192
debug!(
144193
"MirPatch: {:?} new temps, starting from index {}: {:?}",
@@ -151,12 +200,17 @@ impl<'tcx> MirPatch<'tcx> {
151200
self.new_blocks.len(),
152201
body.basic_blocks.len()
153202
);
154-
body.basic_blocks_mut().extend(self.new_blocks);
203+
let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
204+
body.basic_blocks.as_mut_preserves_cfg()
205+
} else {
206+
body.basic_blocks.as_mut()
207+
};
208+
bbs.extend(self.new_blocks);
155209
body.local_decls.extend(self.new_locals);
156210
for (src, patch) in self.patch_map.into_iter_enumerated() {
157211
if let Some(patch) = patch {
158212
debug!("MirPatch: patching block {:?}", src);
159-
body[src].terminator_mut().kind = patch;
213+
bbs[src].terminator_mut().kind = patch;
160214
}
161215
}
162216

@@ -170,19 +224,12 @@ impl<'tcx> MirPatch<'tcx> {
170224
delta = 0;
171225
last_bb = loc.block;
172226
}
173-
debug!(
174-
"MirPatch: adding statement {:?} at loc {:?}+{}",
175-
stmt, loc, delta
176-
);
227+
debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
177228
loc.statement_index += delta;
178229
let source_info = Self::source_info_for_index(&body[loc.block], loc);
179-
body[loc.block].statements.insert(
180-
loc.statement_index,
181-
Statement {
182-
source_info,
183-
kind: stmt,
184-
},
185-
);
230+
body[loc.block]
231+
.statements
232+
.insert(loc.statement_index, Statement { source_info, kind: stmt });
186233
delta += 1;
187234
}
188235
}
@@ -201,4 +248,4 @@ impl<'tcx> MirPatch<'tcx> {
201248
};
202249
Self::source_info_for_index(data, loc)
203250
}
204-
}
251+
}

prusti-interface/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(box_patterns)]
1414
#![feature(control_flow_enum)]
1515
#![feature(min_specialization)]
16+
#![feature(let_chains)]
1617
// We may want to remove this in the future.
1718
#![allow(clippy::needless_lifetimes)]
1819

0 commit comments

Comments
 (0)