Skip to main content

rustc_middle/middle/codegen_fn_attrs/
ferrocene.rs

1use rustc_hir::def::DefKind;
2use rustc_hir::def_id::DefId;
3use rustc_hir::{
4    ForeignItem, ForeignItemKind, Item, ItemKind, Node, TraitFn, TraitItem, TraitItemKind,
5};
6use rustc_macros::{StableHash, TyDecodable, TyEncodable};
7use rustc_middle::ty::{self, TyCtxt};
8use rustc_span::{Span, Symbol, sym};
9use tracing::info;
10
11#[derive(#[automatically_derived]
impl ::core::clone::Clone for Validated {
    #[inline]
    fn clone(&self) -> Validated { Validated {} }
}Clone, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for Validated {
            fn encode(&self, __encoder: &mut __E) {
                match *self { Validated {} => {} }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for Validated {
            fn decode(__decoder: &mut __D) -> Self { Validated {} }
        }
    };TyDecodable, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for Validated {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self { Validated {} => {} }
            }
        }
    };StableHash, #[automatically_derived]
impl ::core::fmt::Debug for Validated {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Validated")
    }
}Debug)]
12pub struct Validated {
13    // prevalidated: bool,
14    // FIXME: exported_constraint, validated, standards, qualification levels, entrypoint
15}
16
17const VALIDATED_ATTR: &[Symbol; 2] = &[sym::ferrocene, sym::prevalidated];
18
19pub enum ValidatedStatus {
20    /// `annotation` is None IFF this is the `main` entrypoint.
21    Validated {
22        annotation: Option<Span>,
23    },
24    Unvalidated,
25    WorkaroundDelegationBugs,
26}
27
28impl ValidatedStatus {
29    pub fn validated(self) -> bool {
30        match self {
31            ValidatedStatus::Validated { .. } => true,
32            ValidatedStatus::WorkaroundDelegationBugs | ValidatedStatus::Unvalidated => false,
33        }
34    }
35}
36
37/// Shared between `rustc_lint` and `rustc_codegen_ssa` attr parsing.
38///
39/// This analysis needs to be conservative. If you don't have enough information to determine the
40/// status, assume it's unvalidated.
41pub fn item_is_validated(tcx: TyCtxt<'_>, def_id: DefId) -> ValidatedStatus {
42    // A closure is validated if the function it's defined in is validated.
43    let owner = tcx.typeck_root_def_id(def_id);
44
45    // Skip items synthesized by the compiler.
46    let synthetic = match tcx.def_kind(owner) {
47        DefKind::Ctor(..) | DefKind::SyntheticCoroutineBody => true,
48        // NOTE: intrinsics might have a "fallback body" that is used as a default if the codegen
49        // backend doesn't override it.
50        _ => tcx.intrinsic(owner).is_some_and(|def| def.must_be_overridden),
51    };
52    if synthetic {
53        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs:53",
                        "rustc_middle::middle::codegen_fn_attrs::ferrocene",
                        ::tracing::Level::INFO,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs"),
                        ::tracing_core::__macro_support::Option::Some(53u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::codegen_fn_attrs::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("skipping synthetic item {0:?}",
                                                    owner) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};info!("skipping synthetic item {owner:?}");
54        return ValidatedStatus::Validated { annotation: None };
55    }
56
57    // Skip intrinsics, extern functions, and associated functions with no default.
58    // We only have to do this for local DefIds; nothing makes it to post-mono without a body unless
59    // it's an intrinsic.
60    if let Some(local) = owner.as_local() {
61        match tcx.hir_node_by_def_id(local) {
62            Node::Item(Item { kind: ItemKind::Fn { has_body: false, .. }, .. })
63                // FIXME: ForeignItems should be an exported_constraint
64                | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(..), .. })
65                | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(_, TraitFn::Required(_)), .. }) => {
66                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs:66",
                        "rustc_middle::middle::codegen_fn_attrs::ferrocene",
                        ::tracing::Level::INFO,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs"),
                        ::tracing_core::__macro_support::Option::Some(66u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::codegen_fn_attrs::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("skipping item {0:?}",
                                                    owner) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};info!("skipping item {owner:?}");
67                    return ValidatedStatus::Validated { annotation: None };
68                }
69            _ => {},
70        }
71
72        // Check if this is an associated function from a `derive`.
73        let parent = tcx.parent(owner);
74        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs:74",
                        "rustc_middle::middle::codegen_fn_attrs::ferrocene",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs"),
                        ::tracing_core::__macro_support::Option::Some(74u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::codegen_fn_attrs::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("parent={1:?}, kind={0:?}",
                                                    tcx.def_kind(parent), parent) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};tracing::debug!("parent={parent:?}, kind={:?}", tcx.def_kind(parent));
