Skip to main content

rustc_middle/ty/
significant_drop_order.rs

1use rustc_data_structures::fx::FxHashSet;
2use rustc_data_structures::unord::UnordSet;
3use rustc_hir::def_id::DefId;
4use rustc_span::Span;
5use smallvec::{SmallVec, smallvec};
6use tracing::{debug, instrument};
7
8use crate::ty::{self, Ty, TyCtxt};
9
10/// An additional filter to exclude well-known types from the ecosystem
11/// because their drops are trivial.
12/// This returns additional types to check if the drops are delegated to those.
13/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
14fn true_significant_drop_ty<'tcx>(
15    tcx: TyCtxt<'tcx>,
16    ty: Ty<'tcx>,
17) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
18    if let ty::Adt(def, args) = ty.kind() {
19        let mut did = def.did();
20        let mut name_rev = ::alloc::vec::Vec::new()vec![];
21        loop {
22            let key = tcx.def_key(did);
23
24            match key.disambiguated_data.data {
25                rustc_hir::definitions::DefPathData::CrateRoot => {
26                    name_rev.push(tcx.crate_name(did.krate));
27                }
28                rustc_hir::definitions::DefPathData::TypeNs(symbol) => {
29                    name_rev.push(symbol);
30                }
31                _ => return None,
32            }
33            if let Some(parent) = key.parent {
34                did = DefId { krate: did.krate, index: parent };
35            } else {
36                break;
37            }
38        }
39        let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
40        {
    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/ty/significant_drop_order.rs:40",
                        "rustc_middle::ty::significant_drop_order",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/significant_drop_order.rs"),
                        ::tracing_core::__macro_support::Option::Some(40u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::significant_drop_order"),
                        ::tracing_core::field::FieldSet::new(&["name_str"],
                            ::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};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&name_str)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?name_str);
41        match name_str[..] {
42            // These are the types from Rust core ecosystem
43            ["syn" | "proc_macro2", ..]
44            | ["core" | "std", "task", "LocalWaker" | "Waker"]
45            | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(::smallvec::SmallVec::new()smallvec![]),
46            // These are important types from Rust ecosystem
47            ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(::smallvec::SmallVec::new()smallvec![]),
48            ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
49                if let [ty, ..] = &***args
50                    && let Some(ty) = ty.as_type()
51                {
52                    Some({
    let count = 0usize + 1usize;
    let mut vec = ::smallvec::SmallVec::new();
    if count <= vec.inline_size() {
        vec.push(ty);
        vec
    } else {
        ::smallvec::SmallVec::from_vec(<[_]>::into_vec(::alloc::boxed::box_new([ty])))
    }
}smallvec![ty])
53                } else {
54                    None
55                }
56            }
57            ["hashbrown", "raw", "RawDrain"] => {
58                if let [_, ty, ..] = &***args
59                    && let Some(ty) = ty.as_type()
60                {
61                    Some({
    let count = 0usize + 1usize;
    let mut vec = ::smallvec::SmallVec::new();
    if count <= vec.inline_size() {
        vec.push(ty);
        vec
    } else {
        ::smallvec::SmallVec::from_vec(<[_]>::into_vec(::alloc::boxed::box_new([ty])))
    }
}smallvec![ty])
62                } else {
63                    None
64                }
65            }
66            _ => None,
67        }
68    } else {
69        None
70    }
71}
72
73/// Returns the list of types with a "potentially significant" that may be dropped
74/// by dropping a value of type `ty`.
75#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("extract_component_raw",
                                    "rustc_middle::ty::significant_drop_order",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/significant_drop_order.rs"),
                                    ::tracing_core::__macro_support::Option::Some(75u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::significant_drop_order"),
                                    ::tracing_core::field::FieldSet::new(&["ty", "ty_seen"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty_seen)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: SmallVec<[Ty<'tcx>; 4]> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let ty =
                tcx.try_normalize_erasing_regions(typing_env,
                        ty).unwrap_or(ty);
            let tys =
                tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
            {
                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/ty/significant_drop_order.rs:86",
                                    "rustc_middle::ty::significant_drop_order",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/significant_drop_order.rs"),
                                    ::tracing_core::__macro_support::Option::Some(86u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::significant_drop_order"),
                                    ::tracing_core::field::FieldSet::new(&["message", "ty"],
                                        ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&format_args!("components")
                                                        as &dyn Value)),
                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&ty) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            let mut out_tys = ::smallvec::SmallVec::new();
            for ty in tys {
                if let Some(tys) = true_significant_drop_ty(tcx, ty) {
                    for ty in tys {
                        if ty_seen.insert(ty) {
                            out_tys.extend(extract_component_raw(tcx, typing_env, ty,
                                    ty_seen));
                        }
                    }
                } else { if ty_seen.insert(ty) { out_tys.push(ty); } }
            }
            out_tys
        }
    }
}#[instrument(level = "trace", skip(tcx, typing_env))]
76pub fn extract_component_raw<'tcx>(
77    tcx: TyCtxt<'tcx>,
78    typing_env: ty::TypingEnv<'tcx>,
79    ty: Ty<'tcx>,
80    ty_seen: &mut UnordSet<Ty<'tcx>>,
81) -> SmallVec<[Ty<'tcx>; 4]> {
82    // Droppiness does not depend on regions, so let us erase them.
83    let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
84
85    let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
86    debug!(?ty, "components");
87    let mut out_tys = smallvec![];
88    for ty in tys {
89        if let Some(tys) = true_significant_drop_ty(tcx, ty) {
90            // Some types can be further opened up because the drop is simply delegated
91            for ty in tys {
92                if ty_seen.insert(ty) {
93                    out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen));
94                }
95            }
96        } else {
97            if ty_seen.insert(ty) {
98                out_tys.push(ty);
99            }
100        }
101    }
102    out_tys
103}
104
105#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("extract_component_with_significant_dtor",
                                    "rustc_middle::ty::significant_drop_order",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/significant_drop_order.rs"),
                                    ::tracing_core::__macro_support::Option::Some(105u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::significant_drop_order"),
                                    ::tracing_core::field::FieldSet::new(&["ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: SmallVec<[Ty<'tcx>; 4]> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let mut tys =
                extract_component_raw(tcx, typing_env, ty,
                    &mut Default::default());
            let mut deduplicate = FxHashSet::default();
            tys.retain(|oty| deduplicate.insert(*oty));
            tys.into_iter().collect()
        }
    }
}#[instrument(level = "trace", skip(tcx, typing_env))]
106pub fn extract_component_with_significant_dtor<'tcx>(
107    tcx: TyCtxt<'tcx>,
108    typing_env: ty::TypingEnv<'tcx>,
109    ty: Ty<'tcx>,
110) -> SmallVec<[Ty<'tcx>; 4]> {
111    let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default());
112    let mut deduplicate = FxHashSet::default();
113    tys.retain(|oty| deduplicate.insert(*oty));
114    tys.into_iter().collect()
115}
116
117/// Extract the span of the custom destructor of a type
118/// especially the span of the `impl Drop` header or its entire block
119/// when we are working with current local crate.
120#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("ty_dtor_span",
                                    "rustc_middle::ty::significant_drop_order",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/significant_drop_order.rs"),
                                    ::tracing_core::__macro_support::Option::Some(120u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::significant_drop_order"),
                                    ::tracing_core::field::FieldSet::new(&["ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Option<Span> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            match ty.kind() {
                ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_)
                    | ty::Error(_) | ty::Str | ty::Never | ty::RawPtr(_, _) |
                    ty::Ref(_, _, _) | ty::FnPtr(_, _) | ty::Tuple(_) |
                    ty::Dynamic(_, _) | ty::Alias(_, _) | ty::Bound(_, _) |
                    ty::Pat(_, _) | ty::Placeholder(_) | ty::Infer(_) |
                    ty::Slice(_) | ty::Array(_, _) | ty::UnsafeBinder(_) =>
                    None,
                ty::Adt(adt_def, _) => {
                    if let Some(dtor) = tcx.adt_destructor(adt_def.did()) {
                        Some(tcx.def_span(tcx.parent(dtor.did)))
                    } else { Some(tcx.def_span(adt_def.did())) }
                }
                ty::Coroutine(did, _) | ty::CoroutineWitness(did, _) |
                    ty::CoroutineClosure(did, _) | ty::Closure(did, _) |
                    ty::FnDef(did, _) | ty::Foreign(did) =>
                    Some(tcx.def_span(did)),
                ty::Param(_) => None,
            }
        }
    }
}#[instrument(level = "trace", skip(tcx))]
121pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
122    match ty.kind() {
123        ty::Bool
124        | ty::Char
125        | ty::Int(_)
126        | ty::Uint(_)
127        | ty::Float(_)
128        | ty::Error(_)
129        | ty::Str
130        | ty::Never
131        | ty::RawPtr(_, _)
132        | ty::Ref(_, _, _)
133        | ty::FnPtr(_, _)
134        | ty::Tuple(_)
135        | ty::Dynamic(_, _)
136        | ty::Alias(_, _)
137        | ty::Bound(_, _)
138        | ty::Pat(_, _)
139        | ty::Placeholder(_)
140        | ty::Infer(_)
141        | ty::Slice(_)
142        | ty::Array(_, _)
143        | ty::UnsafeBinder(_) => None,
144
145        ty::Adt(adt_def, _) => {
146            if let Some(dtor) = tcx.adt_destructor(adt_def.did()) {
147                Some(tcx.def_span(tcx.parent(dtor.did)))
148            } else {
149                Some(tcx.def_span(adt_def.did()))
150            }
151        }
152        ty::Coroutine(did, _)
153        | ty::CoroutineWitness(did, _)
154        | ty::CoroutineClosure(did, _)
155        | ty::Closure(did, _)
156        | ty::FnDef(did, _)
157        | ty::Foreign(did) => Some(tcx.def_span(did)),
158        ty::Param(_) => None,
159    }
160}