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