75        #[allow(deprecated)]
76        if #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(parent) {
    DefKind::Impl { .. } => true,
    _ => false,
}matches!(tcx.def_kind(parent), DefKind::Impl { .. }) {
77            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs:77",
                        "rustc_middle::middle::codegen_fn_attrs::ferrocene",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs"),
                        ::tracing_core::__macro_support::Option::Some(77u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::codegen_fn_attrs::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("attrs={0:?}",
                                                    tcx.get_all_attrs(parent)) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};tracing::debug!("attrs={:?}", tcx.get_all_attrs(parent));
78        }
79
80        let derived = #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(parent) {
    DefKind::Impl { .. } => true,
    _ => false,
}matches!(tcx.def_kind(parent), DefKind::Impl { .. })
81            && tcx.is_automatically_derived(parent);
82        if derived {
83            // Builtin macros are covered under our compiler qualification and considered verified.
84            // We currently don't support proc-macros; assume them to be unverified.
85            if !tcx.is_builtin_derived(parent) {
86                return ValidatedStatus::Unvalidated;
87            }
88
89            let self_ty = tcx.type_of(parent);
90            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs:90",
                        "rustc_middle::middle::codegen_fn_attrs::ferrocene",
                        ::tracing::Level::INFO,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs"),
                        ::tracing_core::__macro_support::Option::Some(90u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::codegen_fn_attrs::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("checking {0:?}",
                                                    self_ty) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};info!("checking {self_ty:?}");
91            // FIXME: need to try to normalize this type so we handle aliases and associated types
92            let unwrapped_ty = self_ty.skip_binder().peel_refs();
93            match unwrapped_ty.kind() {
94                ty::Adt(adt_def, _) => {
95                    let self_id = adt_def.did();
96                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs:96",
                        "rustc_middle::middle::codegen_fn_attrs::ferrocene",
                        ::tracing::Level::INFO,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/codegen_fn_attrs/ferrocene.rs"),
                        ::tracing_core::__macro_support::Option::Some(96u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::codegen_fn_attrs::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0} is marked #[automatically_derived], checking {1}",
                                                    tcx.def_path_str(def_id), tcx.def_path_str(self_id)) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};info!(
97                        "{} is marked #[automatically_derived], checking {}",
98                        tcx.def_path_str(def_id),
99                        tcx.def_path_str(self_id)
100                    );
101                    return item_is_validated(tcx, self_id);
102                }
103                ty::Error(..) => {}
104                _ if unwrapped_ty.is_primitive_ty() => {}
105                // We don't know how to resolve this back to a type.
106                // For now, just assume it's unvalidated.
107                _ => {
108                    return ValidatedStatus::Unvalidated;
109                }
110            }
111        }
112    }
113
114    // HACK: `feature(delegation)` is horribly buggy and causes infinite cycles within the query
115    // system itself. While we wait for upstream to fix it, work around the issue.
116    // See https://github.com/rust-lang/rust/pull/154387 for more information.
117    let delegation_enabled = tcx.dcx().has_errors().is_some() || tcx.features().fn_delegation();
118    let is_main = delegation_enabled || tcx.entry_fn(()).map_or(false, |(main, _)| main == owner);
119    // We normally assume main functions are validated, but not for the
120    // shim generated by `rustc --test`.
121    let main_is_validated = is_main && !tcx.sess.opts.test;
122
123    let annotation = tcx.get_attrs_by_path(owner, VALIDATED_ATTR).next();
124    if annotation.is_some() {
125        ValidatedStatus::Validated { annotation: annotation.map(|attr| attr.span()) }
126    } else if delegation_enabled {
127        // Avoid trying to run our lint on items with delegation errors.
128        ValidatedStatus::WorkaroundDelegationBugs
129    } else if main_is_validated {
130        ValidatedStatus::Validated { annotation: None }
131    } else {
132        ValidatedStatus::Unvalidated
133    }
134}