Skip to main content

charon_lib/
options.rs

1//! The options that control charon behavior.
2use annotate_snippets::Level;
3use clap::ValueEnum;
4use indoc::indoc;
5use itertools::Itertools;
6use macros::EnumAsGetters;
7use serde::{Deserialize, Serialize};
8use std::path::PathBuf;
9
10use crate::{
11    ast::*,
12    errors::{ErrorCtx, display_unspanned_error},
13    name_matcher::NamePattern,
14    raise_error, register_error,
15};
16
17/// The name of the environment variable we use to save the serialized Cli options
18/// when calling charon-driver from cargo-charon.
19pub const CHARON_ARGS: &str = "CHARON_ARGS";
20
21// This structure is used to store the command-line instructions.
22// We automatically derive a command-line parser based on this structure.
23// Note that the doc comments are used to generate the help message when using
24// `--help`.
25//
26// Note that because we need to transmit the options to the charon driver,
27// we store them in a file before calling this driver (hence the `Serialize`,
28// `Deserialize` options).
29#[derive(Debug, Default, Clone, clap::Args, PartialEq, Eq, Serialize, Deserialize)]
30#[clap(name = "Charon")]
31#[charon::rename("cli_options")]
32pub struct CliOpts {
33    /// Extract the unstructured LLBC (i.e., don't reconstruct the control-flow)
34    #[clap(long)]
35    #[serde(default)]
36    pub ullbc: bool,
37    /// Whether to precisely translate drops and drop-related code. For this, we add explicit
38    /// `Destruct` bounds to all generic parameters, set the MIR level to at least `elaborated`,
39    /// and attempt to retrieve drop glue for all types.
40    ///
41    /// This option is known to cause panics inside rustc, because their drop handling is not
42    /// design to work on polymorphic types. To silence the warning, pass appropriate `--opaque
43    /// '{impl core::marker::Destruct for some::Type}'` options.
44    ///
45    /// Without this option, drops may be "conditional" and we may lack information about what code
46    /// is run on drop in a given polymorphic function body.
47    #[clap(long)]
48    #[serde(default)]
49    pub precise_drops: bool,
50    /// If activated, this skips borrow-checking of the crate.
51    #[clap(long)]
52    #[serde(default)]
53    pub skip_borrowck: bool,
54    /// The MIR stage to extract. This is only relevant for the current crate; for dpendencies only
55    /// MIR optimized is available.
56    #[arg(long)]
57    pub mir: Option<MirLevel>,
58    /// Extra flags to pass to rustc.
59    #[clap(long = "rustc-arg")]
60    #[serde(default)]
61    pub rustc_args: Vec<String>,
62
63    /// Monomorphize the items encountered when possible. Generic items found in the crate are
64    /// skipped. To only translate a particular call graph, use `--start-from`. Note: this doesn't
65    /// currently support `dyn Trait`.
66    #[clap(long, visible_alias = "mono")]
67    #[serde(default)]
68    pub monomorphize: bool,
69    /// Partially monomorphize items to make it so that no item is ever monomorphized with a
70    /// mutable reference (or type containing one); said differently, so that the presence of
71    /// mutable references in a type is independent of its generics. This is used by Aeneas.
72    #[clap(
73        long,
74        value_name("INCLUDE_TYPES"),
75        num_args(0..=1),
76        require_equals(true),
77        default_missing_value("all"),
78    )]
79    #[serde(default)]
80    pub monomorphize_mut: Option<MonomorphizeMut>,
81
82    /// A list of item paths to use as starting points for the translation. We will translate these
83    /// items and any items they refer to, according to the opacity rules. When absent, we start
84    /// from the path `crate` (which translates the whole crate).
85    #[clap(long, value_delimiter = ',')]
86    #[serde(default)]
87    pub start_from: Vec<String>,
88    /// Same as --start-from, but won't raise an error if a pattern doesn't match any item. This is useful
89    /// when the patterns are generated by a build script and may be out of sync with the code.
90    #[clap(long, value_delimiter = ',')]
91    #[serde(default)]
92    pub start_from_if_exists: Vec<String>,
93    /// Use all the items annotated with the given attribute as starting points for translation
94    /// (except modules).
95    /// If an attribute name is not specified, `verify::start_from` is used.
96    #[clap(
97        long,
98        value_name("ATTRIBUTE"),
99        num_args(0..=1),
100        require_equals(true),
101        default_missing_value("verify::start_from"),
102    )]
103    #[serde(default)]
104    pub start_from_attribute: Option<String>,
105    /// Use all the `pub` items as starting points for translation (except modules).
106    #[clap(long)]
107    #[serde(default)]
108    pub start_from_pub: bool,
109
110    /// Whitelist of items to translate. These use the name-matcher syntax.
111    #[clap(
112        long,
113        help = indoc!("
114            Whitelist of items to translate. These use the name-matcher syntax (note: this differs
115            a bit from the ocaml NameMatcher).
116
117            Note: This is very rough at the moment. E.g. this parses `u64` as a path instead of the
118            built-in type. It is also not possible to filter a trait impl (this will only filter
119            its methods). Please report bugs or missing features.
120
121            Examples:
122              - `crate::module1::module2::item`: refers to this item and all its subitems (e.g.
123                  submodules or trait methods);
124              - `crate::module1::module2::item::_`: refers only to the subitems of this item;
125              - `core::convert::{impl core::convert::Into<_> for _}`: retrieve the body of this
126                  very useful impl;
127
128            When multiple patterns in the `--include` and `--opaque` options match the same item,
129            the most precise pattern wins. E.g.: `charon --opaque crate::module --include
130            crate::module::_` makes the `module` opaque (we won't explore its contents), but the
131            items in it transparent (we will translate them if we encounter them.)
132    "))]
133    #[serde(default)]
134    #[charon::rename("included")]
135    pub include: Vec<String>,
136    /// Blacklist of items to keep opaque. Works just like `--include`, see the doc there.
137    #[clap(long)]
138    #[serde(default)]
139    pub opaque: Vec<String>,
140    /// Blacklist of items to not translate at all. Works just like `--include`, see the doc there.
141    #[clap(long)]
142    #[serde(default)]
143    pub exclude: Vec<String>,
144    /// Usually we skip the bodies of foreign methods and structs with private fields. When this
145    /// flag is on, we don't.
146    #[clap(long)]
147    #[serde(default)]
148    pub extract_opaque_bodies: bool,
149    /// Usually we skip the provided methods that aren't used. When this flag is on, we translate
150    /// them all.
151    #[clap(long)]
152    #[serde(default)]
153    pub translate_all_methods: bool,
154
155    /// Transform the associate types of traits to be type parameters instead. This takes a list
156    /// of name patterns of the traits to transform, using the same syntax as `--include`.
157    #[clap(long, alias = "remove-associated-types")]
158    #[serde(default)]
159    pub lift_associated_types: Vec<String>,
160    /// Whether to hide various marker traits such as `Sized`, `Sync`, `Send` and `Destruct`
161    /// anywhere they show up. This can considerably speed up translation.
162    #[clap(long)]
163    #[serde(default)]
164    pub hide_marker_traits: bool,
165    /// Remove trait clauses from type declarations. Must be combined with
166    /// `--remove-associated-types` for type declarations that use trait associated types in their
167    /// fields, otherwise this will result in errors.
168    #[clap(long)]
169    #[serde(default)]
170    pub remove_adt_clauses: bool,
171    /// Hide the `A` type parameter on standard library containers (`Box`, `Vec`, etc).
172    #[clap(long)]
173    #[serde(default)]
174    pub hide_allocator: bool,
175    /// Trait method declarations take a `Self: Trait` clause as parameter, so that they can be
176    /// reused by multiple trait impls. This however causes trait definitions to be mutually
177    /// recursive with their method declarations. This flag removes `Self` clauses that aren't used
178    /// to break this mutual recursion when possible.
179    #[clap(long)]
180    #[serde(default)]
181    pub remove_unused_self_clauses: bool,
182
183    /// Transform precise drops to the equivalent `drop_in_place(&raw mut p)` call.
184    #[clap(long)]
185    #[serde(default)]
186    pub desugar_drops: bool,
187    /// Transform array-to-slice unsizing, repeat expressions, and raw pointer construction into
188    /// builtin functions in ULLBC.
189    #[clap(long)]
190    #[serde(default)]
191    pub ops_to_function_calls: bool,
192    /// Transform array/slice indexing into builtin functions in ULLBC. Note that this may
193    /// introduce UB since it creates references that were not normally created, including when
194    /// indexing behind a raw pointer.
195    #[clap(long)]
196    #[serde(default)]
197    pub index_to_function_calls: bool,
198    /// Treat `Box<T>` as if it was a built-in type.
199    #[clap(long)]
200    #[serde(default)]
201    pub treat_box_as_builtin: bool,
202    /// Do not inline or evaluate constants.
203    #[clap(long)]
204    #[serde(default)]
205    pub raw_consts: bool,
206    /// Replace string literal constants with a constant u8 array that gets unsized,
207    /// expliciting the fact a string constant has a hidden reference.
208    #[clap(long)]
209    #[serde(default)]
210    pub unsized_strings: bool,
211    /// Replace "bound checks followed by UB-on-overflow operation" with the corresponding
212    /// panic-on-overflow operation. This loses unwinding information.
213    #[clap(long)]
214    #[serde(default)]
215    pub reconstruct_fallible_operations: bool,
216    /// Replace "if x { panic() }" with "assert(x)".
217    #[clap(long)]
218    #[serde(default)]
219    pub reconstruct_asserts: bool,
220    /// Use `DeBruijnVar::Free` for the variables bound in item signatures, instead of
221    /// `DeBruijnVar::Bound` everywhere. This simplifies the management of generics for projects
222    /// that don't intend to manipulate them too much.
223    #[clap(long)]
224    #[serde(default)]
225    pub unbind_item_vars: bool,
226
227    /// Pretty-print the ULLBC immediately after extraction from MIR.
228    #[clap(long)]
229    #[serde(default)]
230    pub print_original_ullbc: bool,
231    /// Pretty-print the ULLBC after applying the micro-passes (before serialization/control-flow reconstruction).
232    #[clap(long)]
233    #[serde(default)]
234    pub print_ullbc: bool,
235    /// Pretty-print the LLBC just after we built it (i.e., immediately after loop reconstruction).
236    #[clap(long)]
237    #[serde(default)]
238    pub print_built_llbc: bool,
239    /// Pretty-print the final LLBC (after all the cleaning micro-passes).
240    #[clap(long)]
241    #[serde(default)]
242    pub print_llbc: bool,
243
244    /// The destination directory. Files will be generated as `<dest_dir>/<crate_name>.{u}llbc`,
245    /// unless `dest_file` is set. `dest_dir` defaults to the current directory.
246    #[clap(long = "dest", value_parser)]
247    #[serde(default)]
248    pub dest_dir: Option<PathBuf>,
249    /// The destination file. By default `<dest_dir>/<crate_name>.llbc`. If this is set we ignore
250    /// `dest_dir`.
251    #[clap(long, value_parser)]
252    #[serde(default)]
253    pub dest_file: Option<PathBuf>,
254    /// Don't deduplicate values (types, trait refs) in the .(u)llbc file. This makes the file easier to inspect.
255    #[clap(long)]
256    #[serde(default)]
257    pub no_dedup_serialized_ast: bool,
258    /// Don't serialize the final (U)LLBC to a file.
259    #[clap(long)]
260    #[serde(default)]
261    pub no_serialize: bool,
262    /// Panic on the first error. This is useful for debugging.
263    #[clap(long)]
264    #[serde(default)]
265    pub abort_on_error: bool,
266    /// Consider any warnings to be errors.
267    #[clap(long)]
268    #[serde(default)]
269    pub error_on_warnings: bool,
270
271    /// Named builtin sets of options.
272    #[clap(long)]
273    #[arg(value_enum)]
274    pub preset: Option<Preset>,
275}
276
277/// The MIR stage to use. This is only relevant for the current crate: for dependencies, only mir
278/// optimized is available (or mir elaborated for consts).
279#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize)]
280pub enum MirLevel {
281    /// The MIR just after MIR lowering.
282    Built,
283    /// The MIR after const promotion. This is the MIR used by the borrow-checker.
284    Promoted,
285    /// The MIR after drop elaboration. This is the first MIR to include all the runtime
286    /// information.
287    Elaborated,
288    /// The MIR after optimizations. Charon disables all the optimizations it can, so this is
289    /// sensibly the same MIR as the elaborated MIR.
290    Optimized,
291}
292
293/// Presets to make it easier to tweak options without breaking dependent projects. Eventually we
294/// should define semantically-meaningful presets instead of project-specific ones.
295#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize)]
296#[non_exhaustive]
297pub enum Preset {
298    /// The default translation used before May 2025. After that, many passes were made optional
299    /// and disabled by default.
300    OldDefaults,
301    /// Emit the MIR as unmodified as possible. This is very imperfect for now, we should make more
302    /// passes optional.
303    RawMir,
304    Aeneas,
305    Eurydice,
306    Soteria,
307    Tests,
308}
309
310#[derive(
311    Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize,
312)]
313pub enum MonomorphizeMut {
314    /// Monomorphize any item instantiated with `&mut`.
315    #[default]
316    All,
317    /// Monomorphize all non-typedecl items instantiated with `&mut`.
318    ExceptTypes,
319}
320
321impl CliOpts {
322    pub fn apply_preset(&mut self) {
323        if let Some(preset) = self.preset {
324            match preset {
325                Preset::OldDefaults => {
326                    self.treat_box_as_builtin = true;
327                    self.hide_allocator = true;
328                    self.ops_to_function_calls = true;
329                    self.index_to_function_calls = true;
330                    self.reconstruct_fallible_operations = true;
331                    self.reconstruct_asserts = true;
332                    self.unbind_item_vars = true;
333                }
334                Preset::RawMir => {
335                    self.extract_opaque_bodies = true;
336                    self.raw_consts = true;
337                    self.ullbc = true;
338                }
339                Preset::Aeneas => {
340                    self.lift_associated_types.push("*".to_owned());
341                    self.treat_box_as_builtin = true;
342                    self.ops_to_function_calls = true;
343                    self.index_to_function_calls = true;
344                    self.reconstruct_fallible_operations = true;
345                    self.reconstruct_asserts = true;
346                    self.hide_marker_traits = true;
347                    self.hide_allocator = true;
348                    self.remove_unused_self_clauses = true;
349                    self.unbind_item_vars = true;
350                    // Hide drop impls because they often involve nested borrows. which aeneas
351                    // doesn't handle yet.
352                    self.exclude.push("core::ops::drop::Drop".to_owned());
353                    self.exclude
354                        .push("{impl core::ops::drop::Drop for _}".to_owned());
355                }
356                Preset::Eurydice => {
357                    self.hide_allocator = true;
358                    self.treat_box_as_builtin = true;
359                    self.ops_to_function_calls = true;
360                    self.index_to_function_calls = true;
361                    self.reconstruct_fallible_operations = true;
362                    self.reconstruct_asserts = true;
363                    self.lift_associated_types.push("*".to_owned());
364                    self.unbind_item_vars = true;
365                    // Eurydice doesn't support opaque vtables it seems?
366                    self.include.push("core::marker::MetaSized".to_owned());
367                }
368                Preset::Soteria => {
369                    self.extract_opaque_bodies = true;
370                    self.monomorphize = true;
371                    self.mir = Some(MirLevel::Elaborated);
372                    self.ullbc = true;
373                }
374                Preset::Tests => {
375                    self.no_dedup_serialized_ast = true; // Helps debug
376                    self.treat_box_as_builtin = true;
377                    self.hide_allocator = true;
378                    self.reconstruct_fallible_operations = true;
379                    self.reconstruct_asserts = true;
380                    self.ops_to_function_calls = true;
381                    self.index_to_function_calls = true;
382                    self.rustc_args.push("--edition=2021".to_owned());
383                    self.rustc_args
384                        .push("-Zcrate-attr=feature(register_tool)".to_owned());
385                    self.rustc_args
386                        .push("-Zcrate-attr=register_tool(charon)".to_owned());
387                    self.exclude.push("core::fmt::Formatter".to_owned());
388                }
389            }
390        }
391    }
392
393    /// Check that the options are meaningful
394    pub fn validate(&self) -> anyhow::Result<()> {
395        if self.dest_dir.is_some() {
396            display_unspanned_error(
397                Level::WARNING,
398                "`--dest` is deprecated, use `--dest-file` instead",
399            )
400        }
401
402        if self.remove_adt_clauses && self.lift_associated_types.is_empty() {
403            anyhow::bail!(
404                "`--remove-adt-clauses` should be used with `--remove-associated-types='*'` \
405                to avoid missing clause errors",
406            )
407        }
408        if matches!(self.monomorphize_mut, Some(MonomorphizeMut::ExceptTypes))
409            && !self.remove_adt_clauses
410        {
411            anyhow::bail!(
412                "`--monomorphize-mut=except-types` should be used with `--remove-adt-clauses` \
413                to avoid generics mismatches"
414            )
415        }
416        Ok(())
417    }
418}
419
420/// Predicates that determine wihch items to use as starting point for translation.
421#[derive(Debug, Clone, EnumAsGetters)]
422pub enum StartFrom {
423    /// Item identified by a pattern/path. If strict is true, then failing to
424    /// find an item matching the pattern is an error; otherwise, we just ignore this pattern.
425    Pattern { pattern: NamePattern, strict: bool },
426    /// Item annotated with the given attribute.
427    Attribute(String),
428    /// Item marked `pub`. Note that this does not take accessibility into account; a
429    /// non-reexported `pub` item will be included here.
430    Pub,
431}
432
433impl StartFrom {
434    pub fn matches(&self, ctx: &TranslatedCrate, item_meta: &ItemMeta) -> bool {
435        match self {
436            StartFrom::Pattern { pattern, .. } => pattern.matches(ctx, &item_meta.name),
437            StartFrom::Attribute(attr) => item_meta
438                .attr_info
439                .attributes
440                .iter()
441                .filter_map(|a| a.as_unknown())
442                .any(|raw_attr| raw_attr.path == *attr),
443            StartFrom::Pub => item_meta.attr_info.public,
444        }
445    }
446}
447
448/// The options that control translation and transformation.
449pub struct TranslateOptions {
450    /// Items from which to start translation.
451    pub start_from: Vec<StartFrom>,
452    /// The level at which to extract the MIR
453    pub mir_level: MirLevel,
454    /// Usually we skip the provided methods that aren't used. When this flag is on, we translate
455    /// them all.
456    pub translate_all_methods: bool,
457    /// If `Some(_)`, run the partial mutability monomorphization pass. The contained enum
458    /// indicates whether to partially monomorphize types.
459    pub monomorphize_mut: Option<MonomorphizeMut>,
460    /// Whether to hide various marker traits such as `Sized`, `Sync`, `Send` and `Destruct`
461    /// anywhere they show up.
462    pub hide_marker_traits: bool,
463    /// Remove trait clauses attached to type declarations.
464    pub remove_adt_clauses: bool,
465    /// Hide the `A` type parameter on standard library containers (`Box`, `Vec`, etc).
466    pub hide_allocator: bool,
467    /// Remove unused `Self: Trait` clauses on method declarations.
468    pub remove_unused_self_clauses: bool,
469    /// Monomorphize code using hax's instantiation mechanism.
470    pub monomorphize_with_hax: bool,
471    /// Transform array-to-slice unsizing, repeat expressions, and raw pointer construction into
472    /// builtin functions in ULLBC.
473    pub ops_to_function_calls: bool,
474    /// Transform array/slice indexing into builtin functions in ULLBC.
475    pub index_to_function_calls: bool,
476    /// Print the llbc just after control-flow reconstruction.
477    pub print_built_llbc: bool,
478    /// Treat `Box<T>` as if it was a built-in type.
479    pub treat_box_as_builtin: bool,
480    /// Don't inline or evaluate constants.
481    pub raw_consts: bool,
482    /// Replace string literal constants with a constant u8 array that gets unsized,
483    /// expliciting the fact a string constant has a hidden reference.
484    pub unsized_strings: bool,
485    /// Replace "bound checks followed by UB-on-overflow operation" with the corresponding
486    /// panic-on-overflow operation. This loses unwinding information.
487    pub reconstruct_fallible_operations: bool,
488    /// Replace "if x { panic() }" with "assert(x)".
489    pub reconstruct_asserts: bool,
490    // Use `DeBruijnVar::Free` for the variables bound in item signatures.
491    pub unbind_item_vars: bool,
492    /// List of patterns to assign a given opacity to. Same as the corresponding `TranslateOptions`
493    /// field.
494    pub item_opacities: Vec<(NamePattern, ItemOpacity)>,
495    /// List of traits for which we transform associated types to type parameters.
496    pub lift_associated_types: Vec<NamePattern>,
497    /// Transform Drop to Call drop_in_place
498    pub desugar_drops: bool,
499    /// Add `Destruct` bounds to all generic params.
500    pub add_destruct_bounds: bool,
501    /// Translate drop glue for poly types, knowing that this may cause ICEs.
502    pub translate_poly_drop_glue: bool,
503}
504
505impl TranslateOptions {
506    pub fn new(error_ctx: &mut ErrorCtx, options: &CliOpts) -> Self {
507        let mut parse_pattern = |s: &str| match NamePattern::parse(s) {
508            Ok(p) => Ok(p),
509            Err(e) => {
510                raise_error!(
511                    error_ctx,
512                    crate(&TranslatedCrate::default()),
513                    Span::dummy(),
514                    "failed to parse pattern `{s}` ({e})"
515                )
516            }
517        };
518
519        let mut mir_level = options.mir.unwrap_or(MirLevel::Promoted);
520        if options.precise_drops {
521            mir_level = std::cmp::max(mir_level, MirLevel::Elaborated);
522        }
523
524        let mut start_from = options
525            .start_from
526            .iter()
527            .filter_map(|path| parse_pattern(&path).ok())
528            .map(|p| StartFrom::Pattern {
529                pattern: p,
530                strict: true,
531            })
532            .collect_vec();
533        start_from.extend(
534            options
535                .start_from_if_exists
536                .iter()
537                .filter_map(|path| parse_pattern(&path).ok())
538                .map(|p| StartFrom::Pattern {
539                    pattern: p,
540                    strict: false,
541                }),
542        );
543        if let Some(attr) = options.start_from_attribute.clone() {
544            start_from.push(StartFrom::Attribute(attr));
545        }
546        if options.start_from_pub {
547            start_from.push(StartFrom::Pub);
548        }
549        if start_from.is_empty() {
550            start_from.push(StartFrom::Pattern {
551                pattern: parse_pattern("crate").unwrap(),
552                strict: true,
553            });
554        }
555
556        let item_opacities = {
557            use ItemOpacity::*;
558            let mut opacities = vec![];
559
560            // This is how to treat items that don't match any other pattern.
561            if options.extract_opaque_bodies {
562                opacities.push(("_".to_string(), Transparent));
563            } else {
564                opacities.push(("_".to_string(), Foreign));
565            }
566
567            // We always include the items from the crate.
568            opacities.push(("crate".to_owned(), Transparent));
569
570            for pat in options.include.iter() {
571                opacities.push((pat.to_string(), Transparent));
572            }
573            for pat in options.opaque.iter() {
574                opacities.push((pat.to_string(), Opaque));
575            }
576            for pat in options.exclude.iter() {
577                opacities.push((pat.to_string(), Invisible));
578            }
579
580            if options.hide_allocator {
581                opacities.push((format!("core::alloc::Allocator"), Invisible));
582                opacities.push((
583                    format!("alloc::alloc::{{impl core::alloc::Allocator for _}}"),
584                    Invisible,
585                ));
586            }
587
588            opacities
589                .into_iter()
590                .filter_map(|(s, opacity)| parse_pattern(&s).ok().map(|pat| (pat, opacity)))
591                .collect()
592        };
593
594        let lift_associated_types = options
595            .lift_associated_types
596            .iter()
597            .filter_map(|s| parse_pattern(&s).ok())
598            .collect();
599
600        TranslateOptions {
601            start_from,
602            mir_level,
603            monomorphize_mut: options.monomorphize_mut,
604            hide_marker_traits: options.hide_marker_traits,
605            remove_adt_clauses: options.remove_adt_clauses,
606            hide_allocator: options.hide_allocator,
607            remove_unused_self_clauses: options.remove_unused_self_clauses,
608            monomorphize_with_hax: options.monomorphize,
609            ops_to_function_calls: options.ops_to_function_calls,
610            index_to_function_calls: options.index_to_function_calls,
611            print_built_llbc: options.print_built_llbc,
612            item_opacities,
613            treat_box_as_builtin: options.treat_box_as_builtin,
614            raw_consts: options.raw_consts,
615            unsized_strings: options.unsized_strings,
616            reconstruct_fallible_operations: options.reconstruct_fallible_operations,
617            reconstruct_asserts: options.reconstruct_asserts,
618            lift_associated_types,
619            unbind_item_vars: options.unbind_item_vars,
620            translate_all_methods: options.translate_all_methods,
621            desugar_drops: options.desugar_drops,
622            add_destruct_bounds: options.precise_drops,
623            translate_poly_drop_glue: options.precise_drops,
624        }
625    }
626
627    /// Find the opacity requested for the given name. This does not take into account
628    /// `#[charon::opaque]` annotations, only cli parameters.
629    #[tracing::instrument(skip(self, krate), ret)]
630    pub fn opacity_for_name(&self, krate: &TranslatedCrate, name: &Name) -> ItemOpacity {
631        // Find the most precise pattern that matches this name. There is always one since
632        // the list contains the `_` pattern. If there are conflicting settings for this item, we
633        // err on the side of being more opaque.
634        let (_, opacity) = self
635            .item_opacities
636            .iter()
637            .filter(|(pat, _)| pat.matches(krate, name))
638            .max()
639            .unwrap();
640        *opacity
641    }
642}