Skip to main content

rustc_lint/
context.rs

1//! Basic types for managing and implementing lints.
2//!
3//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
4//! overview of how lints are implemented.
5
6use std::cell::Cell;
7use std::slice;
8
9use rustc_abi as abi;
10use rustc_ast::BindingMode;
11use rustc_ast::util::parser::ExprPrecedence;
12use rustc_data_structures::fx::FxIndexMap;
13use rustc_data_structures::sync;
14use rustc_data_structures::unord::UnordMap;
15use rustc_errors::{Diagnostic, LintBuffer, MultiSpan};
16use rustc_feature::Features;
17use rustc_hir as hir;
18use rustc_hir::def::Res;
19use rustc_hir::def_id::{CrateNum, DefId};
20use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
21use rustc_hir::{Pat, PatKind};
22use rustc_middle::bug;
23use rustc_middle::lint::{LevelSpec, StableLevelSpec, UnstableLevelSpec};
24use rustc_middle::middle::privacy::EffectiveVisibilities;
25use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
26use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
27use rustc_middle::ty::{
28    self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized,
29};
30use rustc_session::lint::{
31    FutureIncompatibleInfo, Lint, LintExpectationId, LintId, StableLintExpectationId,
32    UnstableLintExpectationId,
33};
34use rustc_session::{DynLintStore, Session};
35use rustc_span::edit_distance::find_best_match_for_names;
36use rustc_span::{Ident, Span, Symbol, sym};
37use tracing::debug;
38
39use self::TargetLint::*;
40use crate::levels::LintLevelsBuilder;
41use crate::passes::{EarlyLintPassObject, LateLintPassObject};
42
43type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
44type LateLintPassFactory =
45    dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
46
47/// Information about the registered lints.
48pub struct LintStore {
49    /// Registered lints.
50    lints: Vec<&'static Lint>,
51
52    /// Constructor functions for each variety of lint pass.
53    ///
54    /// These should only be called once, but since we want to avoid locks or
55    /// interior mutability, we don't enforce this (and lints should, in theory,
56    /// be compatible with being constructed more than once, though not
57    /// necessarily in a sane manner. This is safe though.)
58    pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
59    pub early_passes: Vec<Box<EarlyLintPassFactory>>,
60    pub late_passes: Vec<Box<LateLintPassFactory>>,
61    /// This is unique in that we construct them per-module, so not once.
62    pub late_module_passes: Vec<Box<LateLintPassFactory>>,
63
64    /// Lints indexed by name.
65    by_name: UnordMap<String, TargetLint>,
66
67    /// Map of registered lint groups to what lints they expand to.
68    lint_groups: FxIndexMap<&'static str, LintGroup>,
69}
70
71impl DynLintStore for LintStore {
72    fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
73        Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
74            rustc_session::LintGroup { name, lints, is_externally_loaded }
75        }))
76    }
77}
78
79/// The target of the `by_name` map, which accounts for renaming/deprecation.
80#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TargetLint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TargetLint::Id(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Id",
                    &__self_0),
            TargetLint::Renamed(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "Renamed", __self_0, &__self_1),
            TargetLint::Removed(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Removed", &__self_0),
            TargetLint::Ignored =>
                ::core::fmt::Formatter::write_str(f, "Ignored"),
        }
    }
}Debug)]
81enum TargetLint {
82    /// A direct lint target
83    Id(LintId),
84
85    /// Temporary renaming, used for easing migration pain; see #16545
86    Renamed(String, LintId),
87
88    /// Lint with this name existed previously, but has been removed/deprecated.
89    /// The string argument is the reason for removal.
90    Removed(String),
91
92    /// A lint name that should give no warnings and have no effect.
93    ///
94    /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers
95    /// them as tool lints.
96    Ignored,
97}
98
99struct LintAlias {
100    name: &'static str,
101    /// Whether deprecation warnings should be suppressed for this alias.
102    silent: bool,
103}
104
105struct LintGroup {
106    lint_ids: Vec<LintId>,
107    is_externally_loaded: bool,
108    depr: Option<LintAlias>,
109}
110
111#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for CheckLintNameResult<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CheckLintNameResult::Ok(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ok",
                    &__self_0),
            CheckLintNameResult::NoLint(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "NoLint",
                    &__self_0),
            CheckLintNameResult::NoTool =>
                ::core::fmt::Formatter::write_str(f, "NoTool"),
            CheckLintNameResult::Renamed(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Renamed", &__self_0),
            CheckLintNameResult::Removed(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Removed", &__self_0),
            CheckLintNameResult::Tool(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Tool",
                    __self_0, &__self_1),
            CheckLintNameResult::MissingTool =>
                ::core::fmt::Formatter::write_str(f, "MissingTool"),
        }
    }
}Debug)]
112pub enum CheckLintNameResult<'a> {
113    Ok(&'a [LintId]),
114    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
115    NoLint(Option<(Symbol, bool)>),
116    /// The lint refers to a tool that has not been registered.
117    NoTool,
118    /// The lint has been renamed to a new name.
119    Renamed(String),
120    /// The lint has been removed due to the given reason.
121    Removed(String),
122
123    /// The lint is from a tool. The `LintId` will be returned as if it were a
124    /// rustc lint. The `Option<String>` indicates if the lint has been
125    /// renamed.
126    Tool(&'a [LintId], Option<String>),
127
128    /// The lint is from a tool. Either the lint does not exist in the tool or
129    /// the code was not compiled with the tool and therefore the lint was
130    /// never added to the `LintStore`.
131    MissingTool,
132}
133
134impl LintStore {
135    pub fn new() -> LintStore {
136        LintStore {
137            lints: ::alloc::vec::Vec::new()vec![],
138            pre_expansion_passes: ::alloc::vec::Vec::new()vec![],
139            early_passes: ::alloc::vec::Vec::new()vec![],
140            late_passes: ::alloc::vec::Vec::new()vec![],
141            late_module_passes: ::alloc::vec::Vec::new()vec![],
142            by_name: Default::default(),
143            lint_groups: Default::default(),
144        }
145    }
146
147    pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
148        &self.lints
149    }
150
151    pub fn get_lint_groups(&self) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> {
152        self.lint_groups
153            .iter()
154            .filter(|(_, LintGroup { depr, .. })| {
155                // Don't display deprecated lint groups.
156                depr.is_none()
157            })
158            .map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
159                (*k, lint_ids.clone(), *is_externally_loaded)
160            })
161    }
162
163    /// Returns all lint group names, including deprecated/aliased groups
164    pub fn get_all_group_names(&self) -> impl Iterator<Item = &'static str> {
165        self.lint_groups.keys().copied()
166    }
167
168    pub fn register_early_pass(
169        &mut self,
170        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
171    ) {
172        self.early_passes.push(Box::new(pass));
173    }
174
175    /// This lint pass is softly deprecated. It misses expanded code and has caused a few
176    /// errors in the past. Currently, it is only used in Clippy. New implementations
177    /// should avoid using this interface, as it might be removed in the future.
178    ///
179    /// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838)
180    /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518)
181    pub fn register_pre_expansion_pass(
182        &mut self,
183        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
184    ) {
185        self.pre_expansion_passes.push(Box::new(pass));
186    }
187
188    pub fn register_late_pass(
189        &mut self,
190        pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
191        + 'static
192        + sync::DynSend
193        + sync::DynSync,
194    ) {
195        self.late_passes.push(Box::new(pass));
196    }
197
198    pub fn register_late_mod_pass(
199        &mut self,
200        pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
201        + 'static
202        + sync::DynSend
203        + sync::DynSync,
204    ) {
205        self.late_module_passes.push(Box::new(pass));
206    }
207
208    /// Helper method for register_early/late_pass
209    pub fn register_lints(&mut self, lints: &[&'static Lint]) {
210        for lint in lints {
211            self.lints.push(lint);
212
213            let id = LintId::of(lint);
214            if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
215                ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
        lint.name_lower()))bug!("duplicate specification of lint {}", lint.name_lower())
216            }
217
218            if let Some(FutureIncompatibleInfo { reason, .. }) = lint.future_incompatible {
219                if let Some(edition) = reason.edition() {
220                    self.lint_groups
221                        .entry(edition.lint_name())
222                        .or_insert(LintGroup {
223                            lint_ids: ::alloc::vec::Vec::new()vec![],
224                            is_externally_loaded: lint.is_externally_loaded,
225                            depr: None,
226                        })
227                        .lint_ids
228                        .push(id);
229                } else {
230                    // Lints belonging to the `future_incompatible` lint group are lints where a
231                    // future version of rustc will cause existing code to stop compiling.
232                    // Lints tied to an edition don't count because they are opt-in.
233                    self.lint_groups
234                        .entry("future_incompatible")
235                        .or_insert(LintGroup {
236                            lint_ids: ::alloc::vec::Vec::new()vec![],
237                            is_externally_loaded: lint.is_externally_loaded,
238                            depr: None,
239                        })
240                        .lint_ids
241                        .push(id);
242                }
243            }
244        }
245    }
246
247    fn insert_group(&mut self, name: &'static str, group: LintGroup) {
248        let previous = self.lint_groups.insert(name, group);
249        if previous.is_some() {
250            ::rustc_middle::util::bug::bug_fmt(format_args!("group {0:?} already exists",
        name));bug!("group {name:?} already exists");
251        }
252    }
253
254    pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
255        let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
256            ::rustc_middle::util::bug::bug_fmt(format_args!("group alias {0:?} points to unregistered group {1:?}",
        alias, group_name))bug!("group alias {alias:?} points to unregistered group {group_name:?}")
