driver_hax_frontend_exporter/
driver.rs1#![feature(rustc_private)]
2#![feature(box_patterns)]
3#![feature(trait_alias)]
4#![allow(unused_imports)]
5#![allow(unused_variables)]
6#![allow(unreachable_code)]
7#![allow(dead_code)]
8#![feature(macro_metavar_expr)]
9#![feature(internal_output_capture)]
10
11extern crate rustc_ast;
12extern crate rustc_borrowck;
13extern crate rustc_data_structures;
14extern crate rustc_driver;
15extern crate rustc_errors;
16extern crate rustc_feature;
17extern crate rustc_hashes;
18extern crate rustc_hir;
19extern crate rustc_hir_analysis;
20extern crate rustc_index;
21extern crate rustc_interface;
22extern crate rustc_middle;
23extern crate rustc_mir_build;
24extern crate rustc_session;
25extern crate rustc_span;
26extern crate rustc_target;
27extern crate rustc_type_ir;
28
29mod exporter;
30
31use std::collections::HashSet;
32
33use exporter::ExtractionCallbacks;
34
35mod callbacks_wrapper;
36mod features;
37use callbacks_wrapper::*;
38use features::*;
39
40use hax_types::cli_options::{BackendOptions, Command, ENV_VAR_OPTIONS_FRONTEND};
41
42use rustc_driver::{Callbacks, Compilation};
43use rustc_interface::interface;
44use rustc_span::symbol::Symbol;
45
46fn rustc_sysroot() -> String {
47 std::process::Command::new("rustc")
48 .args(["--print", "sysroot"])
49 .output()
50 .ok()
51 .and_then(|out| String::from_utf8(out.stdout).ok())
52 .map(|s| s.trim().to_string())
53 .unwrap()
54}
55
56fn setup_logging() {
57 use tracing_subscriber::prelude::*;
58 let enable_colors = {
59 !std::env::var("RUST_LOG_STYLE").is_ok_and(|style| style == "never")
61 };
62 let subscriber = tracing_subscriber::Registry::default()
63 .with(tracing_subscriber::EnvFilter::from_default_env())
64 .with(
65 tracing_tree::HierarchicalLayer::new(2)
66 .with_ansi(enable_colors)
67 .with_indent_lines(true),
68 );
69 tracing::subscriber::set_global_default(subscriber).unwrap();
70}
71
72const HAX_VANILLA_RUSTC: &str = "HAX_VANILLA_RUSTC";
73
74fn main() {
75 setup_logging();
76
77 let options: hax_types::cli_options::Options = serde_json::from_str(
78 &std::env::var(ENV_VAR_OPTIONS_FRONTEND).unwrap_or_else(|_| {
79 panic!(
80 "Cannot find environnement variable {}",
81 ENV_VAR_OPTIONS_FRONTEND
82 )
83 }),
84 )
85 .unwrap_or_else(|_| {
86 panic!(
87 "Invalid value for the environnement variable {}",
88 ENV_VAR_OPTIONS_FRONTEND
89 )
90 });
91
92 let mut rustc_args: Vec<String> = std::env::args().skip(1).collect();
93 if !rustc_args.iter().any(|arg| arg.starts_with("--sysroot")) {
95 rustc_args.extend(vec!["--sysroot".into(), rustc_sysroot()])
96 };
97
98 if std::env::var("HAX_FEATURES_DETECTION_MODE").is_ok() {
102 use std::io::BufWriter;
103 return serde_json::to_writer(
104 BufWriter::new(std::io::stderr()),
105 &Features::detect(&options, &rustc_args),
106 )
107 .unwrap();
108 }
109
110 let (vanilla_rustc, vanilla_rustc_never) = {
111 let vanilla_rustc = std::env::var(HAX_VANILLA_RUSTC);
112 let vanilla_rustc_never = vanilla_rustc == Ok("never".into());
113 (
114 !vanilla_rustc_never && vanilla_rustc.is_ok(),
115 vanilla_rustc_never,
116 )
117 };
118
119 let is_primary_package = std::env::var("CARGO_PRIMARY_PACKAGE").is_ok();
122 let is_build_script = std::env::var("CARGO_CRATE_NAME") == Ok("build_script_build".to_string()); let translate_package =
124 !vanilla_rustc && !is_build_script && (options.deps || is_primary_package);
125 let mut callbacks: Box<dyn Callbacks + Send> = if translate_package {
126 Box::new(exporter::ExtractionCallbacks {
127 body_types: options.command.body_kinds(),
128 })
129 } else {
130 struct CallbacksNoop;
131 impl Callbacks for CallbacksNoop {}
132 Box::new(CallbacksNoop)
133 };
134
135 if translate_package {
136 let features = Features {
139 adt_const_params: false, generic_const_exprs: false, register_tool: true,
142 registered_tools: HashSet::from_iter(vec![hax_lib_macros_types::HAX_TOOL.into()]),
143 auto_traits: true,
144 negative_impls: true,
145 } - Features::detect_forking();
146 rustc_args = [rustc_args[0].clone()]
147 .into_iter()
148 .chain([
149 "--cfg".into(),
150 hax_lib_macros_types::HAX_CFG_OPTION_NAME.into(),
151 ])
152 .chain(match &options.command {
153 Command::Backend(BackendOptions { backend, .. }) => {
154 vec!["--cfg".into(), format!("hax_backend_{backend}")]
155 }
156 _ => vec![],
157 })
158 .chain(features.into_iter().map(|s| format!("-Zcrate-attr={}", s)))
159 .chain(rustc_args[1..].iter().cloned())
160 .collect();
161 };
162
163 let mut callbacks = CallbacksWrapper {
164 sub: &mut *callbacks,
165 options: {
166 let mut options = options.clone();
167 options.force_cargo_build = if translate_package {
168 options.force_cargo_build
169 } else {
170 hax_types::cli_options::ForceCargoBuild::default()
171 };
172 options
173 },
174 };
175
176 let exit_code = rustc_driver::catch_with_exit_code({
177 let rustc_args = rustc_args.clone();
178 move || rustc_driver::run_compiler(&rustc_args, &mut callbacks)
179 });
180
181 std::process::exit(
182 if !vanilla_rustc_never && translate_package && exit_code == 0 {
183 self::vanilla_rustc()
187 } else {
188 exit_code
189 },
190 )
191}
192
193fn vanilla_rustc() -> i32 {
196 use std::process::{Command, Stdio};
197 let output = Command::new(std::env::args().next().unwrap())
198 .args(std::env::args().skip(1))
199 .env(HAX_VANILLA_RUSTC, "1")
200 .stdout(Stdio::piped())
201 .stderr(Stdio::piped())
202 .spawn()
203 .unwrap()
204 .wait_with_output()
205 .unwrap();
206 if output.status.success() {
207 0
208 } else {
209 let stdout = &std::str::from_utf8(&output.stdout).unwrap();
210 let stderr = &std::str::from_utf8(&output.stderr).unwrap();
211 println!("{stdout}");
212 eprintln!("{stderr}");
213 output.status.code().unwrap_or(1)
214 }
215}