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