257        };
258
259        self.insert_group(
260            alias,
261            LintGroup {
262                lint_ids: lint_ids.clone(),
263                is_externally_loaded: false,
264                depr: Some(LintAlias { name: group_name, silent: true }),
265            },
266        );
267    }
268
269    pub fn register_group(
270        &mut self,
271        is_externally_loaded: bool,
272        name: &'static str,
273        deprecated_name: Option<&'static str>,
274        to: Vec<LintId>,
275    ) {
276        if let Some(deprecated) = deprecated_name {
277            self.insert_group(
278                deprecated,
279                LintGroup {
280                    lint_ids: to.clone(),
281                    is_externally_loaded,
282                    depr: Some(LintAlias { name, silent: false }),
283                },
284            );
285        }
286        self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
287    }
288
289    /// This lint should give no warning and have no effect.
290    ///
291    /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers them as tool lints.
292    #[track_caller]
293    pub fn register_ignored(&mut self, name: &str) {
294        if self.by_name.insert(name.to_string(), Ignored).is_some() {
295            ::rustc_middle::util::bug::bug_fmt(format_args!("duplicate specification of lint {0}",
        name));bug!("duplicate specification of lint {}", name);
296        }
297    }
298
299    /// This lint has been renamed; warn about using the new name and apply the lint.
300    #[track_caller]
301    pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
302        let Some(&Id(target)) = self.by_name.get(new_name) else {
303            ::rustc_middle::util::bug::bug_fmt(format_args!("invalid lint renaming of {0} to {1}",
        old_name, new_name));bug!("invalid lint renaming of {} to {}", old_name, new_name);
304        };
305        self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
306    }
307
308    pub fn register_removed(&mut self, name: &str, reason: &str) {
309        self.by_name.insert(name.into(), Removed(reason.into()));
310    }
311
312    pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
313        match self.by_name.get(lint_name) {
314            Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
315            Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
316            Some(Removed(_)) => None,
317            Some(Ignored) => Some(&[]),
318            None => match self.lint_groups.get(lint_name) {
319                Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
320                None => None,
321            },
322        }
323    }
324
325    /// True if this symbol represents a lint group name.
326    pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
327        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/context.rs:327",
                        "rustc_lint::context", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
                        ::tracing_core::__macro_support::Option::Some(327u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
                        ::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};
                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!("is_lint_group(lint_name={0:?}, lint_groups={1:?})",
                                                    lint_name, self.lint_groups.keys().collect::<Vec<_>>()) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(
328            "is_lint_group(lint_name={:?}, lint_groups={:?})",
329            lint_name,
330            self.lint_groups.keys().collect::<Vec<_>>()
331        );
332        let lint_name_str = lint_name.as_str();
333        self.lint_groups.contains_key(lint_name_str) || {
334            let warnings_name_str = crate::WARNINGS.name_lower();
335            lint_name_str == warnings_name_str
336        }
337    }
338
339    /// Checks the name of a lint for its existence, and whether it was
340    /// renamed or removed. Generates a `Diag` containing a
341    /// warning for renamed and removed lints. This is over both lint
342    /// names from attributes and those passed on the command line. Since
343    /// it emits non-fatal warnings and there are *two* lint passes that
344    /// inspect attributes, this is only run from the late pass to avoid
345    /// printing duplicate warnings.
346    pub fn check_lint_name(
347        &self,
348        lint_name: &str,
349        tool_name: Option<Symbol>,
350        registered_tools: &RegisteredTools,
351    ) -> CheckLintNameResult<'_> {
352        if let Some(tool_name) = tool_name {
353            // FIXME: rustc and rustdoc are considered tools for lints, but not for attributes.
354            if tool_name != sym::rustc
355                && tool_name != sym::rustdoc
356                && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
357            {
358                return CheckLintNameResult::NoTool;
359            }
360        }
361
362        let complete_name = if let Some(tool_name) = tool_name {
363            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
    })format!("{tool_name}::{lint_name}")
