driver_hax_frontend_exporter/
features.rs1use std::collections::HashSet;
2
3use rustc_driver::{Callbacks, Compilation};
4use rustc_interface::interface;
5use rustc_middle::ty::TyCtxt;
6use rustc_span::symbol::Symbol;
7
8use crate::callbacks_wrapper::CallbacksWrapper;
9
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Features {
15 pub adt_const_params: bool,
16 pub generic_const_exprs: bool,
17 pub register_tool: bool,
18 pub auto_traits: bool,
19 pub negative_impls: bool,
20 pub registered_tools: HashSet<String>,
21}
22
23impl From<&rustc_feature::Features> for Features {
24 fn from(rfeatures: &rustc_feature::Features) -> Self {
25 Features {
26 adt_const_params: rfeatures.adt_const_params(),
27 generic_const_exprs: rfeatures.generic_const_exprs(),
28 register_tool: rfeatures.register_tool(),
29 auto_traits: rfeatures.auto_traits(),
30 negative_impls: rfeatures.negative_impls(),
31 registered_tools: HashSet::new(),
32 }
33 }
34}
35
36impl core::ops::Sub for Features {
37 type Output = Self;
38 fn sub(self, rhs: Self) -> Self {
39 fn sub(x: bool, y: bool) -> bool {
40 x & !y
41 }
42 Features {
43 adt_const_params: sub(self.adt_const_params, rhs.adt_const_params),
44 generic_const_exprs: sub(self.generic_const_exprs, rhs.generic_const_exprs),
45 register_tool: sub(self.register_tool, rhs.register_tool),
46 auto_traits: sub(self.auto_traits, rhs.auto_traits),
47 negative_impls: sub(self.negative_impls, rhs.negative_impls),
48 registered_tools: self
49 .registered_tools
50 .difference(&rhs.registered_tools)
51 .cloned()
52 .collect(),
53 }
54 }
55}
56
57impl Default for Features {
58 fn default() -> Self {
59 (&rustc_feature::Features::default()).into()
60 }
61}
62
63impl Features {
64 pub fn into_iter(&self) -> impl Iterator<Item = String> {
65 [
66 self.adt_const_params.then_some("adt_const_params"),
67 self.generic_const_exprs.then_some("generic_const_exprs"),
68 self.register_tool.then_some("register_tool"),
69 ]
70 .into_iter()
71 .flatten()
72 .map(|s| format!("feature({})", s))
73 .chain(
74 self.registered_tools
75 .clone()
76 .into_iter()
77 .map(|tool| format!("register_tool({})", tool)),
78 )
79 }
80 pub fn detect(options: &hax_types::cli_options::Options, rustc_args: &Vec<String>) -> Self {
83 struct CollectFeatures {
84 features: Features,
85 }
86 impl Callbacks for CollectFeatures {
87 fn after_expansion<'tcx>(
88 &mut self,
89 compiler: &interface::Compiler,
90 tcx: TyCtxt<'tcx>,
91 ) -> Compilation {
92 self.features = tcx.features().into();
93 self.features.registered_tools = tcx
94 .registered_tools(())
95 .iter()
96 .map(|x| x.name.to_ident_string())
97 .collect();
98 rustc_driver::Compilation::Stop
99 }
100 }
101 let mut callbacks = CollectFeatures {
102 features: Features::default(),
103 };
104 let exit_code = rustc_driver::catch_with_exit_code(|| {
105 rustc_driver::run_compiler(
106 rustc_args,
107 &mut CallbacksWrapper {
108 sub: &mut callbacks,
109 options: options.clone(),
110 },
111 )
112 });
113 if exit_code != 0 {
114 std::process::exit(exit_code);
115 }
116 callbacks.features.clone()
117 }
118
119 pub fn detect_forking() -> Self {
124 use std::process::{Command, Stdio};
125 let output = Command::new(std::env::args().next().unwrap())
126 .args(std::env::args().skip(1))
127 .env("HAX_FEATURES_DETECTION_MODE", "1")
128 .stdout(Stdio::piped())
129 .stderr(Stdio::piped())
130 .spawn()
131 .unwrap()
132 .wait_with_output()
133 .unwrap();
134 let stderr = &std::str::from_utf8(&output.stderr).unwrap();
135 serde_json::from_str(stderr).unwrap_or_else(|e| {
136 eprintln!("{}", stderr);
137 tracing::error!("rustc emitted an error, aborting hax custom driver.");
138 std::process::exit(1);
139 })
140 }
141}