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