Skip to main content

rustc_session/
utils.rs

1use std::path::PathBuf;
2use std::sync::OnceLock;
3
4use rustc_data_structures::profiling::VerboseTimingGuard;
5use rustc_fs_util::try_canonicalize;
6use rustc_hir::attrs::NativeLibKind;
7use rustc_macros::{Decodable, Encodable, HashStable_Generic};
8
9use crate::session::Session;
10
11impl Session {
12    pub fn timer(&self, what: &'static str) -> VerboseTimingGuard<'_> {
13        self.prof.verbose_generic_activity(what)
14    }
15    /// Used by `-Z self-profile`.
16    pub fn time<R>(&self, what: &'static str, f: impl FnOnce() -> R) -> R {
17        self.prof.verbose_generic_activity(what).run(f)
18    }
19}
20
21#[derive(#[automatically_derived]
impl ::core::clone::Clone for NativeLib {
    #[inline]
    fn clone(&self) -> NativeLib {
        NativeLib {
            name: ::core::clone::Clone::clone(&self.name),
            new_name: ::core::clone::Clone::clone(&self.new_name),
            kind: ::core::clone::Clone::clone(&self.kind),
            verbatim: ::core::clone::Clone::clone(&self.verbatim),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for NativeLib {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f, "NativeLib",
            "name", &self.name, "new_name", &self.new_name, "kind",
            &self.kind, "verbatim", &&self.verbatim)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for NativeLib {
    #[inline]
    fn eq(&self, other: &NativeLib) -> bool {
        self.name == other.name && self.new_name == other.new_name &&
                self.kind == other.kind && self.verbatim == other.verbatim
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for NativeLib {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<String>;
        let _: ::core::cmp::AssertParamIsEq<Option<String>>;
        let _: ::core::cmp::AssertParamIsEq<NativeLibKind>;
        let _: ::core::cmp::AssertParamIsEq<Option<bool>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for NativeLib {
    #[inline]
    fn partial_cmp(&self, other: &NativeLib)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.name, &other.name) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.new_name,
                        &other.new_name) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.kind,
                                &other.kind) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                ::core::cmp::PartialOrd::partial_cmp(&self.verbatim,
                                    &other.verbatim),
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for NativeLib {
    #[inline]
    fn cmp(&self, other: &NativeLib) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.name, &other.name) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.new_name, &other.new_name) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.kind, &other.kind) {
                            ::core::cmp::Ordering::Equal =>
                                ::core::cmp::Ord::cmp(&self.verbatim, &other.verbatim),
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for NativeLib {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.name, state);
        ::core::hash::Hash::hash(&self.new_name, state);
        ::core::hash::Hash::hash(&self.kind, state);
        ::core::hash::Hash::hash(&self.verbatim, state)
    }
}Hash, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for NativeLib {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    NativeLib {
                        name: ref __binding_0,
                        new_name: ref __binding_1,
                        kind: ref __binding_2,
                        verbatim: ref __binding_3 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_2,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_3,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for NativeLib {
            fn decode(__decoder: &mut __D) -> Self {
                NativeLib {
                    name: ::rustc_serialize::Decodable::decode(__decoder),
                    new_name: ::rustc_serialize::Decodable::decode(__decoder),
                    kind: ::rustc_serialize::Decodable::decode(__decoder),
                    verbatim: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };Decodable)]
22#[derive(const _: () =
    {
        impl<__CTX> ::rustc_data_structures::stable_hasher::HashStable<__CTX>
            for NativeLib where __CTX: crate::HashStableContext {
            #[inline]
            fn hash_stable(&self, __hcx: &mut __CTX,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    NativeLib {
                        name: ref __binding_0,
                        new_name: ref __binding_1,
                        kind: ref __binding_2,
                        verbatim: ref __binding_3 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                        { __binding_2.hash_stable(__hcx, __hasher); }
                        { __binding_3.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable_Generic)]
23pub struct NativeLib {
24    pub name: String,
25    pub new_name: Option<String>,
26    pub kind: NativeLibKind,
27    pub verbatim: Option<bool>,
28}
29
30impl NativeLib {
31    pub fn has_modifiers(&self) -> bool {
32        self.verbatim.is_some() || self.kind.has_modifiers()
33    }
34}
35
36/// A path that has been canonicalized along with its original, non-canonicalized form
37#[derive(#[automatically_derived]
impl ::core::clone::Clone for CanonicalizedPath {
    #[inline]
    fn clone(&self) -> CanonicalizedPath {
        CanonicalizedPath {
            canonicalized: ::core::clone::Clone::clone(&self.canonicalized),
            original: ::core::clone::Clone::clone(&self.original),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for CanonicalizedPath {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "CanonicalizedPath", "canonicalized", &self.canonicalized,
            "original", &&self.original)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for CanonicalizedPath {
    #[inline]
    fn eq(&self, other: &CanonicalizedPath) -> bool {
        self.canonicalized == other.canonicalized &&
            self.original == other.original
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CanonicalizedPath {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<PathBuf>>;
        let _: ::core::cmp::AssertParamIsEq<PathBuf>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for CanonicalizedPath {
    #[inline]
    fn partial_cmp(&self, other: &CanonicalizedPath)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.canonicalized,
                &other.canonicalized) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.original,
                    &other.original),
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for CanonicalizedPath {
    #[inline]
    fn cmp(&self, other: &CanonicalizedPath) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.canonicalized, &other.canonicalized)
            {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.original, &other.original),
            cmp => cmp,
        }
    }
}Ord)]
38pub struct CanonicalizedPath {
39    // Optional since canonicalization can sometimes fail
40    canonicalized: Option<PathBuf>,
41    original: PathBuf,
42}
43
44impl CanonicalizedPath {
45    pub fn new(path: PathBuf) -> Self {
46        Self { canonicalized: try_canonicalize(&path).ok(), original: path }
47    }
48
49    pub fn canonicalized(&self) -> &PathBuf {
50        self.canonicalized.as_ref().unwrap_or(self.original())
51    }
52
53    pub fn original(&self) -> &PathBuf {
54        &self.original
55    }
56}
57
58/// Gets a list of extra command-line flags provided by the user, as strings.
59///
60/// This function is used during ICEs to show more information useful for
61/// debugging, since some ICEs only happens with non-default compiler flags
62/// (and the users don't always report them).
63pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
64    const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
65
66    const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
67
68    const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
69
70    let mut args = std::env::args_os().map(|arg| arg.to_string_lossy().to_string());
71
72    let mut result = Vec::new();
73    let mut excluded_cargo_defaults = false;
74    while let Some(arg) = args.next() {
75        if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
76            let content = if arg.len() == a.len() {
77                // A space-separated option, like `-C incremental=foo` or `--crate-type rlib`
78                match args.next() {
79                    Some(arg) => arg,
80                    None => continue,
81                }
82            } else if arg.get(a.len()..a.len() + 1) == Some("=") {
83                // An equals option, like `--crate-type=rlib`
84                arg[a.len() + 1..].to_string()
85            } else {
86                // A non-space option, like `-Cincremental=foo`
87                arg[a.len()..].to_string()
88            };
89            let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
90            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&option) {
91                excluded_cargo_defaults = true;
92            } else {
93                result.push(a.to_string());
94                result.push(if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&option) {
95                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}=[REDACTED]", option))
    })format!("{option}=[REDACTED]")
96                } else {
97                    content
98                });
99            }
100        }
101    }
102
103    if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
104}
105
106/// Returns whenever rustc was launched by Cargo as opposed to another build system.
107///
108/// To be used in diagnostics to avoid printing Cargo specific suggestions to other
109/// build systems (like Bazel, Buck2, Makefile, ...).
110pub fn was_invoked_from_cargo() -> bool {
111    static FROM_CARGO: OnceLock<bool> = OnceLock::new();
112
113    // To be able to detect Cargo, we use the simplest and least intrusive
114    // way: we check whenever the `CARGO_CRATE_NAME` env is set.
115    //
116    // Note that it is common in Makefiles to define the `CARGO` env even
117    // though we may not have been called by Cargo, so we avoid using it.
118    *FROM_CARGO.get_or_init(|| std::env::var_os("CARGO_CRATE_NAME").is_some())
119}