364        } else {
365            lint_name.to_string()
366        };
367        // If the lint was scoped with `tool::` check if the tool lint exists
368        if let Some(tool_name) = tool_name {
369            match self.by_name.get(&complete_name) {
370                None => match self.lint_groups.get(&*complete_name) {
371                    // If the lint isn't registered, there are two possibilities:
372                    None => {
373                        // 1. The tool is currently running, so this lint really doesn't exist.
374                        // FIXME: should this handle tools that never register a lint, like rustfmt?
375                        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/context.rs:375",
                        "rustc_lint::context", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
                        ::tracing_core::__macro_support::Option::Some(375u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
                        ::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};
                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!("lints={0:?}",
                                                    self.by_name) as &dyn Value))])
            });
    } else { ; }
};debug!("lints={:?}", self.by_name);
376                        let tool_prefix = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::", tool_name))
    })format!("{tool_name}::");
377
378                        return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
379                            self.no_lint_suggestion(&complete_name, tool_name.as_str())
380                        } else {
381                            // 2. The tool isn't currently running, so no lints will be registered.
382                            // To avoid giving a false positive, ignore all unknown lints.
383                            CheckLintNameResult::MissingTool
384                        };
385                    }
386                    Some(LintGroup { lint_ids, depr, .. }) => {
387                        return if let &Some(LintAlias { name, silent: false }) = depr {
388                            CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
389                        } else {
390                            CheckLintNameResult::Tool(lint_ids, None)
391                        };
392                    }
393                },
394                Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
395                // If the lint was registered as removed or renamed by the lint tool, we don't need
396                // to treat tool_lints and rustc lints different and can use the code below.
397                _ => {}
398            }
399        }
400        match self.by_name.get(&complete_name) {
401            Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
402            Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
403            None => match self.lint_groups.get(&*complete_name) {
404                // If neither the lint, nor the lint group exists check if there is a `clippy::`
405                // variant of this lint
406                None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
407                Some(LintGroup { lint_ids, depr, .. }) => {
408                    // Check if the lint group name is deprecated
409                    if let &Some(LintAlias { name, silent: false }) = depr {
410                        CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
411                    } else {
412                        CheckLintNameResult::Ok(lint_ids)
413                    }
414                }
415            },
416            Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
417            Some(&Ignored) => CheckLintNameResult::Ok(&[]),
418        }
419    }
420
421    fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
422        let name_lower = lint_name.to_lowercase();
423
424        if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
425            // First check if the lint name is (partly) in upper case instead of lower case...
426            return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
427        }
428
429        // ...if not, search for lints with a similar name
430        // Note: find_best_match_for_name depends on the sort order of its input vector.
431        // To ensure deterministic output, sort elements of the lint_groups hash map.
432        // Also, never suggest deprecated lint groups.
433        // We will soon sort, so the initial order does not matter.
434        #[allow(rustc::potential_query_instability)]
435        let mut groups: Vec<_> = self
436            .lint_groups
437            .iter()
438            .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k))
439            .collect();
440        groups.sort();
441        let groups = groups.iter().map(|k| Symbol::intern(k));
442        let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
443        let names: Vec<Symbol> = groups.chain(lints).collect();
444        let mut lookups = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Symbol::intern(&name_lower)]))vec![Symbol::intern(&name_lower)];
445        if let Some(stripped) = name_lower.split("::").last() {
446            lookups.push(Symbol::intern(stripped));
447        }
448        let res = find_best_match_for_names(&names, &lookups, None);
449        let is_rustc = res.map_or_else(
450            || false,
451            |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name),
452        );
453        let suggestion = res.map(|s| (s, is_rustc));
454        CheckLintNameResult::NoLint(suggestion)
455    }
456
457    fn check_tool_name_for_backwards_compat(
458        &self,
459        lint_name: &str,
460        tool_name: &str,
461    ) -> CheckLintNameResult<'_> {
462        let complete_name = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::{1}", tool_name, lint_name))
    })format!("{tool_name}::{lint_name}");
