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