Skip to content

Commit f751146

Browse files
committed
Introduce rmc::proof function attribute (#668)
* Introduce rmc::proof function attribute * add no_mangle as temporary measure to force function codegen
1 parent 9c92a78 commit f751146

File tree

17 files changed

+226
-9
lines changed

17 files changed

+226
-9
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,6 +3342,9 @@ dependencies = [
33423342
[[package]]
33433343
name = "rmc"
33443344
version = "0.1.0"
3345+
dependencies = [
3346+
"rmc_macros",
3347+
]
33453348

33463349
[[package]]
33473350
name = "rmc-link-restrictions"
@@ -3353,6 +3356,10 @@ dependencies = [
33533356
"serde_json",
33543357
]
33553358

3359+
[[package]]
3360+
name = "rmc_macros"
3361+
version = "0.1.0"
3362+
33563363
[[package]]
33573364
name = "rmc_restrictions"
33583365
version = "0.1.0"

compiler/cbmc/src/goto_program/location.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ impl Location {
3232
}
3333
}
3434

35+
pub fn filename(&self) -> Option<String> {
36+
match self {
37+
Location::Loc { file, .. } => Some(file.to_string()),
38+
_ => None,
39+
}
40+
}
41+
42+
pub fn line(&self) -> Option<u64> {
43+
match self {
44+
Location::Loc { line, .. } => Some(*line),
45+
_ => None,
46+
}
47+
}
48+
3549
/// Convert a location to a short string suitable for (e.g.) logging.
3650
/// Goal is to return just "file:line" as clearly as possible.
3751
pub fn short_string(&self) -> String {

compiler/rustc_codegen_rmc/src/codegen/function.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33

44
//! This file contains functions related to codegenning MIR functions into gotoc
55
6+
use crate::context::metadata::HarnessMetadata;
67
use crate::GotocCtx;
78
use cbmc::goto_program::{Expr, Stmt, Symbol};
9+
use rustc_ast::ast;
810
use rustc_middle::mir::{HasLocalDecls, Local};
911
use rustc_middle::ty::{self, Instance, TyS};
1012
use tracing::{debug, warn};
@@ -98,6 +100,8 @@ impl<'tcx> GotocCtx<'tcx> {
98100
let stmts = self.current_fn_mut().extract_block();
99101
let body = Stmt::block(stmts, loc);
100102
self.symbol_table.update_fn_declaration_with_definition(&name, body);
103+
104+
self.handle_rmctool_attributes();
101105
}
102106
self.reset_current_fn();
103107
}
@@ -199,4 +203,49 @@ impl<'tcx> GotocCtx<'tcx> {
199203
});
200204
self.reset_current_fn();
201205
}
206+
207+
/// This updates the goto context with any information that should be accumulated from a function's
208+
/// attributes.
209+
///
210+
/// Currently, this is only proof harness annotations.
211+
/// i.e. `#[rmc::proof]` (which rmc_macros translates to `#[rmctool::proof]` for us to handle here)
212+
fn handle_rmctool_attributes(&mut self) {
213+
let instance = self.current_fn().instance();
214+
215+
for attr in self.tcx.get_attrs(instance.def_id()) {
216+
match rmctool_attr_name(attr).as_deref() {
217+
Some("proof") => self.handle_rmctool_proof(),
218+
_ => {}
219+
}
220+
}
221+
}
222+
223+
/// Update `self` (the goto context) to add the current function as a listed proof harness
224+
fn handle_rmctool_proof(&mut self) {
225+
let current_fn = self.current_fn();
226+
let pretty_name = current_fn.readable_name().to_owned();
227+
let mangled_name = current_fn.name();
228+
let loc = self.codegen_span(&current_fn.mir().span);
229+
230+
let harness = HarnessMetadata {
231+
pretty_name,
232+
mangled_name,
233+
original_file: loc.filename().unwrap(),
234+
original_line: loc.line().unwrap().to_string(),
235+
};
236+
237+
self.proof_harnesses.push(harness);
238+
}
239+
}
240+
241+
/// If the attribute is named `rmctool::name`, this extracts `name`
242+
fn rmctool_attr_name(attr: &ast::Attribute) -> Option<String> {
243+
match &attr.kind {
244+
ast::AttrKind::Normal(ast::AttrItem { path: ast::Path { segments, .. }, .. }, _)
245+
if segments.len() == 2 && segments[0].ident.as_str() == "rmctool" =>
246+
{
247+
Some(segments[1].ident.as_str().to_string())
248+
}
249+
_ => None,
250+
}
202251
}

compiler/rustc_codegen_rmc/src/compiler_interface.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
//! This file contains the code necessary to interface with the compiler backend
55
6+
use crate::context::metadata::RmcMetadata;
67
use crate::GotocCtx;
7-
88
use bitflags::_core::any::Any;
99
use cbmc::goto_program::symtab_transformer;
1010
use cbmc::goto_program::SymbolTable;
@@ -29,9 +29,10 @@ use tracing::{debug, warn};
2929

