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