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