3030
// #[derive(RustcEncodable, RustcDecodable)]
3131
pub struct GotocCodegenResult {
32-
pub type_map: BTreeMap<InternedString, InternedString>,
33-
pub symtab: SymbolTable,
3432
pub crate_name: rustc_span::Symbol,
33+
pub metadata: RmcMetadata,
34+
pub symtab: SymbolTable,
35+
pub type_map: BTreeMap<InternedString, InternedString>,
3536
pub vtable_restrictions: Option<VtableCtxResults>,
3637
}
3738

@@ -128,7 +129,7 @@ impl CodegenBackend for GotocCodegenBackend {
128129
}
129130

130131
// perform post-processing symbol table passes
131-
let symbol_table = symtab_transformer::do_passes(
132+
let symtab = symtab_transformer::do_passes(
132133
c.symbol_table,
133134
&tcx.sess.opts.debugging_opts.symbol_table_passes,
134135
);
@@ -144,11 +145,14 @@ impl CodegenBackend for GotocCodegenBackend {
144145
None
145146
};
146147

148+
let metadata = RmcMetadata { proof_harnesses: c.proof_harnesses };
149+
147150
Box::new(GotocCodegenResult {
148-
type_map,
149-
symtab: symbol_table,
150151
crate_name: tcx.crate_name(LOCAL_CRATE) as rustc_span::Symbol,
151-
vtable_restrictions: vtable_restrictions,
152+
metadata,
153+
symtab,
154+
type_map,
155+
vtable_restrictions,
152156
})
153157
}
154158

@@ -176,7 +180,7 @@ impl CodegenBackend for GotocCodegenBackend {
176180
let base_filename = outputs.path(OutputType::Object);
177181
write_file(&base_filename, "symtab.json", &result.symtab);
178182
write_file(&base_filename, "type_map.json", &result.type_map);
179-
183+
write_file(&base_filename, "rmc-metadata.json", &result.metadata);
180184
// If they exist, write out vtable virtual call function pointer restrictions
181185
if let Some(restrictions) = result.vtable_restrictions {
182186
write_file(&base_filename, "restrictions.json", &restrictions);

compiler/rustc_codegen_rmc/src/context/goto_ctx.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! Any MIR specific functionality (e.g. codegen etc) should live in specialized files that use
1515
//! this structure as input.
1616
use super::current_fn::CurrentFnCtx;
17+
use super::metadata::HarnessMetadata;
1718
use super::vtable_ctx::VtableCtx;
1819
use crate::overrides::{fn_hooks, GotocHooks};
1920
use crate::utils::full_crate_name;
@@ -53,6 +54,7 @@ pub struct GotocCtx<'tcx> {
5354
pub vtable_ctx: VtableCtx,
5455
pub current_fn: Option<CurrentFnCtx<'tcx>>,
5556
pub type_map: FxHashMap<InternedString, Ty<'tcx>>,
57+
pub proof_harnesses: Vec<HarnessMetadata>,
5658
}
5759

5860
/// Constructor
@@ -72,6 +74,7 @@ impl<'tcx> GotocCtx<'tcx> {
7274
vtable_ctx: VtableCtx::new(emit_vtable_restrictions),
7375
current_fn: None,
7476
type_map: FxHashMap::default(),
77+
proof_harnesses: vec![],
7578
}
7679
}
7780
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! This module should be factored out into its own separate crate eventually,
5+
//! but leaving it here for now...
6+
7+
use serde::Serialize;
8+
9+
/// We emit this structure for each annotated proof harness we find
10+
#[derive(Serialize)]
11+
pub struct HarnessMetadata {
12+
/// The name the user gave to the function
13+
pub pretty_name: String,
14+
/// The name of the function in the CBMC symbol table
15+
pub mangled_name: String,
16+
/// The (currently full-) path to the file this proof harness was declared within
17+
pub original_file: String,
18+
/// The line in that file where the proof harness begins
19+
pub original_line: String,
20+
}
21+
22+
/// The structure of `.rmc-metadata.json` files, which are emitted for each crate
23+
#[derive(Serialize)]
24+
pub struct RmcMetadata {
25+
pub proof_harnesses: Vec<HarnessMetadata>,
26+
}

compiler/rustc_codegen_rmc/src/context/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
99
mod current_fn;
1010
mod goto_ctx;
11+
pub mod metadata;
1112
mod vtable_ctx;
1213

1314
pub use goto_ctx::GotocCtx;

library/rmc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ edition = "2018"
88
license = "MIT OR Apache-2.0"
99

1010
[dependencies]
11+
rmc_macros = { path = "../rmc_macros" }

library/rmc/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ pub fn nondet<T>() -> T {
5353
#[inline(never)]
5454
#[rustc_diagnostic_item = "RmcExpectFail"]
5555
pub fn expect_fail(_cond: bool, _message: &str) {}
56+
57+
/// RMC proc macros must be in a separate crate
58+
pub use rmc_macros::*;

library/rmc_macros/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
[package]
5+
name = "rmc_macros"
6+
version = "0.1.0"
7+
edition = "2018"
8+
license = "MIT OR Apache-2.0"
9+
10+
[lib]
11+
proc-macro = true
12+
13+
[dependencies]

0 commit comments

Comments
 (0)