Skip to main content

charon_driver/
main.rs

1//! The Charon driver, which calls Rustc with callbacks to compile some Rust
2//! crate to LLBC.
3// For rustdoc: prevents overflows
4#![recursion_limit = "256"]
5#![feature(rustc_private)]
6#![allow(clippy::arc_with_non_send_sync)]
7#![allow(clippy::borrowed_box)]
8#![allow(clippy::derivable_impls)]
9#![allow(clippy::field_reassign_with_default)]
10#![allow(clippy::manual_map)]
11#![allow(clippy::mem_replace_with_default)]
12#![allow(clippy::useless_format)]
13#![feature(deref_patterns)]
14#![feature(iter_array_chunks)]
15#![feature(iterator_try_collect)]
16#![feature(macro_metavar_expr)]
17#![feature(sized_hierarchy)]
18#![feature(trait_alias)]
19#![feature(type_changing_struct_update)]
20
21extern crate rustc_abi;
22extern crate rustc_apfloat;
23extern crate rustc_ast;
24extern crate rustc_ast_pretty;
25extern crate rustc_const_eval;
26extern crate rustc_data_structures;
27extern crate rustc_driver;
28extern crate rustc_error_messages;
29extern crate rustc_errors;
30extern crate rustc_hashes;
31extern crate rustc_hir;
32extern crate rustc_hir_analysis;
33extern crate rustc_index;
34extern crate rustc_infer;
35extern crate rustc_interface;
36extern crate rustc_lexer;
37extern crate rustc_middle;
38extern crate rustc_mir_build;
39extern crate rustc_mir_transform;
40extern crate rustc_session;
41extern crate rustc_span;
42extern crate rustc_target;
43extern crate rustc_trait_selection;
44extern crate rustc_type_ir;
45
46#[macro_use]
47extern crate charon_lib;
48
49mod driver;
50#[macro_use]
51pub mod hax;
52mod translate;
53
54use charon_lib::{export, logger, transform::run_transformation_passes};
55use std::{fmt, panic};
56
57pub enum CharonFailure {
58    /// The usize is the number of errors.
59    CharonError(usize),
60    RustcError,
61    Panic,
62    Serialize,
63}
64
65impl fmt::Display for CharonFailure {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            CharonFailure::RustcError => write!(f, "Code failed to compile")?,
69            CharonFailure::CharonError(err_count) => write!(
70                f,
71                "Charon failed to translate this code ({err_count} errors)"
72            )?,
73            CharonFailure::Panic => write!(f, "Compilation panicked")?,
74            CharonFailure::Serialize => write!(f, "Could not serialize output file")?,
75        }
76        Ok(())
77    }
78}
79
80/// Run charon. Returns the number of warnings generated.
81fn run_charon() -> Result<usize, CharonFailure> {
82    // Run the driver machinery.
83    let Some((mut ctx, options)) = driver::run_rustc_driver()? else {
84        // We didn't run charon.
85        return Ok(0);
86    };
87
88    // The bulk of the translation is done, we no longer need to interact with rustc internals. We
89    // run several passes that simplify the items and cleanup the bodies.
90    run_transformation_passes(&options, &mut ctx);
91
92    let error_count = ctx.errors.borrow().error_count;
93
94    // # Final step: generate the files.
95    let targets = options.targets(&ctx.translated.crate_name);
96    trace!("Targets: {:?}", targets);
97    export::CrateData::new(ctx)
98        .serialize_to_files(targets)
99        .map_err(|()| CharonFailure::Serialize)?;
100
101    if options.error_on_warnings && error_count != 0 {
102        return Err(CharonFailure::CharonError(error_count));
103    }
104
105    Ok(error_count)
106}
107
108fn main() {
109    // Initialize the logger
110    logger::initialize_logger();
111
112    // Catch any and all panics coming from charon to display a clear error.
113    let res = panic::catch_unwind(run_charon)
114        .map_err(|_| CharonFailure::Panic)
115        .and_then(|x| x);
116
117    match res {
118        Ok(warn_count) => {
119            if warn_count != 0 {
120                let msg = format!("The extraction generated {} warnings", warn_count);
121                eprintln!("warning: {}", msg);
122            }
123        }
124        Err(err) => {
125            log::error!("{err}");
126            let exit_code = match err {
127                CharonFailure::CharonError(_) | CharonFailure::Serialize => 1,
128                CharonFailure::RustcError => 2,
129                // This is a real panic, exit with the standard rust panic error code.
130                CharonFailure::Panic => 101,
131            };
132            std::process::exit(exit_code);
133        }
134    }
135}