1#![feature(rustc_private)]
4#![expect(incomplete_features)]
5#![feature(box_patterns)]
6#![feature(deref_patterns)]
7#![feature(if_let_guard)]
8#![feature(iter_array_chunks)]
9#![feature(iterator_try_collect)]
10#![feature(let_chains)]
11
12extern crate rustc_ast;
13extern crate rustc_ast_pretty;
14extern crate rustc_driver;
15extern crate rustc_error_messages;
16extern crate rustc_errors;
17extern crate rustc_hir;
18extern crate rustc_index;
19extern crate rustc_interface;
20extern crate rustc_middle;
21extern crate rustc_session;
22extern crate rustc_span;
23extern crate rustc_target;
24
25#[macro_use]
26extern crate charon_lib;
27
28mod driver;
29mod translate;
30
31use charon_lib::{
32 export, logger,
33 options::{self, CliOpts},
34 transform::{
35 Pass, PrintCtxPass, FINAL_CLEANUP_PASSES, INITIAL_CLEANUP_PASSES, LLBC_PASSES,
36 SHARED_FINALIZING_PASSES, ULLBC_PASSES,
37 },
38};
39use std::{env, fmt, panic};
40
41pub enum CharonFailure {
42 CharonError(usize),
44 RustcError,
45 Panic,
46 Serialize,
47}
48
49impl fmt::Display for CharonFailure {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 CharonFailure::RustcError => write!(f, "Code failed to compile")?,
53 CharonFailure::CharonError(err_count) => write!(
54 f,
55 "Charon failed to translate this code ({err_count} errors)"
56 )?,
57 CharonFailure::Panic => write!(f, "Compilation panicked")?,
58 CharonFailure::Serialize => write!(f, "Could not serialize output file")?,
59 }
60 Ok(())
61 }
62}
63
64pub fn transformation_passes(options: &CliOpts) -> Vec<Pass> {
66 let mut passes: Vec<Pass> = vec![];
67
68 passes.push(Pass::NonBody(PrintCtxPass::new(
69 options.print_original_ullbc,
70 format!("# ULLBC after translation from MIR"),
71 )));
72
73 passes.extend(INITIAL_CLEANUP_PASSES);
74 passes.extend(ULLBC_PASSES);
75
76 if !options.ullbc {
77 passes.push(Pass::NonBody(PrintCtxPass::new(
79 options.print_ullbc,
80 format!("# Final ULLBC before control-flow reconstruction"),
81 )));
82 }
83
84 if !options.ullbc {
85 passes.extend(LLBC_PASSES);
86 }
87 passes.extend(SHARED_FINALIZING_PASSES);
88
89 if options.ullbc {
90 passes.push(Pass::NonBody(PrintCtxPass::new(
92 options.print_ullbc,
93 format!("# Final ULLBC before serialization"),
94 )));
95 } else {
96 passes.push(Pass::NonBody(PrintCtxPass::new(
97 options.print_llbc,
98 format!("# Final LLBC before serialization"),
99 )));
100 }
101
102 passes.extend(FINAL_CLEANUP_PASSES);
105 passes
106}
107
108fn run_charon(options: CliOpts) -> Result<usize, CharonFailure> {
110 let Some(mut ctx) = driver::run_rustc_driver(&options)? else {
112 return Ok(0);
114 };
115
116 for pass in transformation_passes(&options) {
119 trace!("# Starting pass {}", pass.name());
120 pass.run(&mut ctx);
121 }
122
123 let error_count = ctx.errors.borrow().error_count;
124
125 if !options.no_serialize {
127 let crate_data = export::CrateData::new(ctx);
128 let dest_file = match options.dest_file.clone() {
129 Some(f) => f,
130 None => {
131 let mut target_filename = options.dest_dir.clone().unwrap_or_default();
132 let crate_name = &crate_data.translated.crate_name;
133 let extension = if options.ullbc { "ullbc" } else { "llbc" };
134 target_filename.push(format!("{crate_name}.{extension}"));
135 target_filename
136 }
137 };
138 trace!("Target file: {:?}", dest_file);
139 crate_data
140 .serialize_to_file(&dest_file)
141 .map_err(|()| CharonFailure::Serialize)?;
142 }
143
144 if options.error_on_warnings && error_count != 0 {
145 return Err(CharonFailure::CharonError(error_count));
146 }
147
148 Ok(error_count)
149}
150
151fn main() {
152 logger::initialize_logger();
154
155 let options: options::CliOpts = match env::var(options::CHARON_ARGS) {
159 Ok(opts) => serde_json::from_str(opts.as_str()).unwrap(),
160 Err(_) => Default::default(),
161 };
162
163 let res = panic::catch_unwind(move || run_charon(options))
165 .map_err(|_| CharonFailure::Panic)
166 .and_then(|x| x);
167
168 match res {
169 Ok(warn_count) => {
170 if warn_count != 0 {
171 let msg = format!("The extraction generated {} warnings", warn_count);
172 eprintln!("warning: {}", msg);
173 }
174 }
175 Err(err) => {
176 log::error!("{err}");
177 let exit_code = match err {
178 CharonFailure::CharonError(_) | CharonFailure::Serialize => 1,
179 CharonFailure::RustcError => 2,
180 CharonFailure::Panic => 101,
182 };
183 std::process::exit(exit_code);
184 }
185 }
186}