1use std::cmp;
2
3use rustc_data_structures::fx::FxIndexMap;
4use rustc_data_structures::sorted_map::SortedMap;
5use rustc_errors::{Diag, DiagLocation, Diagnostic, MultiSpan};
6use rustc_hir::{HirId, ItemLocalId};
7use rustc_lint_defs::EditionFcw;
8use rustc_macros::{Decodable, Encodable, StableHash};
9use rustc_session::Session;
10use rustc_session::lint::{
11 FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, builtin,
12};
13use rustc_span::{DUMMY_SP, ExpnKind, Span, Symbol, kw};
14use tracing::instrument;
15
16use crate::ty::TyCtxt;
17
18#[derive(#[automatically_derived]
impl ::core::clone::Clone for LintLevelSource {
#[inline]
fn clone(&self) -> LintLevelSource {
let _: ::core::clone::AssertParamIsClone<Symbol>;
let _: ::core::clone::AssertParamIsClone<Span>;
let _: ::core::clone::AssertParamIsClone<Option<Symbol>>;
let _: ::core::clone::AssertParamIsClone<Level>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for LintLevelSource { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for LintLevelSource {
#[inline]
fn eq(&self, other: &LintLevelSource) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(LintLevelSource::Node {
name: __self_0, span: __self_1, reason: __self_2 },
LintLevelSource::Node {
name: __arg1_0, span: __arg1_1, reason: __arg1_2 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2,
(LintLevelSource::CommandLine(__self_0, __self_1),
LintLevelSource::CommandLine(__arg1_0, __arg1_1)) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for LintLevelSource {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Symbol>;
let _: ::core::cmp::AssertParamIsEq<Span>;
let _: ::core::cmp::AssertParamIsEq<Option<Symbol>>;
let _: ::core::cmp::AssertParamIsEq<Level>;
}
}Eq, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for LintLevelSource {
fn encode(&self, __encoder: &mut __E) {
let disc =
match *self {
LintLevelSource::Default => { 0usize }
LintLevelSource::Node {
name: ref __binding_0,
span: ref __binding_1,
reason: ref __binding_2 } => {
1usize
}
LintLevelSource::CommandLine(ref __binding_0,
ref __binding_1) => {
2usize
}
};
::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
match *self {
LintLevelSource::Default => {}
LintLevelSource::Node {
name: ref __binding_0,
span: ref __binding_1,
reason: ref __binding_2 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
}
LintLevelSource::CommandLine(ref __binding_0,
ref __binding_1) => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for LintLevelSource {
fn decode(__decoder: &mut __D) -> Self {
match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
{
0usize => { LintLevelSource::Default }
1usize => {
LintLevelSource::Node {
name: ::rustc_serialize::Decodable::decode(__decoder),
span: ::rustc_serialize::Decodable::decode(__decoder),
reason: ::rustc_serialize::Decodable::decode(__decoder),
}
}
2usize => {
LintLevelSource::CommandLine(::rustc_serialize::Decodable::decode(__decoder),
::rustc_serialize::Decodable::decode(__decoder))
}
n => {
::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `LintLevelSource`, expected 0..3, actual {0}",
n));
}
}
}
}
};Decodable, const _: () =
{
impl ::rustc_data_structures::stable_hasher::StableHash for
LintLevelSource {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hasher::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
match *self {
LintLevelSource::Default => {}
LintLevelSource::Node {
name: ref __binding_0,
span: ref __binding_1,
reason: ref __binding_2 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
{ __binding_2.stable_hash(__hcx, __hasher); }
}
LintLevelSource::CommandLine(ref __binding_0,
ref __binding_1) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, #[automatically_derived]
impl ::core::fmt::Debug for LintLevelSource {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
LintLevelSource::Default =>
::core::fmt::Formatter::write_str(f, "Default"),
LintLevelSource::Node {
name: __self_0, span: __self_1, reason: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f, "Node",
"name", __self_0, "span", __self_1, "reason", &__self_2),
LintLevelSource::CommandLine(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"CommandLine", __self_0, &__self_1),
}
}
}Debug)]
20pub enum LintLevelSource {
21 Default,
23
24 Node {
26 name: Symbol,
27 span: Span,
28 reason: Option<Symbol>,
30 },
31
32 CommandLine(Symbol, Level),
36}
37
38impl LintLevelSource {
39 pub fn name(&self) -> Symbol {
40 match *self {
41 LintLevelSource::Default => kw::Default,
42 LintLevelSource::Node { name, .. } => name,
43 LintLevelSource::CommandLine(name, _) => name,
44 }
45 }
46
47 pub fn span(&self) -> Span {
48 match *self {
49 LintLevelSource::Default => DUMMY_SP,
50 LintLevelSource::Node { span, .. } => span,
51 LintLevelSource::CommandLine(_, _) => DUMMY_SP,
52 }
53 }
54}
55
56#[derive(#[automatically_derived]
impl ::core::marker::Copy for LevelAndSource { }Copy, #[automatically_derived]
impl ::core::clone::Clone for LevelAndSource {
#[inline]
fn clone(&self) -> LevelAndSource {
let _: ::core::clone::AssertParamIsClone<Level>;
let _: ::core::clone::AssertParamIsClone<Option<LintExpectationId>>;
let _: ::core::clone::AssertParamIsClone<LintLevelSource>;
*self
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for LevelAndSource {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"LevelAndSource", "level", &self.level, "lint_id", &self.lint_id,
"src", &&self.src)
}
}Debug, const _: () =
{
impl ::rustc_data_structures::stable_hasher::StableHash for
LevelAndSource {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hasher::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
LevelAndSource {
level: ref __binding_0,
lint_id: ref __binding_1,
src: ref __binding_2 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
{ __binding_2.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for LevelAndSource {
fn encode(&self, __encoder: &mut __E) {
match *self {
LevelAndSource {
level: ref __binding_0,
lint_id: ref __binding_1,
src: ref __binding_2 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for LevelAndSource {
fn decode(__decoder: &mut __D) -> Self {
LevelAndSource {
level: ::rustc_serialize::Decodable::decode(__decoder),
lint_id: ::rustc_serialize::Decodable::decode(__decoder),
src: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable)]
58pub struct LevelAndSource {
59 pub level: Level,
60 pub lint_id: Option<LintExpectationId>,
61 pub src: LintLevelSource,
62}
63
64#[derive(#[automatically_derived]
impl ::core::default::Default for ShallowLintLevelMap {
#[inline]
fn default() -> ShallowLintLevelMap {
ShallowLintLevelMap {
expectations: ::core::default::Default::default(),
specs: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl ::core::fmt::Debug for ShallowLintLevelMap {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"ShallowLintLevelMap", "expectations", &self.expectations,
"specs", &&self.specs)
}
}Debug, const _: () =
{
impl ::rustc_data_structures::stable_hasher::StableHash for
ShallowLintLevelMap {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hasher::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
ShallowLintLevelMap {
expectations: ref __binding_0, specs: ref __binding_1 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
69pub struct ShallowLintLevelMap {
70 pub expectations: Vec<(LintExpectationId, LintExpectation)>,
71 pub specs: SortedMap<ItemLocalId, FxIndexMap<LintId, LevelAndSource>>,
72}
73
74pub fn reveal_actual_level(
79 level: Option<(Level, Option<LintExpectationId>)>,
80 src: &mut LintLevelSource,
81 sess: &Session,
82 lint: LintId,
83 probe_for_lint_level: impl FnOnce(
84 LintId,
85 )
86 -> (Option<(Level, Option<LintExpectationId>)>, LintLevelSource),
87) -> (Level, Option<LintExpectationId>) {
88 let (mut level, mut lint_id) =
90 level.unwrap_or_else(|| (lint.lint.default_level(sess.edition()), None));
91
92 if level == Level::Warn {
96 let (warnings_level, warnings_src) = probe_for_lint_level(LintId::of(builtin::WARNINGS));
97 if let Some((configured_warning_level, configured_lint_id)) = warnings_level {
98 let respect_warnings_lint_group = match configured_warning_level {
99 Level::Warn => false,
101 Level::Deny | Level::Forbid => !lint.lint.ignore_deny_warnings,
103 Level::Allow => true,
105 Level::Expect => true,
108 Level::ForceWarn => {
109 sess.dcx().span_delayed_bug(
110 warnings_src.span(),
111 "cannot --force-warn the `warnings` lint group",
112 );
113 false
114 }
115 };
116 if respect_warnings_lint_group {
117 level = configured_warning_level;
118 lint_id = configured_lint_id;
119 *src = warnings_src;
120 }
121 }
122 }
123
124 level = if let LintLevelSource::CommandLine(_, Level::ForceWarn) = src {
126 level
127 } else {
128 cmp::min(level, sess.opts.lint_cap.unwrap_or(Level::Forbid))
129 };
130
131 if let Some(driver_level) = sess.driver_lint_caps.get(&lint) {
132 level = cmp::min(*driver_level, level);
134 }
135
136 (level, lint_id)
137}
138
139impl ShallowLintLevelMap {
140 x;#[instrument(level = "trace", skip(self, tcx), ret)]
144 fn probe_for_lint_level(
145 &self,
146 tcx: TyCtxt<'_>,
147 id: LintId,
148 start: HirId,
149 ) -> (Option<(Level, Option<LintExpectationId>)>, LintLevelSource) {
150 if let Some(map) = self.specs.get(&start.local_id)
151 && let Some(&LevelAndSource { level, lint_id, src }) = map.get(&id)
152 {
153 return (Some((level, lint_id)), src);
154 }
155
156 let mut owner = start.owner;
157 let mut specs = &self.specs;
158
159 for parent in tcx.hir_parent_id_iter(start) {
160 if parent.owner != owner {
161 owner = parent.owner;
162 specs = &tcx.shallow_lint_levels_on(owner).specs;
163 }
164 if let Some(map) = specs.get(&parent.local_id)
165 && let Some(&LevelAndSource { level, lint_id, src }) = map.get(&id)
166 {
167 return (Some((level, lint_id)), src);
168 }
169 }
170
171 (None, LintLevelSource::Default)
172 }
173
174 x;#[instrument(level = "trace", skip(self, tcx), ret)]
176 pub fn lint_level_id_at_node(
177 &self,
178 tcx: TyCtxt<'_>,
179 lint: LintId,
180 cur: HirId,
181 ) -> LevelAndSource {
182 let (level, mut src) = self.probe_for_lint_level(tcx, lint, cur);
183 let (level, lint_id) = reveal_actual_level(level, &mut src, tcx.sess, lint, |lint| {
184 self.probe_for_lint_level(tcx, lint, cur)
185 });
186 LevelAndSource { level, lint_id, src }
187 }
188}
189
190impl TyCtxt<'_> {
191 pub fn lint_level_at_node(self, lint: &'static Lint, id: HirId) -> LevelAndSource {
193 self.shallow_lint_levels_on(id.owner).lint_level_id_at_node(self, LintId::of(lint), id)
194 }
195}
196
197#[derive(#[automatically_derived]
impl ::core::clone::Clone for LintExpectation {
#[inline]
fn clone(&self) -> LintExpectation {
LintExpectation {
reason: ::core::clone::Clone::clone(&self.reason),
emission_span: ::core::clone::Clone::clone(&self.emission_span),
is_unfulfilled_lint_expectations: ::core::clone::Clone::clone(&self.is_unfulfilled_lint_expectations),
lint_tool: ::core::clone::Clone::clone(&self.lint_tool),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for LintExpectation {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f,
"LintExpectation", "reason", &self.reason, "emission_span",
&self.emission_span, "is_unfulfilled_lint_expectations",
&self.is_unfulfilled_lint_expectations, "lint_tool",
&&self.lint_tool)
}
}Debug, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for LintExpectation {
fn encode(&self, __encoder: &mut __E) {
match *self {
LintExpectation {
reason: ref __binding_0,
emission_span: ref __binding_1,
is_unfulfilled_lint_expectations: ref __binding_2,
lint_tool: ref __binding_3 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_3,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for LintExpectation {
fn decode(__decoder: &mut __D) -> Self {
LintExpectation {
reason: ::rustc_serialize::Decodable::decode(__decoder),
emission_span: ::rustc_serialize::Decodable::decode(__decoder),
is_unfulfilled_lint_expectations: ::rustc_serialize::Decodable::decode(__decoder),
lint_tool: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable, const _: () =
{
impl ::rustc_data_structures::stable_hasher::StableHash for
LintExpectation {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hasher::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
LintExpectation {
reason: ref __binding_0,
emission_span: ref __binding_1,
is_unfulfilled_lint_expectations: ref __binding_2,
lint_tool: ref __binding_3 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
{ __binding_2.stable_hash(__hcx, __hasher); }
{ __binding_3.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
201pub struct LintExpectation {
202 pub reason: Option<Symbol>,
205 pub emission_span: Span,
207 pub is_unfulfilled_lint_expectations: bool,
211 pub lint_tool: Option<Symbol>,
215}
216
217impl LintExpectation {
218 pub fn new(
219 reason: Option<Symbol>,
220 emission_span: Span,
221 is_unfulfilled_lint_expectations: bool,
222 lint_tool: Option<Symbol>,
223 ) -> Self {
224 Self { reason, emission_span, is_unfulfilled_lint_expectations, lint_tool }
225 }
226}
227
228fn explain_lint_level_source(
229 sess: &Session,
230 lint: &'static Lint,
231 level: Level,
232 src: LintLevelSource,
233 err: &mut Diag<'_, ()>,
234) {
235 let lint_group_name = |lint| {
238 let lint_groups_iter = sess.lint_groups_iter();
239 let lint_id = LintId::of(lint);
240 lint_groups_iter
241 .filter(|lint_group| !lint_group.is_externally_loaded)
242 .find(|lint_group| {
243 lint_group
244 .lints
245 .iter()
246 .find(|lint_group_lint| **lint_group_lint == lint_id)
247 .is_some()
248 })
249 .map(|lint_group| lint_group.name)
250 };
251 let name = lint.name_lower();
252 if let Level::Allow = level {
253 return;
256 }
257 match src {
258 LintLevelSource::Default => {
259 let level_str = level.as_str();
260 match lint_group_name(lint) {
261 Some(group_name) => {
262 err.note_once(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`#[{0}({1})]` (part of `#[{0}({2})]`) on by default",
level_str, name, group_name))
})format!("`#[{level_str}({name})]` (part of `#[{level_str}({group_name})]`) on by default"));
263 }
264 None => {
265 err.note_once(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`#[{0}({1})]` on by default",
level_str, name))
})format!("`#[{level_str}({name})]` on by default"));
266 }
267 }
268 }
269 LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
270 let flag = orig_level.to_cmd_flag();
271 let hyphen_case_lint_name = name.replace('_', "-");
272 if lint_flag_val.as_str() == name {
273 err.note_once(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("requested on the command line with `{0} {1}`",
flag, hyphen_case_lint_name))
})format!(
274 "requested on the command line with `{flag} {hyphen_case_lint_name}`"
275 ));
276 } else {
277 let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
278 err.note_once(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0} {1}` implied by `{0} {2}`",
flag, hyphen_case_lint_name, hyphen_case_flag_val))
})format!(
279 "`{flag} {hyphen_case_lint_name}` implied by `{flag} {hyphen_case_flag_val}`"
280 ));
281 if #[allow(non_exhaustive_omitted_patterns)] match orig_level {
Level::Warn | Level::Deny => true,
_ => false,
}matches!(orig_level, Level::Warn | Level::Deny) {
282 let help = if name == "dead_code" {
283 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("to override `{0} {1}` add `#[expect({2})]` or `#[allow({2})]`",
flag, hyphen_case_flag_val, name))
})format!(
284 "to override `{flag} {hyphen_case_flag_val}` add `#[expect({name})]` or `#[allow({name})]`"
285 )
286 } else {
287 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("to override `{0} {1}` add `#[allow({2})]`",
flag, hyphen_case_flag_val, name))
})format!(
288 "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`"
289 )
290 };
291 err.help_once(help);
292 }
293 }
294 }
295 LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => {
296 if let Some(rationale) = reason {
297 err.note(rationale.to_string());
298 }
299 err.span_note_once(span, "the lint level is defined here");
300 if lint_attr_name.as_str() != name {
301 let level_str = level.as_str();
302 err.note_once(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`#[{0}({1})]` implied by `#[{0}({2})]`",
level_str, name, lint_attr_name))
})format!(
303 "`#[{level_str}({name})]` implied by `#[{level_str}({lint_attr_name})]`"
304 ));
305 }
306 }
307 }
308
309 if let Some(warnings_group) = sess
310 .opts
311 .lint_opts
312 .iter()
313 .find_map(|(opt, level)| (opt == "warnings").then_some(level))
314 .copied()
315 && warnings_group >= Level::Deny
316 && level < warnings_group
317 {
318 err.note_once(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the `{0}` lint ignores `-D warnings`",
name))
})format!("the `{name}` lint ignores `-D warnings`"));
319 }
320}
321
322#[track_caller]
330pub fn emit_lint_base<'a, D: Diagnostic<'a, ()> + 'a>(
331 sess: &'a Session,
332 lint: &'static Lint,
333 level: LevelAndSource,
334 span: Option<MultiSpan>,
335 decorate: D,
336) {
337 #[track_caller]
340 fn emit_lint_base_impl<'a>(
341 sess: &'a Session,
342 lint: &'static Lint,
343 level: LevelAndSource,
344 span: Option<MultiSpan>,
345 decorate: Box<
346 dyn FnOnce(rustc_errors::DiagCtxtHandle<'a>, rustc_errors::Level) -> Diag<'a, ()> + 'a,
347 >,
348 ) {
349 let LevelAndSource { level, lint_id, src } = level;
350
351 let future_incompatible = lint.future_incompatible;
353
354 let has_future_breakage = future_incompatible.map_or(
355 sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
357 |incompat| incompat.report_in_deps,
358 );
359
360 let err_level = match level {
362 Level::Allow => {
363 if has_future_breakage {
364 rustc_errors::Level::Allow
365 } else {
366 return;
367 }
368 }
369 Level::Expect => {
370 rustc_errors::Level::Expect
378 }
379 Level::ForceWarn => rustc_errors::Level::ForceWarning,
380 Level::Warn => rustc_errors::Level::Warning,
381 Level::Deny | Level::Forbid => rustc_errors::Level::Error,
382 };
383
384 let disable_suggestions = if let Some(ref span) = span
385 && span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map()))
389 {
390 true
391 } else {
392 false
393 };
394
395 if disable_suggestions {
396 let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none());
401
402 let is_in_find_attr = sess.enable_internal_lints()
406 && span.as_ref().is_some_and(|span| {
407 span.primary_spans().iter().any(|s| {
408 s.source_callee().is_some_and(|i| {
409 #[allow(non_exhaustive_omitted_patterns)] match i.kind {
ExpnKind::Macro(_, name) if name.as_str() == "find_attr" => true,
_ => false,
}matches!(i.kind, ExpnKind::Macro(_, name) if name.as_str() == "find_attr")
410 })
411 })
412 });
413
414 if !incompatible && !lint.report_in_external_macro && !is_in_find_attr {
415 return;
418 }
419 }
420 let skip = err_level == rustc_errors::Level::Warning && !sess.dcx().can_emit_warnings();
431
432 let mut err: Diag<'_, ()> = if !skip {
433 decorate(sess.dcx(), err_level)
434 } else {
435 Diag::new(sess.dcx(), err_level, "")
436 };
437 err.emitted_at = DiagLocation::caller();
439
440 if let Some(span) = span
441 && err.span.primary_span().is_none()
442 {
443 for primary in span.primary_spans() {
445 err.span.push_primary_span(*primary);
446 }
447 for (label_span, label) in span.span_labels_raw() {
448 err.span.push_span_diag(*label_span, label.clone());
449 }
450 }
451 if let Some(lint_id) = lint_id {
452 err.lint_id(lint_id);
453 }
454
455 if disable_suggestions {
456 err.disable_suggestions();
459 }
460
461 err.is_lint(lint.name_lower(), has_future_breakage);
462 if let Level::Expect = level {
467 err.emit();
468 return;
469 }
470
471 if let Some(future_incompatible) = future_incompatible {
472 let explanation = match future_incompatible.reason {
473 FutureIncompatibilityReason::FutureReleaseError(_) => {
474 "this was previously accepted by the compiler but is being phased out; \
475 it will become a hard error in a future release!"
476 .to_owned()
477 }
478 FutureIncompatibilityReason::FutureReleaseSemanticsChange(_) => {
479 "this will change its meaning in a future release!".to_owned()
480 }
481 FutureIncompatibilityReason::EditionError(EditionFcw { edition, .. }) => {
482 let current_edition = sess.edition();
483 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this is accepted in the current edition (Rust {0}) but is a hard error in Rust {1}!",
current_edition, edition))
})format!(
484 "this is accepted in the current edition (Rust {current_edition}) but is a hard error in Rust {edition}!"
485 )
486 }
487 FutureIncompatibilityReason::EditionSemanticsChange(EditionFcw {
488 edition, ..
489 }) => {
490 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this changes meaning in Rust {0}",
edition))
})format!("this changes meaning in Rust {edition}")
491 }
492 FutureIncompatibilityReason::EditionAndFutureReleaseError(EditionFcw {
493 edition,
494 ..
495 }) => {
496 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust {0} and in a future release in all editions!",
edition))
})format!(
497 "this was previously accepted by the compiler but is being phased out; \
498 it will become a hard error in Rust {edition} and in a future release in all editions!"
499 )
500 }
501 FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(
502 EditionFcw { edition, .. },
503 ) => {
504 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this changes meaning in Rust {0} and in a future release in all editions!",
edition))
})format!(
505 "this changes meaning in Rust {edition} and in a future release in all editions!"
506 )
507 }
508 FutureIncompatibilityReason::Custom(reason, _) => reason.to_owned(),
509 FutureIncompatibilityReason::Unreachable => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
510 };
511
512 if future_incompatible.explain_reason {
513 err.warn(explanation);
514 }
515
516 let citation =
517 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("for more information, see {0}",
future_incompatible.reason.reference()))
})format!("for more information, see {}", future_incompatible.reason.reference());
518 err.note(citation);
519 }
520
521 explain_lint_level_source(sess, lint, level, src, &mut err);
522 err.emit();
523 }
524 emit_lint_base_impl(
525 sess,
526 lint,
527 level,
528 span,
529 Box::new(move |dcx, level| decorate.into_diag(dcx, level)),
530 );
531}