1#![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(sized_hierarchy)]
17#![feature(type_changing_struct_update)]
18
19extern crate rustc_abi;
20extern crate rustc_ast;
21extern crate rustc_ast_pretty;
22extern crate rustc_data_structures;
23extern crate rustc_driver;
24extern crate rustc_hir;
25extern crate rustc_index;
26extern crate rustc_interface;
27extern crate rustc_middle;
28extern crate rustc_mir_transform;
29extern crate rustc_session;
30extern crate rustc_span;
31extern crate rustc_structures;
32extern crate rustc_target;
33extern crate rustc_trait_selection;
34
35#[macro_use]
36extern crate charon_lib;
37
38mod driver;
39#[macro_use]
40pub mod hax;
41#[allow(unused)]
42#[path = "../charon/toolchain.rs"]
43mod toolchain;
44mod translate;
45
46use charon_lib::{export, logger, transform::run_transformation_passes};
47use std::{fmt, panic};
48
49pub enum CharonFailure {
50 CharonError(usize),
52 RustcError,
53 Panic,
54 Serialize,
55 MiniRustTranslationError,
56 MiniRustPanic,
57 MiniRustUb,
58 MiniRustOther,
59}
60
61impl fmt::Display for CharonFailure {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 match self {
64 CharonFailure::RustcError => write!(f, "Code failed to compile")?,
65 CharonFailure::CharonError(err_count) => write!(
66 f,
67 "Charon failed to translate this code ({err_count} errors)"
68 )?,
69 CharonFailure::Panic => write!(f, "Compilation panicked")?,
70 CharonFailure::Serialize => write!(f, "Could not serialize output file")?,
71 CharonFailure::MiniRustTranslationError => {
72 write!(f, "Could not compile the program to MiniRust")?
73 }
74 CharonFailure::MiniRustPanic => write!(f, "MiniRust program panicked")?,
75 CharonFailure::MiniRustUb => write!(f, "MiniRust program encountered UB")?,
76 CharonFailure::MiniRustOther => write!(f, "MiniRust execution failed")?,
77 }
78 Ok(())
79 }
80}
81
82fn run_charon() -> Result<usize, CharonFailure> {
84 let Some((mut ctx, options)) = driver::run_rustc_driver()? else {
86 return Ok(0);
88 };
89
90 charon_lib::timing::time("transformation-passes", || {
93 run_transformation_passes(&options, &mut ctx)
94 });
95
96 let error_count = ctx.errors.borrow().error_count;
97
98 let targets = options.targets(&ctx.translated.crate_name);
100 trace!("Targets: {:?}", targets);
101 let crate_name = ctx.translated.crate_name.clone();
102 let crate_data = export::CrateData::new(ctx);
103 charon_lib::timing::time("serialize", || crate_data.serialize_to_files(targets))
104 .map_err(|()| CharonFailure::Serialize)?;
105 #[cfg(feature = "minirust")]
106 if options.run_with_minirust {
107 charon_lib::timing::time("run-with-minirust", || {
108 charon_lib::minirust::run::<minirust_rs::prelude::x86_64>(&crate_data.translated)
109 })
110 .map_err(|err| {
111 use charon_lib::minirust::RunError;
112 match err {
113 RunError::Translation(error) => {
114 anstream::eprintln!(
115 "{}\n",
116 error.render(&crate_data.translated, charon_lib::errors::Level::ERROR)
117 );
118 CharonFailure::MiniRustTranslationError
119 }
120 RunError::Panic => CharonFailure::MiniRustPanic,
121 RunError::Ub(message) => {
122 anstream::eprintln!("MiniRust UB: {message}");
123 CharonFailure::MiniRustUb
124 }
125 RunError::Other(error) => {
126 anstream::eprintln!("MiniRust execution failed: {error:?}");
127 CharonFailure::MiniRustOther
128 }
129 }
130 })?;
131 }
132 charon_lib::timing::report(&crate_name);
133
134 if options.error_on_warnings && error_count != 0 {
135 return Err(CharonFailure::CharonError(error_count));
136 }
137
138 Ok(error_count)
139}
140
141fn main() {
142 logger::initialize_logger();
144
145 let res = panic::catch_unwind(run_charon)
147 .map_err(|_| CharonFailure::Panic)
148 .and_then(|x| x);
149
150 match res {
151 Ok(warn_count) => {
152 if warn_count != 0 {
153 let msg = format!("The extraction generated {} warnings", warn_count);
154 eprintln!("warning: {}", msg);
155 }
156 }
157 Err(err) => {
158 log::error!("{err}");
159 let exit_code = match err {
160 CharonFailure::CharonError(_)
161 | CharonFailure::Serialize
162 | CharonFailure::MiniRustTranslationError => 1,
163 CharonFailure::RustcError => 2,
164 CharonFailure::MiniRustPanic => 3,
165 CharonFailure::MiniRustUb => 4,
166 CharonFailure::MiniRustOther => 5,
167 CharonFailure::Panic => 101,
169 };
170 std::process::exit(exit_code);
171 }
172 }
173}