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