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