Skip to content

Commit d06672b

Browse files
authored
Add initial implementation of the reachability algorithm (rust-lang#1683)
Add a new module reachability which implements the reachability algorithm. Add the end to end logic for the reachability starting from all the harnesses in the target crate. ## Resolved issues: Resolves rust-lang#1672 ## Related RFC: rust-lang#1588 ## Call-outs: We still need to build the custom sysroot in order to fix the missing functions issue. I added a mechanism to run the regression tests using the MIR linker inside compiletest. I ran the regression manually (with the mir_linker enabled) the only tests that didn't pass were: cargo-kani/asm/global_error/doesnt_call_crate_with_global_asm.expected: The global assembly is out of the scope so it doesn't get processed. If we want to keep that behavior, we will have to inspect all items manually. cargo-kani/cargo-tests-dir/expected: This might be a legit issue that I need to fix on kani-driver logic. cargo-ui/dry-run/expected: Not an issue (arguments to the compiler changes).
1 parent b85813e commit d06672b

File tree

18 files changed

+896
-122
lines changed

18 files changed

+896
-122
lines changed

kani-compiler/src/codegen_cprover_gotoc/codegen/function.rs

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use cbmc::InternString;
99
use kani_metadata::HarnessMetadata;
1010
use rustc_ast::ast;
1111
use rustc_ast::{Attribute, LitKind};
12+
use rustc_hir::def::DefKind;
13+
use rustc_hir::def_id::DefId;
1214
use rustc_middle::mir::{HasLocalDecls, Local};
1315
use rustc_middle::ty::print::with_no_trimmed_paths;
1416
use rustc_middle::ty::{self, Instance};
@@ -262,14 +264,47 @@ impl<'tcx> GotocCtx<'tcx> {
262264
self.reset_current_fn();
263265
}
264266

265-
/// This updates the goto context with any information that should be accumulated from a function's
266-
/// attributes.
267-
///
268-
/// Handle all attributes i.e. `#[kani::x]` (which kani_macros translates to `#[kanitool::x]` for us to handle here)
269-
fn handle_kanitool_attributes(&mut self) {
270-
let all_attributes = self.tcx.get_attrs_unchecked(self.current_fn().instance().def_id());
267+
pub fn is_proof_harness(&self, def_id: DefId) -> bool {
268+
let all_attributes = self.tcx.get_attrs_unchecked(def_id);
269+
let (proof_attributes, _) = partition_kanitool_attributes(all_attributes);
270+
if !proof_attributes.is_empty() {
271+
let span = proof_attributes.first().unwrap().span;
272+
if self.tcx.def_kind(def_id) != DefKind::Fn {
273+
self.tcx
274+
.sess
275+
.span_err(span, "The kani::proof attribute can only be applied to functions.");
276+
} else if self.tcx.generics_of(def_id).requires_monomorphization(self.tcx) {
277+
self.tcx
278+
.sess
279+
.span_err(span, "The proof attribute cannot be applied to generic functions.");
280+
}
281+
self.tcx.sess.abort_if_errors();
282+
true
283+
} else {
284+
false
285+
}
286+
}
287+
288+
// Check that all attributes assigned to an item is valid.
289+
pub fn check_attributes(&self, def_id: DefId) {
290+
let all_attributes = self.tcx.get_attrs_unchecked(def_id);
271291
let (proof_attributes, other_attributes) = partition_kanitool_attributes(all_attributes);
272-
if proof_attributes.is_empty() && !other_attributes.is_empty() {
292+
if !proof_attributes.is_empty() {
293+
let span = proof_attributes.first().unwrap().span;
294+
if self.tcx.def_kind(def_id) != DefKind::Fn {
295+
self.tcx
296+
.sess
297+
.span_err(span, "The kani::proof attribute can only be applied to functions.");
298+
} else if self.tcx.generics_of(def_id).requires_monomorphization(self.tcx) {
299+
self.tcx
300+
.sess
301+
.span_err(span, "The proof attribute cannot be applied to generic functions.");
302+
} else if proof_attributes.len() > 1 {
303+
self.tcx
304+
.sess
305+
.span_warn(proof_attributes[0].span, "Only one '#[kani::proof]' allowed");
306+
}
307+
} else if !other_attributes.is_empty() {
273308
self.tcx.sess.span_err(
274309
other_attributes[0].1.span,
275310
format!(
@@ -278,12 +313,16 @@ impl<'tcx> GotocCtx<'tcx> {
278313
)
279314
.as_str(),
280315
);
281-
return;
282-
}
283-
if proof_attributes.len() > 1 {
284-
// No return because this only requires a warning
285-
self.tcx.sess.span_warn(proof_attributes[0].span, "Only one '#[kani::proof]' allowed");
286316
}
317+
}
318+
319+
/// This updates the goto context with any information that should be accumulated from a function's
320+
/// attributes.
321+
///
322+
/// Handle all attributes i.e. `#[kani::x]` (which kani_macros translates to `#[kanitool::x]` for us to handle here)
323+
fn handle_kanitool_attributes(&mut self) {
324+
let all_attributes = self.tcx.get_attrs_unchecked(self.current_fn().instance().def_id());
325+
let (proof_attributes, other_attributes) = partition_kanitool_attributes(all_attributes);
287326
if !proof_attributes.is_empty() {
288327
self.create_proof_harness(other_attributes);
289328
}

0 commit comments

Comments
 (0)