1use std::cell::Cell;
9use std::collections::hash_map::Entry;
10
11use rustc_abi::{Align, ExternAbi, Size};
12use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
13use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr};
14use rustc_data_structures::fx::FxHashMap;
15use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
16use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
17use rustc_hir::def::DefKind;
18use rustc_hir::def_id::LocalModDefId;
19use rustc_hir::intravisit::{self, Visitor};
20use rustc_hir::{
21 self as hir, self, AssocItemKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem,
22 HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem,
23};
24use rustc_macros::LintDiagnostic;
25use rustc_middle::hir::nested_filter;
26use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
27use rustc_middle::query::Providers;
28use rustc_middle::traits::ObligationCause;
29use rustc_middle::ty::error::{ExpectedFound, TypeError};
30use rustc_middle::ty::{self, TyCtxt, TypingMode};
31use rustc_middle::{bug, span_bug};
32use rustc_session::config::CrateType;
33use rustc_session::lint;
34use rustc_session::lint::builtin::{
35 CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
36 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
37};
38use rustc_session::parse::feature_err;
39use rustc_span::edition::Edition;
40use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym};
41use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
42use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
43use rustc_trait_selection::traits::ObligationCtxt;
44use tracing::debug;
45
46use crate::{errors, fluent_generated as fluent};
47
48#[derive(LintDiagnostic)]
49#[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
50struct DiagnosticOnUnimplementedOnlyForTraits;
51
52fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
53 match impl_item.kind {
54 hir::ImplItemKind::Const(..) => Target::AssocConst,
55 hir::ImplItemKind::Fn(..) => {
56 let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
57 let containing_item = tcx.hir_expect_item(parent_def_id);
58 let containing_impl_is_for_trait = match &containing_item.kind {
59 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
60 _ => bug!("parent of an ImplItem must be an Impl"),
61 };
62 if containing_impl_is_for_trait {
63 Target::Method(MethodKind::Trait { body: true })
64 } else {
65 Target::Method(MethodKind::Inherent)
66 }
67 }
68 hir::ImplItemKind::Type(..) => Target::AssocTy,
69 }
70}
71
72#[derive(Clone, Copy)]
73enum ItemLike<'tcx> {
74 Item(&'tcx Item<'tcx>),
75 ForeignItem,
76}
77
78#[derive(Copy, Clone)]
79pub(crate) enum ProcMacroKind {
80 FunctionLike,
81 Derive,
82 Attribute,
83}
84
85impl IntoDiagArg for ProcMacroKind {
86 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
87 match self {
88 ProcMacroKind::Attribute => "attribute proc macro",
89 ProcMacroKind::Derive => "derive proc macro",
90 ProcMacroKind::FunctionLike => "function-like proc macro",
91 }
92 .into_diag_arg(&mut None)
93 }
94}
95
96struct CheckAttrVisitor<'tcx> {
97 tcx: TyCtxt<'tcx>,
98
99 abort: Cell<bool>,
101}
102
103impl<'tcx> CheckAttrVisitor<'tcx> {
104 fn dcx(&self) -> DiagCtxtHandle<'tcx> {
105 self.tcx.dcx()
106 }
107
108 fn check_attributes(
110 &self,
111 hir_id: HirId,
112 span: Span,
113 target: Target,
114 item: Option<ItemLike<'_>>,
115 ) {
116 let mut doc_aliases = FxHashMap::default();
117 let mut specified_inline = None;
118 let mut seen = FxHashMap::default();
119 let attrs = self.tcx.hir_attrs(hir_id);
120 for attr in attrs {
121 let mut style = None;
122 match attr {
123 Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch {
124 span: attr_span,
125 ..
126 }) => {
127 self.check_must_be_applied_to_trait(*attr_span, span, target);
128 }
129 Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
130 self.check_confusables(*first_span, target);
131 }
132 Attribute::Parsed(
133 AttributeKind::Stability { span, .. }
134 | AttributeKind::ConstStability { span, .. },
135 ) => self.check_stability_promotable(*span, target),
136 Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
138 self.check_inline(hir_id, *attr_span, span, kind, target)
139 }
140 Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => {
141 self.check_optimize(hir_id, *attr_span, span, target)
142 }
143 Attribute::Parsed(AttributeKind::LoopMatch(attr_span)) => {
144 self.check_loop_match(hir_id, *attr_span, target)
145 }
146 Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
147 self.check_const_continue(hir_id, *attr_span, target)
148 }
149 Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
150 .check_allow_internal_unstable(
151 hir_id,
152 syms.first().unwrap().1,
153 span,
154 target,
155 attrs,
156 ),
157 Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => {
158 self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
159 }
160 Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
161 self.check_deprecated(hir_id, attr, span, target)
162 }
163 Attribute::Parsed(AttributeKind::DocComment { .. }) => { }
165 Attribute::Parsed(AttributeKind::Repr(_)) => { }
167
168 &Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => {
169 self.check_rustc_pub_transparent(attr_span, span, attrs)
170 }
171 Attribute::Parsed(AttributeKind::Cold(attr_span)) => {
172 self.check_cold(hir_id, *attr_span, span, target)
173 }
174 Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => {
175 self.check_export_name(hir_id, *attr_span, span, target)
176 }
177 Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
178 self.check_align(span, target, *align, *repr_span)
179 }
180 Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
181 self.check_naked(hir_id, *attr_span, span, target)
182 }
183 Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
184 self.check_track_caller(hir_id, *attr_span, attrs, span, target)
185 }
186 Attribute::Parsed(
187 AttributeKind::BodyStability { .. }
188 | AttributeKind::ConstStabilityIndirect
189 | AttributeKind::MacroTransparency(_),
190 ) => { }
191 Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
192 self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
193 }
194 Attribute::Parsed(AttributeKind::LinkName { span: attr_span, name }) => {
195 self.check_link_name(hir_id, *attr_span, *name, span, target)
196 }
197 Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
198 self.check_may_dangle(hir_id, *attr_span)
199 }
200 Attribute::Parsed(AttributeKind::MustUse { span, .. }) => {
201 self.check_must_use(hir_id, *span, target)
202 }
203 Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => {
204 self.check_no_mangle(hir_id, *attr_span, span, target)
205 }
206 Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => {
207 self.check_used(*attr_span, target, span);
208 }
209 Attribute::Unparsed(attr_item) => {
210 style = Some(attr_item.style);
211 match attr.path().as_slice() {
212 [sym::diagnostic, sym::do_not_recommend, ..] => {
213 self.check_do_not_recommend(attr.span(), hir_id, target, attr, item)
214 }
215 [sym::diagnostic, sym::on_unimplemented, ..] => {
216 self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
217 }
218 [sym::coverage, ..] => self.check_coverage(attr, span, target),
219 [sym::no_sanitize, ..] => {
220 self.check_no_sanitize(attr, span, target)
221 }
222 [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
223 [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
224 [sym::target_feature, ..] => {
225 self.check_target_feature(hir_id, attr, span, target, attrs)
226 }
227 [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
228 [sym::doc, ..] => self.check_doc_attrs(
229 attr,
230 attr_item.style,
231 hir_id,
232 target,
233 &mut specified_inline,
234 &mut doc_aliases,
235 ),
236 [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
237 [sym::rustc_layout_scalar_valid_range_start, ..]
238 | [sym::rustc_layout_scalar_valid_range_end, ..] => {
239 self.check_rustc_layout_scalar_valid_range(attr, span, target)
240 }
241 [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
242 [sym::rustc_std_internal_symbol, ..] => {
243 self.check_rustc_std_internal_symbol(attr, span, target)
244 }
245 [sym::rustc_no_implicit_autorefs, ..] => {
246 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
247 }
248 [sym::rustc_never_returns_null_ptr, ..] => {
249 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
250 }
251 [sym::rustc_legacy_const_generics, ..] => {
252 self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
253 }
254 [sym::rustc_lint_query_instability, ..] => {
255 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
256 }
257 [sym::rustc_lint_untracked_query_information, ..] => {
258 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
259 }
260 [sym::rustc_lint_diagnostics, ..] => {
261 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
262 }
263 [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
264 [sym::rustc_lint_opt_deny_field_access, ..] => {
265 self.check_rustc_lint_opt_deny_field_access(attr, span, target)
266 }
267 [sym::rustc_clean, ..]
268 | [sym::rustc_dirty, ..]
269 | [sym::rustc_if_this_changed, ..]
270 | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
271 [sym::rustc_coinductive, ..]
272 | [sym::rustc_must_implement_one_of, ..]
273 | [sym::rustc_deny_explicit_impl, ..]
274 | [sym::rustc_do_not_implement_via_object, ..]
275 | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
276 [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
277 [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
278 [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
279 [sym::rustc_allow_incoherent_impl, ..] => {
280 self.check_allow_incoherent_impl(attr, span, target)
281 }
282 [sym::rustc_has_incoherent_inherent_impls, ..] => {
283 self.check_has_incoherent_inherent_impls(attr, span, target)
284 }
285 [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target),
286 [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
287 [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
288 [sym::link, ..] => self.check_link(hir_id, attr, span, target),
289 [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
290 [sym::macro_use, ..] | [sym::macro_escape, ..] => {
291 self.check_macro_use(hir_id, attr, target)
292 }
293 [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
294 [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
295 [sym::ignore, ..] | [sym::should_panic, ..] => {
296 self.check_generic_attr(hir_id, attr, target, Target::Fn)
297 }
298 [sym::automatically_derived, ..] => {
299 self.check_generic_attr(hir_id, attr, target, Target::Impl)
300 }
301 [sym::no_implicit_prelude, ..] => {
302 self.check_generic_attr(hir_id, attr, target, Target::Mod)
303 }
304 [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id),
305 [sym::proc_macro, ..] => {
306 self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
307 }
308 [sym::proc_macro_attribute, ..] => {
309 self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
310 }
311 [sym::proc_macro_derive, ..] => {
312 self.check_generic_attr(hir_id, attr, target, Target::Fn);
313 self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
314 }
315 [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
316 self.check_autodiff(hir_id, attr, span, target)
317 }
318 [sym::coroutine, ..] => {
319 self.check_coroutine(attr, target);
320 }
321 [sym::type_const, ..] => {
322 self.check_type_const(hir_id,attr, target);
323 }
324 [sym::linkage, ..] => self.check_linkage(attr, span, target),
325 [
326 sym::allow
328 | sym::expect
329 | sym::warn
330 | sym::deny
331 | sym::forbid
332 | sym::cfg
333 | sym::cfg_attr
334 | sym::cfg_trace
335 | sym::cfg_attr_trace
336 | sym::export_stable | sym::cfi_encoding | sym::pointee | sym::omit_gdb_pretty_printer_section | sym::instruction_set | sym::windows_subsystem | sym::patchable_function_entry | sym::deprecated_safe | sym::prelude_import
347 | sym::panic_handler
348 | sym::allow_internal_unsafe
349 | sym::fundamental
350 | sym::lang
351 | sym::needs_allocator
352 | sym::default_lib_allocator
353 | sym::custom_mir,
354 ..
355 ] => {}
356 [name, ..] => {
357 match BUILTIN_ATTRIBUTE_MAP.get(name) {
358 Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
360 Some(_) => {
361 if !name.as_str().starts_with("rustc_") {
365 span_bug!(
366 attr.span(),
367 "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
368 )
369 }
370 }
371 None => (),
372 }
373 }
374 [] => unreachable!(),
375 }
376 }
377 }
378
379 let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
380
381 if hir_id != CRATE_HIR_ID {
382 if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
383 attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
384 {
385 match style {
386 Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint(
387 UNUSED_ATTRIBUTES,
388 hir_id,
389 attr.span(),
390 errors::OuterCrateLevelAttr,
391 ),
392 Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
393 UNUSED_ATTRIBUTES,
394 hir_id,
395 attr.span(),
396 errors::InnerCrateLevelAttr,
397 ),
398 }
399 }
400 }
401
402 if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
403 check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
404 }
405
406 self.check_unused_attribute(hir_id, attr, style)
407 }
408
409 self.check_repr(attrs, span, target, item, hir_id);
410 self.check_rustc_force_inline(hir_id, attrs, span, target);
411 self.check_mix_no_mangle_export(hir_id, attrs);
412 }
413
414 fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) {
415 self.tcx.emit_node_span_lint(
416 UNUSED_ATTRIBUTES,
417 hir_id,
418 attr_span,
419 errors::IgnoredAttrWithMacro { sym },
420 );
421 }
422
423 fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) {
424 self.tcx.emit_node_span_lint(
425 UNUSED_ATTRIBUTES,
426 hir_id,
427 attr_span,
428 errors::IgnoredAttr { sym },
429 );
430 }
431
432 fn check_do_not_recommend(
434 &self,
435 attr_span: Span,
436 hir_id: HirId,
437 target: Target,
438 attr: &Attribute,
439 item: Option<ItemLike<'_>>,
440 ) {
441 if !matches!(target, Target::Impl)
442 || matches!(
443 item,
444 Some(ItemLike::Item(hir::Item { kind: hir::ItemKind::Impl(_impl),.. }))
445 if _impl.of_trait.is_none()
446 )
447 {
448 self.tcx.emit_node_span_lint(
449 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
450 hir_id,
451 attr_span,
452 errors::IncorrectDoNotRecommendLocation,
453 );
454 }
455 if !attr.is_word() {
456 self.tcx.emit_node_span_lint(
457 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
458 hir_id,
459 attr_span,
460 errors::DoNotRecommendDoesNotExpectArgs,
461 );
462 }
463 }
464
465 fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
467 if !matches!(target, Target::Trait) {
468 self.tcx.emit_node_span_lint(
469 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
470 hir_id,
471 attr_span,
472 DiagnosticOnUnimplementedOnlyForTraits,
473 );
474 }
475 }
476
477 fn check_inline(
479 &self,
480 hir_id: HirId,
481 attr_span: Span,
482 defn_span: Span,
483 kind: &InlineAttr,
484 target: Target,
485 ) {
486 match target {
487 Target::Fn
488 | Target::Closure
489 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
490 Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
491 self.tcx.emit_node_span_lint(
492 UNUSED_ATTRIBUTES,
493 hir_id,
494 attr_span,
495 errors::IgnoredInlineAttrFnProto,
496 )
497 }
498 Target::AssocConst => self.tcx.emit_node_span_lint(
503 UNUSED_ATTRIBUTES,
504 hir_id,
505 attr_span,
506 errors::IgnoredInlineAttrConstants,
507 ),
508 Target::Field | Target::Arm | Target::MacroDef => {
510 self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "inline")
511 }
512 _ => {
513 self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span });
514 }
515 }
516
517 if let Some(did) = hir_id.as_owner()
519 && self.tcx.def_kind(did).has_codegen_attrs()
520 && kind != &InlineAttr::Never
521 {
522 let attrs = self.tcx.codegen_fn_attrs(did);
523 if attrs.contains_extern_indicator() {
525 self.tcx.emit_node_span_lint(
526 UNUSED_ATTRIBUTES,
527 hir_id,
528 attr_span,
529 errors::InlineIgnoredForExported {},
530 );
531 }
532 }
533 }
534
535 fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
538 let mut not_fn_impl_mod = None;
539 let mut no_body = None;
540
541 match target {
542 Target::Fn
543 | Target::Closure
544 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
545 | Target::Impl
546 | Target::Mod => return,
547
548 Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
551 no_body = Some(target_span);
552 }
553
554 _ => {
555 not_fn_impl_mod = Some(target_span);
556 }
557 }
558
559 self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
560 attr_span: attr.span(),
561 not_fn_impl_mod,
562 no_body,
563 help: (),
564 });
565 }
566
567 fn check_optimize(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
570 let is_valid = matches!(
571 target,
572 Target::Fn
573 | Target::Closure
574 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
575 );
576 if !is_valid {
577 self.dcx().emit_err(errors::OptimizeInvalidTarget {
578 attr_span,
579 defn_span: span,
580 on_crate: hir_id == CRATE_HIR_ID,
581 });
582 }
583 }
584
585 fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
586 if let Some(list) = attr.meta_item_list() {
587 for item in list.iter() {
588 let sym = item.name();
589 match sym {
590 Some(s @ sym::address | s @ sym::hwaddress) => {
591 let is_valid =
592 matches!(target, Target::Fn | Target::Method(..) | Target::Static);
593 if !is_valid {
594 self.dcx().emit_err(errors::NoSanitize {
595 attr_span: item.span(),
596 defn_span: span,
597 accepted_kind: "a function or static",
598 attr_str: s.as_str(),
599 });
600 }
601 }
602 _ => {
603 let is_valid = matches!(target, Target::Fn | Target::Method(..));
604 if !is_valid {
605 self.dcx().emit_err(errors::NoSanitize {
606 attr_span: item.span(),
607 defn_span: span,
608 accepted_kind: "a function",
609 attr_str: &match sym {
610 Some(name) => name.to_string(),
611 None => "...".to_string(),
612 },
613 });
614 }
615 }
616 }
617 }
618 }
619 }
620
621 fn check_generic_attr(
622 &self,
623 hir_id: HirId,
624 attr: &Attribute,
625 target: Target,
626 allowed_target: Target,
627 ) {
628 if target != allowed_target {
629 let path = attr.path();
630 let path: Vec<_> = path.iter().map(|s| s.as_str()).collect();
631 let attr_name = path.join("::");
632 self.tcx.emit_node_span_lint(
633 UNUSED_ATTRIBUTES,
634 hir_id,
635 attr.span(),
636 errors::OnlyHasEffectOn {
637 attr_name,
638 target_name: allowed_target.name().replace(' ', "_"),
639 },
640 );
641 }
642 }
643
644 fn check_naked(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
646 match target {
647 Target::Fn
648 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
649 let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
650 let abi = fn_sig.header.abi;
651 if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() {
652 feature_err(
653 &self.tcx.sess,
654 sym::naked_functions_rustic_abi,
655 fn_sig.span,
656 format!(
657 "`#[naked]` is currently unstable on `extern \"{}\"` functions",
658 abi.as_str()
659 ),
660 )
661 .emit();
662 }
663 }
664 _ => {
665 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
666 attr_span,
667 defn_span: span,
668 on_crate: hir_id == CRATE_HIR_ID,
669 });
670 }
671 }
672 }
673
674 fn check_object_lifetime_default(&self, hir_id: HirId) {
676 let tcx = self.tcx;
677 if let Some(owner_id) = hir_id.as_owner()
678 && let Some(generics) = tcx.hir_get_generics(owner_id.def_id)
679 {
680 for p in generics.params {
681 let hir::GenericParamKind::Type { .. } = p.kind else { continue };
682 let default = tcx.object_lifetime_default(p.def_id);
683 let repr = match default {
684 ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
685 ObjectLifetimeDefault::Static => "'static".to_owned(),
686 ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
687 ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
688 };
689 tcx.dcx().emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
690 }
691 }
692 }
693
694 fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) {
696 match target {
697 Target::MacroDef => {}
698 _ => {
699 self.tcx.dcx().emit_err(errors::CollapseDebuginfo {
700 attr_span: attr.span(),
701 defn_span: span,
702 });
703 }
704 }
705 }
706
707 fn check_track_caller(
709 &self,
710 hir_id: HirId,
711 attr_span: Span,
712 attrs: &[Attribute],
713 span: Span,
714 target: Target,
715 ) {
716 match target {
717 Target::Fn => {
718 if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
721 && let Some(item) = hir::LangItem::from_name(lang_item)
722 && item.is_weak()
723 {
724 let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
725
726 self.dcx().emit_err(errors::LangItemWithTrackCaller {
727 attr_span,
728 name: lang_item,
729 sig_span: sig.span,
730 });
731 }
732 }
733 Target::Method(..) | Target::ForeignFn | Target::Closure => {}
734 Target::Field | Target::Arm | Target::MacroDef => {
739 self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller");
740 }
741 _ => {
742 self.dcx().emit_err(errors::TrackedCallerWrongLocation {
743 attr_span,
744 defn_span: span,
745 on_crate: hir_id == CRATE_HIR_ID,
746 });
747 }
748 }
749 }
750
751 fn check_non_exhaustive(
753 &self,
754 hir_id: HirId,
755 attr: &Attribute,
756 span: Span,
757 target: Target,
758 item: Option<ItemLike<'_>>,
759 ) {
760 match target {
761 Target::Struct => {
762 if let Some(ItemLike::Item(hir::Item {
763 kind: hir::ItemKind::Struct(_, _, hir::VariantData::Struct { fields, .. }),
764 ..
765 })) = item
766 && !fields.is_empty()
767 && fields.iter().any(|f| f.default.is_some())
768 {
769 self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
770 attr_span: attr.span(),
771 defn_span: span,
772 });
773 }
774 }
775 Target::Enum | Target::Variant => {}
776 Target::Field | Target::Arm | Target::MacroDef => {
781 self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive");
782 }
783 _ => {
784 self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
785 attr_span: attr.span(),
786 defn_span: span,
787 });
788 }
789 }
790 }
791
792 fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
794 match target {
795 Target::Trait => {}
796 Target::Field | Target::Arm | Target::MacroDef => {
801 self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "marker");
802 }
803 _ => {
804 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
805 attr_span: attr.span(),
806 defn_span: span,
807 });
808 }
809 }
810 }
811
812 fn check_target_feature(
814 &self,
815 hir_id: HirId,
816 attr: &Attribute,
817 span: Span,
818 target: Target,
819 attrs: &[Attribute],
820 ) {
821 match target {
822 Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
823 | Target::Fn => {
824 if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
826 && !self.tcx.sess.target.is_like_wasm
829 && !self.tcx.sess.opts.actually_rustdoc
830 {
831 let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
832
833 self.dcx().emit_err(errors::LangItemWithTargetFeature {
834 attr_span: attr.span(),
835 name: lang_item,
836 sig_span: sig.span,
837 });
838 }
839 }
840 Target::Statement => {
843 self.tcx.emit_node_span_lint(
844 UNUSED_ATTRIBUTES,
845 hir_id,
846 attr.span(),
847 errors::TargetFeatureOnStatement,
848 );
849 }
850 Target::Field | Target::Arm | Target::MacroDef => {
855 self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "target_feature");
856 }
857 _ => {
858 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
859 attr_span: attr.span(),
860 defn_span: span,
861 on_crate: hir_id == CRATE_HIR_ID,
862 });
863 }
864 }
865 }
866
867 fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) {
869 match target {
870 Target::ForeignStatic | Target::Static => {}
871 _ => {
872 self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
873 attr_span: attr.span(),
874 defn_span: span,
875 });
876 }
877 }
878 }
879
880 fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) {
881 self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
882 }
883
884 fn check_doc_alias_value(
885 &self,
886 meta: &MetaItemInner,
887 doc_alias: Symbol,
888 hir_id: HirId,
889 target: Target,
890 is_list: bool,
891 aliases: &mut FxHashMap<String, Span>,
892 ) {
893 let tcx = self.tcx;
894 let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
895 let attr_str =
896 &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
897 if doc_alias == sym::empty {
898 tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
899 return;
900 }
901
902 let doc_alias_str = doc_alias.as_str();
903 if let Some(c) = doc_alias_str
904 .chars()
905 .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
906 {
907 tcx.dcx().emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
908 return;
909 }
910 if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
911 tcx.dcx().emit_err(errors::DocAliasStartEnd { span, attr_str });
912 return;
913 }
914
915 let span = meta.span();
916 if let Some(location) = match target {
917 Target::AssocTy => {
918 let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
919 let containing_item = self.tcx.hir_expect_item(parent_def_id);
920 if Target::from_item(containing_item) == Target::Impl {
921 Some("type alias in implementation block")
922 } else {
923 None
924 }
925 }
926 Target::AssocConst => {
927 let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
928 let containing_item = self.tcx.hir_expect_item(parent_def_id);
929 let err = "associated constant in trait implementation block";
931 match containing_item.kind {
932 ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
933 _ => None,
934 }
935 }
936 Target::Param => return,
938 Target::Expression
939 | Target::Statement
940 | Target::Arm
941 | Target::ForeignMod
942 | Target::Closure
943 | Target::Impl
944 | Target::WherePredicate => Some(target.name()),
945 Target::ExternCrate
946 | Target::Use
947 | Target::Static
948 | Target::Const
949 | Target::Fn
950 | Target::Mod
951 | Target::GlobalAsm
952 | Target::TyAlias
953 | Target::Enum
954 | Target::Variant
955 | Target::Struct
956 | Target::Field
957 | Target::Union
958 | Target::Trait
959 | Target::TraitAlias
960 | Target::Method(..)
961 | Target::ForeignFn
962 | Target::ForeignStatic
963 | Target::ForeignTy
964 | Target::GenericParam(..)
965 | Target::MacroDef
966 | Target::PatField
967 | Target::ExprField => None,
968 } {
969 tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location });
970 return;
971 }
972 if self.tcx.hir_opt_name(hir_id) == Some(doc_alias) {
973 tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str });
974 return;
975 }
976 if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
977 self.tcx.emit_node_span_lint(
978 UNUSED_ATTRIBUTES,
979 hir_id,
980 span,
981 errors::DocAliasDuplicated { first_defn: *entry.entry.get() },
982 );
983 }
984 }
985
986 fn check_doc_alias(
987 &self,
988 meta: &MetaItemInner,
989 hir_id: HirId,
990 target: Target,
991 aliases: &mut FxHashMap<String, Span>,
992 ) {
993 if let Some(values) = meta.meta_item_list() {
994 for v in values {
995 match v.lit() {
996 Some(l) => match l.kind {
997 LitKind::Str(s, _) => {
998 self.check_doc_alias_value(v, s, hir_id, target, true, aliases);
999 }
1000 _ => {
1001 self.tcx
1002 .dcx()
1003 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
1004 }
1005 },
1006 None => {
1007 self.tcx
1008 .dcx()
1009 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
1010 }
1011 }
1012 }
1013 } else if let Some(doc_alias) = meta.value_str() {
1014 self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
1015 } else {
1016 self.dcx().emit_err(errors::DocAliasMalformed { span: meta.span() });
1017 }
1018 }
1019
1020 fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) {
1021 fn is_doc_keyword(s: Symbol) -> bool {
1022 s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy
1026 }
1027
1028 let doc_keyword = match meta.value_str() {
1029 Some(value) if value != sym::empty => value,
1030 _ => return self.doc_attr_str_error(meta, "keyword"),
1031 };
1032
1033 let item_kind = match self.tcx.hir_node(hir_id) {
1034 hir::Node::Item(item) => Some(&item.kind),
1035 _ => None,
1036 };
1037 match item_kind {
1038 Some(ItemKind::Mod(_, module)) => {
1039 if !module.item_ids.is_empty() {
1040 self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
1041 return;
1042 }
1043 }
1044 _ => {
1045 self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() });
1046 return;
1047 }
1048 }
1049 if !is_doc_keyword(doc_keyword) {
1050 self.dcx().emit_err(errors::DocKeywordNotKeyword {
1051 span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
1052 keyword: doc_keyword,
1053 });
1054 }
1055 }
1056
1057 fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) {
1058 let item_kind = match self.tcx.hir_node(hir_id) {
1059 hir::Node::Item(item) => Some(&item.kind),
1060 _ => None,
1061 };
1062 match item_kind {
1063 Some(ItemKind::Impl(i)) => {
1064 let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
1065 || if let Some(&[hir::GenericArg::Type(ty)]) = i
1066 .of_trait
1067 .as_ref()
1068 .and_then(|trait_ref| trait_ref.path.segments.last())
1069 .map(|last_segment| last_segment.args().args)
1070 {
1071 matches!(&ty.kind, hir::TyKind::Tup([_]))
1072 } else {
1073 false
1074 };
1075 if !is_valid {
1076 self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
1077 }
1078 }
1079 _ => {
1080 self.dcx().emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
1081 }
1082 }
1083 }
1084
1085 fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) {
1086 let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
1087 self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
1088 return;
1089 };
1090 match item.kind {
1091 ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _)
1092 if generics.params.len() != 0 => {}
1093 ItemKind::Trait(_, _, _, generics, _, items)
1094 if generics.params.len() != 0
1095 || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
1096 ItemKind::TyAlias(_, generics, _) if generics.params.len() != 0 => {}
1097 _ => {
1098 self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
1099 }
1100 }
1101 }
1102
1103 fn check_doc_inline(
1113 &self,
1114 style: AttrStyle,
1115 meta: &MetaItemInner,
1116 hir_id: HirId,
1117 target: Target,
1118 specified_inline: &mut Option<(bool, Span)>,
1119 ) {
1120 match target {
1121 Target::Use | Target::ExternCrate => {
1122 let do_inline = meta.has_name(sym::inline);
1123 if let Some((prev_inline, prev_span)) = *specified_inline {
1124 if do_inline != prev_inline {
1125 let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
1126 spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
1127 spans.push_span_label(
1128 meta.span(),
1129 fluent::passes_doc_inline_conflict_second,
1130 );
1131 self.dcx().emit_err(errors::DocKeywordConflict { spans });
1132 }
1133 } else {
1134 *specified_inline = Some((do_inline, meta.span()));
1135 }
1136 }
1137 _ => {
1138 self.tcx.emit_node_span_lint(
1139 INVALID_DOC_ATTRIBUTES,
1140 hir_id,
1141 meta.span(),
1142 errors::DocInlineOnlyUse {
1143 attr_span: meta.span(),
1144 item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
1145 },
1146 );
1147 }
1148 }
1149 }
1150
1151 fn check_doc_masked(
1152 &self,
1153 style: AttrStyle,
1154 meta: &MetaItemInner,
1155 hir_id: HirId,
1156 target: Target,
1157 ) {
1158 if target != Target::ExternCrate {
1159 self.tcx.emit_node_span_lint(
1160 INVALID_DOC_ATTRIBUTES,
1161 hir_id,
1162 meta.span(),
1163 errors::DocMaskedOnlyExternCrate {
1164 attr_span: meta.span(),
1165 item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
1166 },
1167 );
1168 return;
1169 }
1170
1171 if self.tcx.extern_mod_stmt_cnum(hir_id.owner).is_none() {
1172 self.tcx.emit_node_span_lint(
1173 INVALID_DOC_ATTRIBUTES,
1174 hir_id,
1175 meta.span(),
1176 errors::DocMaskedNotExternCrateSelf {
1177 attr_span: meta.span(),
1178 item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
1179 },
1180 );
1181 }
1182 }
1183
1184 fn check_attr_not_crate_level(
1186 &self,
1187 meta: &MetaItemInner,
1188 hir_id: HirId,
1189 attr_name: &str,
1190 ) -> bool {
1191 if CRATE_HIR_ID == hir_id {
1192 self.dcx().emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
1193 return false;
1194 }
1195 true
1196 }
1197
1198 fn check_attr_crate_level(
1200 &self,
1201 attr: &Attribute,
1202 style: AttrStyle,
1203 meta: &MetaItemInner,
1204 hir_id: HirId,
1205 ) -> bool {
1206 if hir_id != CRATE_HIR_ID {
1207 let bang_span = attr.span().lo() + BytePos(1);
1209 let sugg = (style == AttrStyle::Outer
1210 && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
1211 .then_some(errors::AttrCrateLevelOnlySugg {
1212 attr: attr.span().with_lo(bang_span).with_hi(bang_span),
1213 });
1214 self.tcx.emit_node_span_lint(
1215 INVALID_DOC_ATTRIBUTES,
1216 hir_id,
1217 meta.span(),
1218 errors::AttrCrateLevelOnly { sugg },
1219 );
1220 return false;
1221 }
1222 true
1223 }
1224
1225 fn check_test_attr(
1227 &self,
1228 attr: &Attribute,
1229 style: AttrStyle,
1230 meta: &MetaItemInner,
1231 hir_id: HirId,
1232 ) {
1233 if let Some(metas) = meta.meta_item_list() {
1234 for i_meta in metas {
1235 match (i_meta.name(), i_meta.meta_item()) {
1236 (Some(sym::attr), _) => {
1237 }
1239 (Some(sym::no_crate_inject), _) => {
1240 self.check_attr_crate_level(attr, style, meta, hir_id);
1241 }
1242 (_, Some(m)) => {
1243 self.tcx.emit_node_span_lint(
1244 INVALID_DOC_ATTRIBUTES,
1245 hir_id,
1246 i_meta.span(),
1247 errors::DocTestUnknown {
1248 path: rustc_ast_pretty::pprust::path_to_string(&m.path),
1249 },
1250 );
1251 }
1252 (_, None) => {
1253 self.tcx.emit_node_span_lint(
1254 INVALID_DOC_ATTRIBUTES,
1255 hir_id,
1256 i_meta.span(),
1257 errors::DocTestLiteral,
1258 );
1259 }
1260 }
1261 }
1262 } else {
1263 self.tcx.emit_node_span_lint(
1264 INVALID_DOC_ATTRIBUTES,
1265 hir_id,
1266 meta.span(),
1267 errors::DocTestTakesList,
1268 );
1269 }
1270 }
1271
1272 fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) {
1275 if meta.meta_item_list().is_none() {
1276 self.tcx.emit_node_span_lint(
1277 INVALID_DOC_ATTRIBUTES,
1278 hir_id,
1279 meta.span(),
1280 errors::DocCfgHideTakesList,
1281 );
1282 }
1283 }
1284
1285 fn check_doc_attrs(
1292 &self,
1293 attr: &Attribute,
1294 style: AttrStyle,
1295 hir_id: HirId,
1296 target: Target,
1297 specified_inline: &mut Option<(bool, Span)>,
1298 aliases: &mut FxHashMap<String, Span>,
1299 ) {
1300 if let Some(list) = attr.meta_item_list() {
1301 for meta in &list {
1302 if let Some(i_meta) = meta.meta_item() {
1303 match i_meta.name() {
1304 Some(sym::alias) => {
1305 if self.check_attr_not_crate_level(meta, hir_id, "alias") {
1306 self.check_doc_alias(meta, hir_id, target, aliases);
1307 }
1308 }
1309
1310 Some(sym::keyword) => {
1311 if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
1312 self.check_doc_keyword(meta, hir_id);
1313 }
1314 }
1315
1316 Some(sym::fake_variadic) => {
1317 if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1318 self.check_doc_fake_variadic(meta, hir_id);
1319 }
1320 }
1321
1322 Some(sym::search_unbox) => {
1323 if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1324 self.check_doc_search_unbox(meta, hir_id);
1325 }
1326 }
1327
1328 Some(sym::test) => {
1329 self.check_test_attr(attr, style, meta, hir_id);
1330 }
1331
1332 Some(
1333 sym::html_favicon_url
1334 | sym::html_logo_url
1335 | sym::html_playground_url
1336 | sym::issue_tracker_base_url
1337 | sym::html_root_url
1338 | sym::html_no_source,
1339 ) => {
1340 self.check_attr_crate_level(attr, style, meta, hir_id);
1341 }
1342
1343 Some(sym::cfg_hide) => {
1344 if self.check_attr_crate_level(attr, style, meta, hir_id) {
1345 self.check_doc_cfg_hide(meta, hir_id);
1346 }
1347 }
1348
1349 Some(sym::inline | sym::no_inline) => {
1350 self.check_doc_inline(style, meta, hir_id, target, specified_inline)
1351 }
1352
1353 Some(sym::masked) => self.check_doc_masked(style, meta, hir_id, target),
1354
1355 Some(sym::cfg | sym::hidden | sym::notable_trait) => {}
1356
1357 Some(sym::rust_logo) => {
1358 if self.check_attr_crate_level(attr, style, meta, hir_id)
1359 && !self.tcx.features().rustdoc_internals()
1360 {
1361 feature_err(
1362 &self.tcx.sess,
1363 sym::rustdoc_internals,
1364 meta.span(),
1365 fluent::passes_doc_rust_logo,
1366 )
1367 .emit();
1368 }
1369 }
1370
1371 _ => {
1372 let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
1373 if i_meta.has_name(sym::spotlight) {
1374 self.tcx.emit_node_span_lint(
1375 INVALID_DOC_ATTRIBUTES,
1376 hir_id,
1377 i_meta.span,
1378 errors::DocTestUnknownSpotlight { path, span: i_meta.span },
1379 );
1380 } else if i_meta.has_name(sym::include)
1381 && let Some(value) = i_meta.value_str()
1382 {
1383 let applicability = if list.len() == 1 {
1384 Applicability::MachineApplicable
1385 } else {
1386 Applicability::MaybeIncorrect
1387 };
1388 self.tcx.emit_node_span_lint(
1391 INVALID_DOC_ATTRIBUTES,
1392 hir_id,
1393 i_meta.span,
1394 errors::DocTestUnknownInclude {
1395 path,
1396 value: value.to_string(),
1397 inner: match style {
1398 AttrStyle::Inner => "!",
1399 AttrStyle::Outer => "",
1400 },
1401 sugg: (attr.span(), applicability),
1402 },
1403 );
1404 } else if i_meta.has_name(sym::passes)
1405 || i_meta.has_name(sym::no_default_passes)
1406 {
1407 self.tcx.emit_node_span_lint(
1408 INVALID_DOC_ATTRIBUTES,
1409 hir_id,
1410 i_meta.span,
1411 errors::DocTestUnknownPasses { path, span: i_meta.span },
1412 );
1413 } else if i_meta.has_name(sym::plugins) {
1414 self.tcx.emit_node_span_lint(
1415 INVALID_DOC_ATTRIBUTES,
1416 hir_id,
1417 i_meta.span,
1418 errors::DocTestUnknownPlugins { path, span: i_meta.span },
1419 );
1420 } else {
1421 self.tcx.emit_node_span_lint(
1422 INVALID_DOC_ATTRIBUTES,
1423 hir_id,
1424 i_meta.span,
1425 errors::DocTestUnknownAny { path },
1426 );
1427 }
1428 }
1429 }
1430 } else {
1431 self.tcx.emit_node_span_lint(
1432 INVALID_DOC_ATTRIBUTES,
1433 hir_id,
1434 meta.span(),
1435 errors::DocInvalid,
1436 );
1437 }
1438 }
1439 }
1440 }
1441
1442 fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) {
1444 match target {
1445 Target::Struct | Target::Enum | Target::TyAlias => {}
1446 _ => {
1447 self.dcx().emit_err(errors::PassByValue { attr_span: attr.span(), span });
1448 }
1449 }
1450 }
1451
1452 fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) {
1453 match target {
1454 Target::Method(MethodKind::Inherent) => {}
1455 _ => {
1456 self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span(), span });
1457 }
1458 }
1459 }
1460
1461 fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) {
1462 match target {
1463 Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {}
1464 _ => {
1465 self.tcx
1466 .dcx()
1467 .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span });
1468 }
1469 }
1470 }
1471
1472 fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) {
1473 if target != Target::ForeignFn {
1474 self.dcx().emit_err(errors::FfiPureInvalidTarget { attr_span });
1475 return;
1476 }
1477 if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
1478 self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span });
1480 }
1481 }
1482
1483 fn check_ffi_const(&self, attr_span: Span, target: Target) {
1484 if target != Target::ForeignFn {
1485 self.dcx().emit_err(errors::FfiConstInvalidTarget { attr_span });
1486 }
1487 }
1488
1489 fn check_must_use(&self, hir_id: HirId, attr_span: Span, target: Target) {
1491 if matches!(
1492 target,
1493 Target::Fn
1494 | Target::Enum
1495 | Target::Struct
1496 | Target::Union
1497 | Target::Method(MethodKind::Trait { body: false } | MethodKind::Inherent)
1498 | Target::ForeignFn
1499 | Target::Trait
1503 ) {
1504 return;
1505 }
1506
1507 if let Target::Method(MethodKind::Trait { body: true }) = target
1509 && let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id
1510 && let containing_item = self.tcx.hir_expect_item(parent_def_id)
1511 && let hir::ItemKind::Trait(..) = containing_item.kind
1512 {
1513 return;
1514 }
1515
1516 let article = match target {
1517 Target::ExternCrate
1518 | Target::Enum
1519 | Target::Impl
1520 | Target::Expression
1521 | Target::Arm
1522 | Target::AssocConst
1523 | Target::AssocTy => "an",
1524 _ => "a",
1525 };
1526
1527 self.tcx.emit_node_span_lint(
1528 UNUSED_ATTRIBUTES,
1529 hir_id,
1530 attr_span,
1531 errors::MustUseNoEffect { article, target },
1532 );
1533 }
1534
1535 fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
1537 match target {
1538 Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
1539 _ => {
1540 self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span });
1541 }
1542 }
1543 }
1544
1545 fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) {
1547 if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id)
1548 && matches!(
1549 param.kind,
1550 hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }
1551 )
1552 && matches!(param.source, hir::GenericParamSource::Generics)
1553 && let parent_hir_id = self.tcx.parent_hir_id(hir_id)
1554 && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
1555 && let hir::ItemKind::Impl(impl_) = item.kind
1556 && let Some(trait_) = impl_.of_trait
1557 && let Some(def_id) = trait_.trait_def_id()
1558 && self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
1559 {
1560 return;
1561 }
1562
1563 self.dcx().emit_err(errors::InvalidMayDangle { attr_span });
1564 }
1565
1566 fn check_cold(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
1568 match target {
1569 Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
1570 Target::Field | Target::Arm | Target::MacroDef => {
1575 self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "cold");
1576 }
1577 _ => {
1578 self.tcx.emit_node_span_lint(
1581 UNUSED_ATTRIBUTES,
1582 hir_id,
1583 attr_span,
1584 errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID },
1585 );
1586 }
1587 }
1588 }
1589
1590 fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1592 if target == Target::ForeignMod
1593 && let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
1594 && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
1595 && !matches!(abi, ExternAbi::Rust)
1596 {
1597 return;
1598 }
1599
1600 self.tcx.emit_node_span_lint(
1601 UNUSED_ATTRIBUTES,
1602 hir_id,
1603 attr.span(),
1604 errors::Link { span: (target != Target::ForeignMod).then_some(span) },
1605 );
1606 }
1607
1608 fn check_link_name(
1610 &self,
1611 hir_id: HirId,
1612 attr_span: Span,
1613 name: Symbol,
1614 span: Span,
1615 target: Target,
1616 ) {
1617 match target {
1618 Target::ForeignFn | Target::ForeignStatic => {}
1619 Target::Field | Target::Arm | Target::MacroDef => {
1624 self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_name");
1625 }
1626 _ => {
1627 let help_span = matches!(target, Target::ForeignMod).then_some(attr_span);
1630 self.tcx.emit_node_span_lint(
1631 UNUSED_ATTRIBUTES,
1632 hir_id,
1633 attr_span,
1634 errors::LinkName { span, help_span, value: name.as_str() },
1635 );
1636 }
1637 }
1638 }
1639
1640 fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1642 match target {
1643 Target::ExternCrate => {}
1644 Target::Field | Target::Arm | Target::MacroDef => {
1649 self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link");
1650 }
1651 _ => {
1652 self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span });
1653 }
1654 }
1655 }
1656
1657 fn is_impl_item(&self, hir_id: HirId) -> bool {
1658 matches!(self.tcx.hir_node(hir_id), hir::Node::ImplItem(..))
1659 }
1660
1661 fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
1663 match target {
1664 Target::Static | Target::Fn => {}
1665 Target::Method(..) if self.is_impl_item(hir_id) => {}
1666 Target::Field | Target::Arm | Target::MacroDef => {
1671 self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name");
1672 }
1673 _ => {
1674 self.dcx().emit_err(errors::ExportName { attr_span, span });
1675 }
1676 }
1677 }
1678
1679 fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) {
1680 if target != Target::Struct {
1681 self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
1682 attr_span: attr.span(),
1683 span,
1684 });
1685 return;
1686 }
1687
1688 let Some(list) = attr.meta_item_list() else {
1689 return;
1690 };
1691
1692 if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
1693 self.tcx
1694 .dcx()
1695 .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() });
1696 }
1697 }
1698
1699 fn check_rustc_legacy_const_generics(
1701 &self,
1702 hir_id: HirId,
1703 attr: &Attribute,
1704 span: Span,
1705 target: Target,
1706 item: Option<ItemLike<'_>>,
1707 ) {
1708 let is_function = matches!(target, Target::Fn);
1709 if !is_function {
1710 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
1711 attr_span: attr.span(),
1712 defn_span: span,
1713 on_crate: hir_id == CRATE_HIR_ID,
1714 });
1715 return;
1716 }
1717
1718 let Some(list) = attr.meta_item_list() else {
1719 return;
1721 };
1722
1723 let Some(ItemLike::Item(Item {
1724 kind: ItemKind::Fn { sig: FnSig { decl, .. }, generics, .. },
1725 ..
1726 })) = item
1727 else {
1728 bug!("should be a function item");
1729 };
1730
1731 for param in generics.params {
1732 match param.kind {
1733 hir::GenericParamKind::Const { .. } => {}
1734 _ => {
1735 self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly {
1736 attr_span: attr.span(),
1737 param_span: param.span,
1738 });
1739 return;
1740 }
1741 }
1742 }
1743
1744 if list.len() != generics.params.len() {
1745 self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex {
1746 attr_span: attr.span(),
1747 generics_span: generics.span,
1748 });
1749 return;
1750 }
1751
1752 let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
1753 let mut invalid_args = vec![];
1754 for meta in list {
1755 if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) {
1756 if *val >= arg_count {
1757 let span = meta.span();
1758 self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed {
1759 span,
1760 arg_count: arg_count as usize,
1761 });
1762 return;
1763 }
1764 } else {
1765 invalid_args.push(meta.span());
1766 }
1767 }
1768
1769 if !invalid_args.is_empty() {
1770 self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
1771 }
1772 }
1773
1774 fn check_applied_to_fn_or_method(
1777 &self,
1778 hir_id: HirId,
1779 attr_span: Span,
1780 defn_span: Span,
1781 target: Target,
1782 ) {
1783 let is_function = matches!(target, Target::Fn | Target::Method(..));
1784 if !is_function {
1785 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
1786 attr_span,
1787 defn_span,
1788 on_crate: hir_id == CRATE_HIR_ID,
1789 });
1790 }
1791 }
1792
1793 fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
1795 match target {
1796 Target::Struct => {}
1797 _ => {
1798 self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span(), span });
1799 }
1800 }
1801 }
1802
1803 fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) {
1805 match target {
1806 Target::Field => {}
1807 _ => {
1808 self.tcx
1809 .dcx()
1810 .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span });
1811 }
1812 }
1813 }
1814
1815 fn check_rustc_dirty_clean(&self, attr: &Attribute) {
1818 if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
1819 self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span() });
1820 }
1821 }
1822
1823 fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) {
1825 match target {
1826 Target::Trait => {}
1827 _ => {
1828 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span });
1829 }
1830 }
1831 }
1832
1833 fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1835 match target {
1836 Target::Static | Target::Fn | Target::Method(..) => {}
1837 Target::Field | Target::Arm | Target::MacroDef => {
1842 self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section");
1843 }
1844 _ => {
1845 self.tcx.emit_node_span_lint(
1848 UNUSED_ATTRIBUTES,
1849 hir_id,
1850 attr.span(),
1851 errors::LinkSection { span },
1852 );
1853 }
1854 }
1855 }
1856
1857 fn check_no_mangle(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
1859 match target {
1860 Target::Static | Target::Fn => {}
1861 Target::Method(..) if self.is_impl_item(hir_id) => {}
1862 Target::Field | Target::Arm | Target::MacroDef => {
1867 self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "no_mangle");
1868 }
1869 Target::ForeignFn | Target::ForeignStatic => {
1873 let foreign_item_kind = match target {
1874 Target::ForeignFn => "function",
1875 Target::ForeignStatic => "static",
1876 _ => unreachable!(),
1877 };
1878 self.tcx.emit_node_span_lint(
1879 UNUSED_ATTRIBUTES,
1880 hir_id,
1881 attr_span,
1882 errors::NoMangleForeign { span, attr_span, foreign_item_kind },
1883 );
1884 }
1885 _ => {
1886 self.tcx.emit_node_span_lint(
1889 UNUSED_ATTRIBUTES,
1890 hir_id,
1891 attr_span,
1892 errors::NoMangle { span },
1893 );
1894 }
1895 }
1896 }
1897
1898 fn check_align(&self, span: Span, target: Target, align: Align, repr_span: Span) {
1900 match target {
1901 Target::Fn | Target::Method(_) => {}
1902 Target::Struct | Target::Union | Target::Enum => {
1903 self.dcx().emit_err(errors::AlignShouldBeReprAlign {
1904 span: repr_span,
1905 item: target.name(),
1906 align_bytes: align.bytes(),
1907 });
1908 }
1909 _ => {
1910 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1911 hint_span: repr_span,
1912 span,
1913 });
1914 }
1915 }
1916
1917 self.check_align_value(align, repr_span);
1918 }
1919
1920 fn check_repr(
1922 &self,
1923 attrs: &[Attribute],
1924 span: Span,
1925 target: Target,
1926 item: Option<ItemLike<'_>>,
1927 hir_id: HirId,
1928 ) {
1929 let reprs = find_attr!(attrs, AttributeKind::Repr(r) => r.as_slice()).unwrap_or(&[]);
1935
1936 let mut int_reprs = 0;
1937 let mut is_explicit_rust = false;
1938 let mut is_c = false;
1939 let mut is_simd = false;
1940 let mut is_transparent = false;
1941
1942 for (repr, repr_span) in reprs {
1943 match repr {
1944 ReprAttr::ReprRust => {
1945 is_explicit_rust = true;
1946 match target {
1947 Target::Struct | Target::Union | Target::Enum => continue,
1948 _ => {
1949 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1950 hint_span: *repr_span,
1951 span,
1952 });
1953 }
1954 }
1955 }
1956 ReprAttr::ReprC => {
1957 is_c = true;
1958 match target {
1959 Target::Struct | Target::Union | Target::Enum => continue,
1960 _ => {
1961 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1962 hint_span: *repr_span,
1963 span,
1964 });
1965 }
1966 }
1967 }
1968 ReprAttr::ReprAlign(align) => {
1969 match target {
1970 Target::Struct | Target::Union | Target::Enum => {}
1971 Target::Fn | Target::Method(_) => {
1972 self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
1973 span: *repr_span,
1974 item: target.name(),
1975 });
1976 }
1977 _ => {
1978 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1979 hint_span: *repr_span,
1980 span,
1981 });
1982 }
1983 }
1984
1985 self.check_align_value(*align, *repr_span);
1986 }
1987 ReprAttr::ReprPacked(_) => {
1988 if target != Target::Struct && target != Target::Union {
1989 self.dcx().emit_err(errors::AttrApplication::StructUnion {
1990 hint_span: *repr_span,
1991 span,
1992 });
1993 } else {
1994 continue;
1995 }
1996 }
1997 ReprAttr::ReprSimd => {
1998 is_simd = true;
1999 if target != Target::Struct {
2000 self.dcx().emit_err(errors::AttrApplication::Struct {
2001 hint_span: *repr_span,
2002 span,
2003 });
2004 } else {
2005 continue;
2006 }
2007 }
2008 ReprAttr::ReprTransparent => {
2009 is_transparent = true;
2010 match target {
2011 Target::Struct | Target::Union | Target::Enum => continue,
2012 _ => {
2013 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
2014 hint_span: *repr_span,
2015 span,
2016 });
2017 }
2018 }
2019 }
2020 ReprAttr::ReprInt(_) => {
2021 int_reprs += 1;
2022 if target != Target::Enum {
2023 self.dcx().emit_err(errors::AttrApplication::Enum {
2024 hint_span: *repr_span,
2025 span,
2026 });
2027 } else {
2028 continue;
2029 }
2030 }
2031 ReprAttr::ReprEmpty => {
2034 if item.is_some() {
2036 match target {
2037 Target::Struct | Target::Union | Target::Enum => continue,
2038 Target::Fn | Target::Method(_) => {
2039 self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
2040 span: *repr_span,
2041 item: target.name(),
2042 });
2043 }
2044 _ => {
2045 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
2046 hint_span: *repr_span,
2047 span,
2048 });
2049 }
2050 }
2051 }
2052
2053 return;
2054 }
2055 };
2056 }
2057
2058 let hint_spans = reprs.iter().map(|(_, span)| *span);
2061
2062 if is_transparent && reprs.len() > 1 {
2064 let hint_spans = hint_spans.clone().collect();
2065 self.dcx().emit_err(errors::TransparentIncompatible {
2066 hint_spans,
2067 target: target.to_string(),
2068 });
2069 }
2070 if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
2071 let hint_spans = hint_spans.clone().collect();
2072 self.dcx().emit_err(errors::ReprConflicting { hint_spans });
2073 }
2074 if (int_reprs > 1)
2076 || (is_simd && is_c)
2077 || (int_reprs == 1
2078 && is_c
2079 && item.is_some_and(|item| {
2080 if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false }
2081 }))
2082 {
2083 self.tcx.emit_node_span_lint(
2084 CONFLICTING_REPR_HINTS,
2085 hir_id,
2086 hint_spans.collect::<Vec<Span>>(),
2087 errors::ReprConflictingLint,
2088 );
2089 }
2090 }
2091
2092 fn check_align_value(&self, align: Align, span: Span) {
2093 if align.bytes() > 2_u64.pow(29) {
2094 self.dcx().span_delayed_bug(
2096 span,
2097 "alignment greater than 2^29 should be errored on elsewhere",
2098 );
2099 } else {
2100 let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
2105 if align.bytes() > max {
2106 self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max });
2107 }
2108 }
2109 }
2110
2111 fn check_used(&self, attr_span: Span, target: Target, target_span: Span) {
2112 if target != Target::Static {
2113 self.dcx().emit_err(errors::UsedStatic {
2114 attr_span,
2115 span: target_span,
2116 target: target.name(),
2117 });
2118 }
2119 }
2120
2121 fn check_allow_internal_unstable(
2125 &self,
2126 hir_id: HirId,
2127 attr_span: Span,
2128 span: Span,
2129 target: Target,
2130 attrs: &[Attribute],
2131 ) {
2132 match target {
2133 Target::Fn => {
2134 for attr in attrs {
2135 if attr.is_proc_macro_attr() {
2136 return;
2138 }
2139 }
2140 }
2142 Target::MacroDef => return,
2144 Target::Field | Target::Arm => {
2149 self.inline_attr_str_error_without_macro_def(
2150 hir_id,
2151 attr_span,
2152 "allow_internal_unstable",
2153 );
2154 return;
2155 }
2156 _ => {}
2158 }
2159
2160 self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span });
2161 }
2162
2163 fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
2165 match target {
2170 Target::Mod => {}
2171 _ => {
2172 self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
2173 }
2174 }
2175 }
2176
2177 fn check_rustc_allow_const_fn_unstable(
2180 &self,
2181 hir_id: HirId,
2182 attr: &Attribute,
2183 span: Span,
2184 target: Target,
2185 ) {
2186 match target {
2187 Target::Fn | Target::Method(_)
2188 if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {}
2189 Target::Field | Target::Arm | Target::MacroDef => self
2194 .inline_attr_str_error_with_macro_def(
2195 hir_id,
2196 attr.span(),
2197 "allow_internal_unstable",
2198 ),
2199 _ => {
2200 self.tcx
2201 .dcx()
2202 .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span });
2203 }
2204 }
2205 }
2206
2207 fn check_rustc_std_internal_symbol(&self, attr: &Attribute, span: Span, target: Target) {
2208 match target {
2209 Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {}
2210 _ => {
2211 self.tcx
2212 .dcx()
2213 .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span(), span });
2214 }
2215 }
2216 }
2217
2218 fn check_stability_promotable(&self, span: Span, target: Target) {
2219 match target {
2220 Target::Expression => {
2221 self.dcx().emit_err(errors::StabilityPromotable { attr_span: span });
2222 }
2223 _ => {}
2224 }
2225 }
2226
2227 fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) {
2228 match target {
2229 Target::ForeignFn | Target::ForeignStatic => {}
2230 _ => {
2231 self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span() });
2232 }
2233 }
2234 }
2235
2236 fn check_confusables(&self, span: Span, target: Target) {
2237 if !matches!(target, Target::Method(MethodKind::Inherent)) {
2238 self.dcx().emit_err(errors::Confusables { attr_span: span });
2239 }
2240 }
2241
2242 fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
2243 match target {
2244 Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
2245 self.tcx.emit_node_span_lint(
2246 UNUSED_ATTRIBUTES,
2247 hir_id,
2248 attr.span(),
2249 errors::Deprecated,
2250 );
2251 }
2252 _ => {}
2253 }
2254 }
2255
2256 fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2257 let Some(name) = attr.name() else {
2258 return;
2259 };
2260 match target {
2261 Target::ExternCrate | Target::Mod => {}
2262 _ => {
2263 self.tcx.emit_node_span_lint(
2264 UNUSED_ATTRIBUTES,
2265 hir_id,
2266 attr.span(),
2267 errors::MacroUse { name },
2268 );
2269 }
2270 }
2271 }
2272
2273 fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2274 if target != Target::MacroDef {
2275 self.tcx.emit_node_span_lint(
2276 UNUSED_ATTRIBUTES,
2277 hir_id,
2278 attr.span(),
2279 errors::MacroExport::Normal,
2280 );
2281 } else if let Some(meta_item_list) = attr.meta_item_list()
2282 && !meta_item_list.is_empty()
2283 {
2284 if meta_item_list.len() > 1 {
2285 self.tcx.emit_node_span_lint(
2286 INVALID_MACRO_EXPORT_ARGUMENTS,
2287 hir_id,
2288 attr.span(),
2289 errors::MacroExport::TooManyItems,
2290 );
2291 } else if !meta_item_list[0].has_name(sym::local_inner_macros) {
2292 self.tcx.emit_node_span_lint(
2293 INVALID_MACRO_EXPORT_ARGUMENTS,
2294 hir_id,
2295 meta_item_list[0].span(),
2296 errors::MacroExport::InvalidArgument,
2297 );
2298 }
2299 } else {
2300 let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
2302 let is_decl_macro = !macro_definition.macro_rules;
2303
2304 if is_decl_macro {
2305 self.tcx.emit_node_span_lint(
2306 UNUSED_ATTRIBUTES,
2307 hir_id,
2308 attr.span(),
2309 errors::MacroExport::OnDeclMacro,
2310 );
2311 }
2312 }
2313 }
2314
2315 fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
2316 if let Attribute::Parsed(p) = attr {
2319 match p {
2320 AttributeKind::Repr(reprs) => {
2321 for (r, span) in reprs {
2322 if let ReprAttr::ReprEmpty = r {
2323 self.tcx.emit_node_span_lint(
2324 UNUSED_ATTRIBUTES,
2325 hir_id,
2326 *span,
2327 errors::Unused {
2328 attr_span: *span,
2329 note: errors::UnusedNote::EmptyList { name: sym::repr },
2330 },
2331 );
2332 }
2333 }
2334 return;
2335 }
2336 _ => {}
2337 }
2338 }
2339
2340 let note = if attr.has_any_name(&[
2342 sym::macro_use,
2343 sym::allow,
2344 sym::expect,
2345 sym::warn,
2346 sym::deny,
2347 sym::forbid,
2348 sym::feature,
2349 sym::target_feature,
2350 ]) && attr.meta_item_list().is_some_and(|list| list.is_empty())
2351 {
2352 errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
2353 } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
2354 && let Some(meta) = attr.meta_item_list()
2355 && let [meta] = meta.as_slice()
2356 && let Some(item) = meta.meta_item()
2357 && let MetaItemKind::NameValue(_) = &item.kind
2358 && item.path == sym::reason
2359 {
2360 errors::UnusedNote::NoLints { name: attr.name().unwrap() }
2361 } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
2362 && let Some(meta) = attr.meta_item_list()
2363 && meta.iter().any(|meta| {
2364 meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
2365 })
2366 {
2367 if hir_id != CRATE_HIR_ID {
2368 match style {
2369 Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint(
2370 UNUSED_ATTRIBUTES,
2371 hir_id,
2372 attr.span(),
2373 errors::OuterCrateLevelAttr,
2374 ),
2375 Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
2376 UNUSED_ATTRIBUTES,
2377 hir_id,
2378 attr.span(),
2379 errors::InnerCrateLevelAttr,
2380 ),
2381 };
2382 return;
2383 } else {
2384 let never_needs_link = self
2385 .tcx
2386 .crate_types()
2387 .iter()
2388 .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib));
2389 if never_needs_link {
2390 errors::UnusedNote::LinkerMessagesBinaryCrateOnly
2391 } else {
2392 return;
2393 }
2394 }
2395 } else if attr.has_name(sym::default_method_body_is_const) {
2396 errors::UnusedNote::DefaultMethodBodyConst
2397 } else {
2398 return;
2399 };
2400
2401 self.tcx.emit_node_span_lint(
2402 UNUSED_ATTRIBUTES,
2403 hir_id,
2404 attr.span(),
2405 errors::Unused { attr_span: attr.span(), note },
2406 );
2407 }
2408
2409 fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
2413 if target != Target::Fn {
2414 return;
2415 }
2416
2417 let tcx = self.tcx;
2418 let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else {
2419 return;
2420 };
2421 let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else {
2422 return;
2423 };
2424
2425 let def_id = hir_id.expect_owner().def_id;
2426 let param_env = ty::ParamEnv::empty();
2427
2428 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
2429 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
2430
2431 let span = tcx.def_span(def_id);
2432 let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id());
2433 let sig = tcx.liberate_late_bound_regions(
2434 def_id.to_def_id(),
2435 tcx.fn_sig(def_id).instantiate(tcx, fresh_args),
2436 );
2437
2438 let mut cause = ObligationCause::misc(span, def_id);
2439 let sig = ocx.normalize(&cause, param_env, sig);
2440
2441 let errors = ocx.select_where_possible();
2443 if !errors.is_empty() {
2444 return;
2445 }
2446
2447 let expected_sig = tcx.mk_fn_sig(
2448 std::iter::repeat(token_stream).take(match kind {
2449 ProcMacroKind::Attribute => 2,
2450 ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
2451 }),
2452 token_stream,
2453 false,
2454 Safety::Safe,
2455 ExternAbi::Rust,
2456 );
2457
2458 if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
2459 let mut diag = tcx.dcx().create_err(errors::ProcMacroBadSig { span, kind });
2460
2461 let hir_sig = tcx.hir_fn_sig_by_hir_id(hir_id);
2462 if let Some(hir_sig) = hir_sig {
2463 #[allow(rustc::diagnostic_outside_of_impl)] match terr {
2465 TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
2466 if let Some(ty) = hir_sig.decl.inputs.get(idx) {
2467 diag.span(ty.span);
2468 cause.span = ty.span;
2469 } else if idx == hir_sig.decl.inputs.len() {
2470 let span = hir_sig.decl.output.span();
2471 diag.span(span);
2472 cause.span = span;
2473 }
2474 }
2475 TypeError::ArgCount => {
2476 if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
2477 diag.span(ty.span);
2478 cause.span = ty.span;
2479 }
2480 }
2481 TypeError::SafetyMismatch(_) => {
2482 }
2484 TypeError::AbiMismatch(_) => {
2485 }
2487 TypeError::VariadicMismatch(_) => {
2488 }
2490 _ => {}
2491 }
2492 }
2493
2494 infcx.err_ctxt().note_type_err(
2495 &mut diag,
2496 &cause,
2497 None,
2498 Some(param_env.and(ValuePairs::PolySigs(ExpectedFound {
2499 expected: ty::Binder::dummy(expected_sig),
2500 found: ty::Binder::dummy(sig),
2501 }))),
2502 terr,
2503 false,
2504 None,
2505 );
2506 diag.emit();
2507 self.abort.set(true);
2508 }
2509
2510 let errors = ocx.select_all_or_error();
2511 if !errors.is_empty() {
2512 infcx.err_ctxt().report_fulfillment_errors(errors);
2513 self.abort.set(true);
2514 }
2515 }
2516
2517 fn check_coroutine(&self, attr: &Attribute, target: Target) {
2518 match target {
2519 Target::Closure => return,
2520 _ => {
2521 self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() });
2522 }
2523 }
2524 }
2525
2526 fn check_type_const(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2527 let tcx = self.tcx;
2528 if target == Target::AssocConst
2529 && let parent = tcx.parent(hir_id.expect_owner().to_def_id())
2530 && self.tcx.def_kind(parent) == DefKind::Trait
2531 {
2532 return;
2533 } else {
2534 self.dcx()
2535 .struct_span_err(
2536 attr.span(),
2537 "`#[type_const]` must only be applied to trait associated constants",
2538 )
2539 .emit();
2540 }
2541 }
2542
2543 fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) {
2544 match target {
2545 Target::Fn
2546 | Target::Method(..)
2547 | Target::Static
2548 | Target::ForeignStatic
2549 | Target::ForeignFn => {}
2550 _ => {
2551 self.dcx().emit_err(errors::Linkage { attr_span: attr.span(), span });
2552 }
2553 }
2554 }
2555
2556 fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) {
2557 if !find_attr!(attrs, AttributeKind::Repr(r) => r.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent))
2558 .unwrap_or(false)
2559 {
2560 self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span });
2561 }
2562 }
2563
2564 fn check_rustc_force_inline(
2565 &self,
2566 hir_id: HirId,
2567 attrs: &[Attribute],
2568 span: Span,
2569 target: Target,
2570 ) {
2571 match (
2572 target,
2573 find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span),
2574 ) {
2575 (Target::Closure, None) => {
2576 let is_coro = matches!(
2577 self.tcx.hir_expect_expr(hir_id).kind,
2578 hir::ExprKind::Closure(hir::Closure {
2579 kind: hir::ClosureKind::Coroutine(..)
2580 | hir::ClosureKind::CoroutineClosure(..),
2581 ..
2582 })
2583 );
2584 let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id();
2585 let parent_span = self.tcx.def_span(parent_did);
2586
2587 if let Some(attr_span) = find_attr!(
2588 self.tcx.get_all_attrs(parent_did),
2589 AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span
2590 ) && is_coro
2591 {
2592 self.dcx()
2593 .emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span });
2594 }
2595 }
2596 (Target::Fn, _) => (),
2597 (_, Some(attr_span)) => {
2598 self.dcx().emit_err(errors::RustcForceInline { attr_span, span });
2599 }
2600 (_, None) => (),
2601 }
2602 }
2603
2604 fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) {
2605 if let Some(export_name_span) = find_attr!(attrs, AttributeKind::ExportName { span: export_name_span, .. } => *export_name_span)
2606 && let Some(no_mangle_span) =
2607 find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
2608 {
2609 let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 {
2610 "#[unsafe(no_mangle)]"
2611 } else {
2612 "#[no_mangle]"
2613 };
2614 let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 {
2615 "#[unsafe(export_name)]"
2616 } else {
2617 "#[export_name]"
2618 };
2619
2620 self.tcx.emit_node_span_lint(
2621 lint::builtin::UNUSED_ATTRIBUTES,
2622 hir_id,
2623 no_mangle_span,
2624 errors::MixedExportNameAndNoMangle {
2625 no_mangle_span,
2626 export_name_span,
2627 no_mangle_attr,
2628 export_name_attr,
2629 },
2630 );
2631 }
2632 }
2633
2634 fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) {
2636 debug!("check_autodiff");
2637 match target {
2638 Target::Fn => {}
2639 _ => {
2640 self.dcx().emit_err(errors::AutoDiffAttr { attr_span: span });
2641 self.abort.set(true);
2642 }
2643 }
2644 }
2645
2646 fn check_loop_match(&self, hir_id: HirId, attr_span: Span, target: Target) {
2647 let node_span = self.tcx.hir_span(hir_id);
2648
2649 if !matches!(target, Target::Expression) {
2650 self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span });
2651 return;
2652 }
2653
2654 if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Loop(..)) {
2655 self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span });
2656 };
2657 }
2658
2659 fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) {
2660 let node_span = self.tcx.hir_span(hir_id);
2661
2662 if !matches!(target, Target::Expression) {
2663 self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
2664 return;
2665 }
2666
2667 if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Break(..)) {
2668 self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
2669 };
2670 }
2671}
2672
2673impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
2674 type NestedFilter = nested_filter::OnlyBodies;
2675
2676 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
2677 self.tcx
2678 }
2679
2680 fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
2681 if let ItemKind::Macro(_, macro_def, _) = item.kind {
2685 let def_id = item.owner_id.to_def_id();
2686 if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
2687 check_non_exported_macro_for_invalid_attrs(self.tcx, item);
2688 }
2689 }
2690
2691 let target = Target::from_item(item);
2692 self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
2693 intravisit::walk_item(self, item)
2694 }
2695
2696 fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<'tcx>) {
2697 const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace];
2702 let spans = self
2703 .tcx
2704 .hir_attrs(where_predicate.hir_id)
2705 .iter()
2706 .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym)))
2707 .map(|attr| attr.span())
2708 .collect::<Vec<_>>();
2709 if !spans.is_empty() {
2710 self.tcx.dcx().emit_err(errors::UnsupportedAttributesInWhere { span: spans.into() });
2711 }
2712 self.check_attributes(
2713 where_predicate.hir_id,
2714 where_predicate.span,
2715 Target::WherePredicate,
2716 None,
2717 );
2718 intravisit::walk_where_predicate(self, where_predicate)
2719 }
2720
2721 fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
2722 let target = Target::from_generic_param(generic_param);
2723 self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
2724 intravisit::walk_generic_param(self, generic_param)
2725 }
2726
2727 fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
2728 let target = Target::from_trait_item(trait_item);
2729 self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
2730 intravisit::walk_trait_item(self, trait_item)
2731 }
2732
2733 fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
2734 self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
2735 intravisit::walk_field_def(self, struct_field);
2736 }
2737
2738 fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
2739 self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
2740 intravisit::walk_arm(self, arm);
2741 }
2742
2743 fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
2744 let target = Target::from_foreign_item(f_item);
2745 self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
2746 intravisit::walk_foreign_item(self, f_item)
2747 }
2748
2749 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
2750 let target = target_from_impl_item(self.tcx, impl_item);
2751 self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
2752 intravisit::walk_impl_item(self, impl_item)
2753 }
2754
2755 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
2756 if let hir::StmtKind::Let(l) = stmt.kind {
2758 self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
2759 }
2760 intravisit::walk_stmt(self, stmt)
2761 }
2762
2763 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
2764 let target = match expr.kind {
2765 hir::ExprKind::Closure { .. } => Target::Closure,
2766 _ => Target::Expression,
2767 };
2768
2769 self.check_attributes(expr.hir_id, expr.span, target, None);
2770 intravisit::walk_expr(self, expr)
2771 }
2772
2773 fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
2774 self.check_attributes(field.hir_id, field.span, Target::ExprField, None);
2775 intravisit::walk_expr_field(self, field)
2776 }
2777
2778 fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
2779 self.check_attributes(variant.hir_id, variant.span, Target::Variant, None);
2780 intravisit::walk_variant(self, variant)
2781 }
2782
2783 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
2784 self.check_attributes(param.hir_id, param.span, Target::Param, None);
2785
2786 intravisit::walk_param(self, param);
2787 }
2788
2789 fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
2790 self.check_attributes(field.hir_id, field.span, Target::PatField, None);
2791 intravisit::walk_pat_field(self, field);
2792 }
2793}
2794
2795fn is_c_like_enum(item: &Item<'_>) -> bool {
2796 if let ItemKind::Enum(_, _, ref def) = item.kind {
2797 for variant in def.variants {
2798 match variant.data {
2799 hir::VariantData::Unit(..) => { }
2800 _ => return false,
2801 }
2802 }
2803 true
2804 } else {
2805 false
2806 }
2807}
2808
2809fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
2812 const ATTRS_TO_CHECK: &[Symbol] = &[
2816 sym::macro_export,
2817 sym::path,
2818 sym::automatically_derived,
2819 sym::rustc_main,
2820 sym::derive,
2821 sym::test,
2822 sym::test_case,
2823 sym::global_allocator,
2824 sym::bench,
2825 ];
2826
2827 for attr in attrs {
2828 let (span, name) = if let Some(a) =
2830 ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check))
2831 {
2832 (attr.span(), *a)
2833 } else if let Attribute::Parsed(AttributeKind::Repr(r)) = attr {
2834 (r.first().unwrap().1, sym::repr)
2835 } else {
2836 continue;
2837 };
2838
2839 let item = tcx
2840 .hir_free_items()
2841 .map(|id| tcx.hir_item(id))
2842 .find(|item| !item.span.is_dummy()) .map(|item| errors::ItemFollowingInnerAttr {
2844 span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span },
2845 kind: item.kind.descr(),
2846 });
2847 let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {
2848 span,
2849 sugg_span: tcx
2850 .sess
2851 .source_map()
2852 .span_to_snippet(span)
2853 .ok()
2854 .filter(|src| src.starts_with("#!["))
2855 .map(|_| span.with_lo(span.lo() + BytePos(1)).with_hi(span.lo() + BytePos(2))),
2856 name,
2857 item,
2858 });
2859
2860 if let Attribute::Unparsed(p) = attr {
2861 tcx.dcx().try_steal_replace_and_emit_err(
2862 p.path.span,
2863 StashKey::UndeterminedMacroResolution,
2864 err,
2865 );
2866 } else {
2867 err.emit();
2868 }
2869 }
2870}
2871
2872fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
2873 let attrs = tcx.hir_attrs(item.hir_id());
2874
2875 if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span)
2876 {
2877 tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span });
2878 }
2879}
2880
2881fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
2882 let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
2883 tcx.hir_visit_item_likes_in_module(module_def_id, check_attr_visitor);
2884 if module_def_id.to_local_def_id().is_top_level_module() {
2885 check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
2886 check_invalid_crate_level_attr(tcx, tcx.hir_krate_attrs());
2887 }
2888 if check_attr_visitor.abort.get() {
2889 tcx.dcx().abort_if_errors()
2890 }
2891}
2892
2893pub(crate) fn provide(providers: &mut Providers) {
2894 *providers = Providers { check_mod_attrs, ..*providers };
2895}
2896
2897fn check_duplicates(
2899 tcx: TyCtxt<'_>,
2900 attr: &Attribute,
2901 hir_id: HirId,
2902 duplicates: AttributeDuplicates,
2903 seen: &mut FxHashMap<Symbol, Span>,
2904) {
2905 use AttributeDuplicates::*;
2906 if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
2907 return;
2908 }
2909 let attr_name = attr.name().unwrap();
2910 match duplicates {
2911 DuplicatesOk => {}
2912 WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
2913 match seen.entry(attr_name) {
2914 Entry::Occupied(mut entry) => {
2915 let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
2916 let to_remove = entry.insert(attr.span());
2917 (to_remove, attr.span())
2918 } else {
2919 (attr.span(), *entry.get())
2920 };
2921 tcx.emit_node_span_lint(
2922 UNUSED_ATTRIBUTES,
2923 hir_id,
2924 this,
2925 errors::UnusedDuplicate {
2926 this,
2927 other,
2928 warning: matches!(
2929 duplicates,
2930 FutureWarnFollowing | FutureWarnPreceding
2931 ),
2932 },
2933 );
2934 }
2935 Entry::Vacant(entry) => {
2936 entry.insert(attr.span());
2937 }
2938 }
2939 }
2940 ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
2941 Entry::Occupied(mut entry) => {
2942 let (this, other) = if matches!(duplicates, ErrorPreceding) {
2943 let to_remove = entry.insert(attr.span());
2944 (to_remove, attr.span())
2945 } else {
2946 (attr.span(), *entry.get())
2947 };
2948 tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
2949 }
2950 Entry::Vacant(entry) => {
2951 entry.insert(attr.span());
2952 }
2953 },
2954 }
2955}
2956
2957fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
2958 matches!(&self_ty.kind, hir::TyKind::Tup([_]))
2959 || if let hir::TyKind::BareFn(bare_fn_ty) = &self_ty.kind {
2960 bare_fn_ty.decl.inputs.len() == 1
2961 } else {
2962 false
2963 }
2964 || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind
2965 && let Some(&[hir::GenericArg::Type(ty)]) =
2966 path.segments.last().map(|last| last.args().args)
2967 {
2968 doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
2969 } else {
2970 false
2971 })
2972}