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