463        match self.by_name.get(&complete_name) {
464            None => match self.lint_groups.get(&*complete_name) {
465                // Now we are sure, that this lint exists nowhere
466                None => self.no_lint_suggestion(lint_name, tool_name),
467                Some(LintGroup { lint_ids, .. }) => {
468                    CheckLintNameResult::Tool(lint_ids, Some(complete_name))
469                }
470            },
471            Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
472            Some(other) => {
473                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/context.rs:473",
                        "rustc_lint::context", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/context.rs"),
                        ::tracing_core::__macro_support::Option::Some(473u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::context"),
                        ::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};
                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!("got renamed lint {0:?}",
                                                    other) as &dyn Value))])
            });
    } else { ; }
};debug!("got renamed lint {:?}", other);
474                CheckLintNameResult::NoLint(None)
475            }
476        }
477    }
478}
479
480/// Context for lint checking outside of type inference.
481pub struct LateContext<'tcx> {
482    /// Type context we're checking in.
483    pub tcx: TyCtxt<'tcx>,
484
485    /// Current body, or `None` if outside a body.
486    pub enclosing_body: Option<hir::BodyId>,
487
488    /// Type-checking results for the current body. Access using the `typeck_results`
489    /// and `maybe_typeck_results` methods, which handle querying the typeck results on demand.
490    // FIXME(eddyb) move all the code accessing internal fields like this,
491    // to this module, to avoid exposing it to lint logic.
492    pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
493
494    /// Parameter environment for the item we are in.
495    pub param_env: ty::ParamEnv<'tcx>,
496
497    /// Items accessible from the crate being checked.
498    pub effective_visibilities: &'tcx EffectiveVisibilities,
499
500    pub last_node_with_lint_attrs: hir::HirId,
501
502    /// Generic type parameters in scope for the item we are in.
503    pub generics: Option<&'tcx hir::Generics<'tcx>>,
504
505    /// We are only looking at one module
506    pub only_module: bool,
507}
508
509/// Context for lint checking of the AST, after expansion, before lowering to HIR.
510pub struct EarlyContext<'a> {
511    pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
512    pub buffered: LintBuffer,
513}
514
515pub trait LintContext {
516    type LintExpectationId: Copy + Into<LintExpectationId>;
517
518    fn sess(&self) -> &Session;
519
520    // FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
521    // set the span in their `decorate` function (preferably using set_span).
522    /// Emit a lint at the appropriate level, with an optional associated span.
523    ///
524    /// [`emit_lint_base`]: rustc_middle::lint::emit_lint_base#decorate-signature
525    #[track_caller]
526    fn opt_span_lint<S: Into<MultiSpan>>(
527        &self,
528        lint: &'static Lint,
529        span: Option<S>,
530        decorate: impl for<'a> Diagnostic<'a, ()>,
531    );
532
533    /// Emit a lint at `span` from a lint struct (some type that implements `Diagnostic`,
534    /// typically generated by `#[derive(Diagnostic)]`).
535    #[track_caller]
536    fn emit_span_lint<S: Into<MultiSpan>>(
537        &self,
538        lint: &'static Lint,
539        span: S,
540        decorator: impl for<'a> Diagnostic<'a, ()>,
541    ) {
542        self.opt_span_lint(lint, Some(span), decorator);
543    }
544
545    /// This returns the lint level spec for the given lint at the current location.
546    fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<Self::LintExpectationId>;
547
548    /// This function can be used to manually fulfill an expectation. This can
549    /// be used for lints which contain several spans, and should be suppressed,
550    /// if either location was marked with an expectation.
551    ///
552    /// Note that this function should only be called for [`LintExpectationId`]s
553    /// retrieved from the current lint pass. Buffered or manually created ids can
554    /// cause ICEs.
555    fn fulfill_expectation(&self, expectation: Self::LintExpectationId) {
556        // We need to make sure that submitted expectation ids are correctly fulfilled suppressed
557        // and stored between compilation sessions. To not manually do these steps, we simply create
558        // a dummy diagnostic and emit it as usual, which will be suppressed and stored like a
559        // normal expected lint diagnostic.
560        self.sess()
561            .dcx()
562            .struct_expect(
563                "this is a dummy diagnostic, to submit and store an expectation",
564                expectation.into(),
565            )
566            .emit();
567    }
568}
569
570impl<'a> EarlyContext<'a> {
571    pub(crate) fn new(
572        sess: &'a Session,
573        features: &'a Features,
574        lint_added_lints: bool,
575        lint_store: &'a LintStore,
576        registered_tools: &'a RegisteredTools,
577        buffered: LintBuffer,
578    ) -> EarlyContext<'a> {
579        EarlyContext {
580            builder: LintLevelsBuilder::new(
581                sess,
582                features,
583                lint_added_lints,
584                lint_store,
585                registered_tools,
586            ),
587            buffered,
588        }
589    }
590}
591
592impl<'tcx> LintContext for LateContext<'tcx> {
593    type LintExpectationId = StableLintExpectationId;
594
595    /// Gets the overall compiler `Session` object.
596    fn sess(&self) -> &Session {
597        self.tcx.sess
598    }
599
600    fn opt_span_lint<S: Into<MultiSpan>>(
601        &self,
602        lint: &'static Lint,
603        span: Option<S>,
604        decorate: impl for<'a> Diagnostic<'a, ()>,
605    ) {
606        let hir_id = self.last_node_with_lint_attrs;
607
608        match span {
609            Some(s) => self.tcx.emit_node_span_lint(lint, hir_id, s, decorate),
610            None => self.tcx.emit_node_lint(lint, hir_id, decorate),
611        }
612    }
613
614    fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec {
615        self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs)
616    }
617}
618
619impl LintContext for EarlyContext<'_> {
620    type LintExpectationId = UnstableLintExpectationId;
621
622    /// Gets the overall compiler `Session` object.
623    fn sess(&self) -> &Session {
624        self.builder.sess()
625    }
626
627    fn opt_span_lint<S: Into<MultiSpan>>(
628        &self,
629        lint: &'static Lint,
630        span: Option<S>,
631        decorator: impl for<'a> Diagnostic<'a, ()>,
632    ) {
633        self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator)
634    }
635
636    fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec {
637        self.builder.lint_level_spec(lint)
638    }
639}
640
641impl<'tcx> LateContext<'tcx> {
642    /// The typing mode of the currently visited node. Use this when
643    /// building a new `InferCtxt`.
644    pub fn typing_mode(&self) -> TypingMode<'tcx> {
645        if let Some(body_id) = self.enclosing_body
646            && self.tcx.use_typing_mode_borrowck()
647        {
648            let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id);
649            TypingMode::borrowck(self.tcx, def_id)
650        } else {
651            TypingMode::non_body_analysis()
652        }
653    }
654
655    pub fn typing_env(&self) -> TypingEnv<'tcx> {
656        TypingEnv::new(self.param_env, self.typing_mode())
657    }
658
659    pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
660        self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
661    }
662
663    pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
664        self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
665    }
666
667    /// Gets the type-checking results for the current body,
668    /// or `None` if outside a body.
669    pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
670        self.cached_typeck_results.get().or_else(|| {
671            self.enclosing_body.map(|body| {
672                let typeck_results = self.tcx.typeck_body(body);
673                self.cached_typeck_results.set(Some(typeck_results));
674                typeck_results
675            })
676        })
677    }
678
679    /// Gets the type-checking results for the current body.
680    /// As this will ICE if called outside bodies, only call when working with
681    /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
682    #[track_caller]
683    pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
684        self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
685    }
686
687    /// Returns the final resolution of a `QPath`, or `Res::Err` if unavailable.
688    /// Unlike `.typeck_results().qpath_res(qpath, id)`, this can be used even outside
689    /// bodies (e.g. for paths in `hir::Ty`), without any risk of ICE-ing.
690    pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
691        match *qpath {
692            hir::QPath::Resolved(_, path) => path.res,
693            hir::QPath::TypeRelative(..) => self
694                .maybe_typeck_results()
695                .filter(|typeck_results| typeck_results.hir_owner == id.owner)
696                .or_else(|| {
697                    self.tcx
698                        .has_typeck_results(id.owner.def_id)
699                        .then(|| self.tcx.typeck(id.owner.def_id))
700                })
701                .and_then(|typeck_results| typeck_results.type_dependent_def(id))
702                .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
703        }
704    }
705
706    /// Gets the absolute path of `def_id` as a vector of `Symbol`.
707    ///
708    /// Note that this is kinda expensive because it has to
709    /// travel the tree and pretty-print. Use sparingly.
710    ///
711    /// If you're trying to match for an item given by its path, use a
712    /// diagnostic item. If you're only interested in given sections, use more
713    /// specific functions, such as [`TyCtxt::crate_name`]
714    ///
715    /// FIXME: It would be great if this could be optimized.
716    ///
717    /// # Examples
718    ///
719    /// ```rust,ignore (no context or def id available)
720    /// let def_path = cx.get_def_path(def_id);
721    /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] {
722    ///     // The given `def_id` is that of an `Option` type
723    /// }
724    /// ```
725    pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
726        struct LintPathPrinter<'tcx> {
727            tcx: TyCtxt<'tcx>,
728            path: Vec<Symbol>,
729        }
730
731        impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
732            fn tcx(&self) -> TyCtxt<'tcx> {
733                self.tcx
734            }
735
736            fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
737                ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
738            }
739
740            fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
741                ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
742            }
743
744            fn print_dyn_existential(
745                &mut self,
746                _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
747            ) -> Result<(), PrintError> {
748                ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
749            }
750
751            fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
752                ::core::panicking::panic("internal error: entered unreachable code");unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
753            }
754
755            fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
756                self.path = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self.tcx.crate_name(cnum)]))vec![self.tcx.crate_name(cnum)];
757                Ok(())
758            }
759
760            fn print_path_with_qualified(
761                &mut self,
762                self_ty: Ty<'tcx>,
763                trait_ref: Option<ty::TraitRef<'tcx>>,
764            ) -> Result<(), PrintError> {
765                if trait_ref.is_none()
766                    && let ty::Adt(def, args) = self_ty.kind()
767                {
768                    return self.print_def_path(def.did(), args);
769                }
770
771                // This shouldn't ever be needed, but just in case:
772                {
    let _guard = NoTrimmedGuard::new();
    {
        self.path =
            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                    [match trait_ref {
                                Some(trait_ref) =>
                                    Symbol::intern(&::alloc::__export::must_use({
                                                    ::alloc::fmt::format(format_args!("{0:?}", trait_ref))
                                                })),
                                None =>
                                    Symbol::intern(&::alloc::__export::must_use({
                                                    ::alloc::fmt::format(format_args!("<{0}>", self_ty))
                                                })),
                            }]));
        Ok(())
    }
}with_no_trimmed_paths!({
773                    self.path = vec![match trait_ref {
774                        Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
775                        None => Symbol::intern(&format!("<{self_ty}>")),
776                    }];
777                    Ok(())
778                })
779            }
780
781            fn print_path_with_impl(
782                &mut self,
783                print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
784                self_ty: Ty<'tcx>,
785                trait_ref: Option<ty::TraitRef<'tcx>>,
786            ) -> Result<(), PrintError> {
787                print_prefix(self)?;
788
789                // This shouldn't ever be needed, but just in case:
790                self.path.push(match trait_ref {
791                    Some(trait_ref) => {
792                        {
    let _guard = NoTrimmedGuard::new();
    Symbol::intern(&::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("<impl {0} for {1}>",
                            trait_ref.print_only_trait_path(), self_ty))
                }))
}with_no_trimmed_paths!(Symbol::intern(&format!(
793                            "<impl {} for {}>",
794                            trait_ref.print_only_trait_path(),
795                            self_ty
796                        )))
797                    }
798                    None => {
799                        {
    let _guard = NoTrimmedGuard::new();
    Symbol::intern(&::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("<impl {0}>", self_ty))
                }))
}with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>")))
800                    }
801                });
802
803                Ok(())
804            }
805
806            fn print_path_with_simple(
807                &mut self,
808                print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
809                disambiguated_data: &DisambiguatedDefPathData,
810            ) -> Result<(), PrintError> {
811                print_prefix(self)?;
812
813                // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
814                if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
815                    return Ok(());
816                }
817
818                self.path.push(match disambiguated_data.data.get_opt_name() {
819                    Some(sym) => sym,
820                    None => Symbol::intern(&disambiguated_data.data.to_string()),
821                });
822                Ok(())
823            }
824
825            fn print_path_with_generic_args(
826                &mut self,
827                print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
828                _args: &[GenericArg<'tcx>],
829            ) -> Result<(), PrintError> {
830                print_prefix(self)
831            }
832        }
833
834        let mut p = LintPathPrinter { tcx: self.tcx, path: ::alloc::vec::Vec::new()vec![] };
835        p.print_def_path(def_id, &[]).unwrap();
836        p.path
837    }
838
839    /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`.
840    /// Do not invoke without first verifying that the type implements the trait.
841    pub fn get_associated_type(
842        &self,
843        self_ty: Ty<'tcx>,
844        trait_id: DefId,
845        name: Symbol,
846    ) -> Option<Ty<'tcx>> {
847        let tcx = self.tcx;
848        tcx.associated_items(trait_id)
849            .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
850            .and_then(|assoc| {
851                let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
852                tcx.try_normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(proj))
853                    .ok()
854            })
855    }
856
857    /// Returns the effective precedence of an expression for the purpose of
858    /// rendering diagnostic. This is not the same as the precedence that would
859    /// be used for pretty-printing HIR by rustc_hir_pretty.
860    pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
861        let has_attr = |id: hir::HirId| -> bool {
862            self.tcx.hir_attrs(id).iter().any(hir::Attribute::is_prefix_attr_for_suggestions)
863        };
864        expr.precedence(&has_attr)
865    }
866
867    /// If the given expression is a local binding, find the initializer expression.
868    /// If that initializer expression is another local binding, find its initializer again.
869    ///
870    /// This process repeats as long as possible (but usually no more than once).
871    /// Type-check adjustments are not taken in account in this function.
872    ///
873    /// Examples:
874    /// ```
875    /// let abc = 1;
876    /// let def = abc + 2;
877    /// //        ^^^^^^^ output
878    /// let def = def;
879    /// dbg!(def);
880    /// //   ^^^ input
881    /// ```
882    pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
883        expr = expr.peel_blocks();
884
885        while let hir::ExprKind::Path(ref qpath) = expr.kind
886            && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
887                Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
888                _ => None,
889            }
890            && let Some(init) = match parent_node {
891                hir::Node::Expr(expr) => Some(expr),
892                hir::Node::LetStmt(hir::LetStmt {
893                    init,
894                    // Binding is immutable, init cannot be re-assigned
895                    pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
896                    ..
897                }) => *init,
898                _ => None,
899            }
900        {
901            expr = init.peel_blocks();
902        }
903        expr
904    }
905
906    /// If the given expression is a local binding, find the initializer expression.
907    /// If that initializer expression is another local or **outside** (`const`/`static`)
908    /// binding, find its initializer again.
909    ///
910    /// This process repeats as long as possible (but usually no more than once).
911    /// Type-check adjustments are not taken in account in this function.
912    ///
913    /// Examples:
914    /// ```
915    /// const ABC: i32 = 1;
916    /// //               ^ output
917    /// let def = ABC;
918    /// dbg!(def);
919    /// //   ^^^ input
920    ///
921    /// // or...
922    /// let abc = 1;
923    /// let def = abc + 2;
924    /// //        ^^^^^^^ output
925    /// dbg!(def);
926    /// //   ^^^ input
927    /// ```
928    pub fn expr_or_init_with_outside_body<'a>(
929        &self,
930        mut expr: &'a hir::Expr<'tcx>,
931    ) -> &'a hir::Expr<'tcx> {
932        expr = expr.peel_blocks();
933
934        while let hir::ExprKind::Path(ref qpath) = expr.kind
935            && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
936                Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
937                Res::Def(_, def_id) => self.tcx.hir_get_if_local(def_id),
938                _ => None,
939            }
940            && let Some(init) = match parent_node {
941                hir::Node::Expr(expr) => Some(expr),
942                hir::Node::LetStmt(hir::LetStmt {
943                    init,
944                    // Binding is immutable, init cannot be re-assigned
945                    pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
946                    ..
947                }) => *init,
948                hir::Node::Item(item) => match item.kind {
949                    // FIXME(mgca): figure out how to handle ConstArgKind::Path (or don't but add warning in docs here)
950                    hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
951                    | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
952                    _ => None,
953                },
954                _ => None,
955            }
956        {
957            expr = init.peel_blocks();
958        }
959        expr
960    }
961}
962
963impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
964    #[inline]
965    fn data_layout(&self) -> &abi::TargetDataLayout {
966        &self.tcx.data_layout
967    }
968}
969
970impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
971    #[inline]
972    fn tcx(&self) -> TyCtxt<'tcx> {
973        self.tcx
974    }
975}
976
977impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
978    #[inline]
979    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
980        self.typing_env()
981    }
982}
983
984impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
985    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
986
987    #[inline]
988    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
989        err
990    }
991}