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, MetaItem, MetaItemInner, MetaItemKind, ast};
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, MirDialect, MirPhase, ReprAttr, SanitizerSet};
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, Constness, FnSig, ForeignItem, HirId,
27 Item, 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, MALFORMED_DIAGNOSTIC_ATTRIBUTES,
42 MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
43};
44use rustc_session::parse::feature_err;
45use rustc_span::edition::Edition;
46use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym};
47use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
48use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
49use rustc_trait_selection::traits::ObligationCtxt;
50use tracing::debug;
51
52use crate::{errors, fluent_generated as fluent};
53
54#[derive(LintDiagnostic)]
55#[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
56struct DiagnosticOnUnimplementedOnlyForTraits;
57
58#[derive(LintDiagnostic)]
59#[diag(passes_diagnostic_diagnostic_on_const_only_for_trait_impls)]
60struct DiagnosticOnConstOnlyForTraitImpls {
61 #[label]
62 item_span: Span,
63}
64
65fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
66 match impl_item.kind {
67 hir::ImplItemKind::Const(..) => Target::AssocConst,
68 hir::ImplItemKind::Fn(..) => {
69 let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
70 let containing_item = tcx.hir_expect_item(parent_def_id);
71 let containing_impl_is_for_trait = match &containing_item.kind {
72 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
73 _ => bug!("parent of an ImplItem must be an Impl"),
74 };
75 if containing_impl_is_for_trait {
76 Target::Method(MethodKind::Trait { body: true })
77 } else {
78 Target::Method(MethodKind::Inherent)
79 }
80 }
81 hir::ImplItemKind::Type(..) => Target::AssocTy,
82 }
83}
84
85#[derive(Clone, Copy)]
86enum ItemLike<'tcx> {
87 Item(&'tcx Item<'tcx>),
88 ForeignItem,
89}
90
91#[derive(Copy, Clone)]
92pub(crate) enum ProcMacroKind {
93 FunctionLike,
94 Derive,
95 Attribute,
96}
97
98impl IntoDiagArg for ProcMacroKind {
99 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
100 match self {
101 ProcMacroKind::Attribute => "attribute proc macro",
102 ProcMacroKind::Derive => "derive proc macro",
103 ProcMacroKind::FunctionLike => "function-like proc macro",
104 }
105 .into_diag_arg(&mut None)
106 }
107}
108
109#[derive(Clone, Copy)]
110enum DocFakeItemKind {
111 Attribute,
112 Keyword,
113}
114
115impl DocFakeItemKind {
116 fn name(self) -> &'static str {
117 match self {
118 Self::Attribute => "attribute",
119 Self::Keyword => "keyword",
120 }
121 }
122}
123
124struct CheckAttrVisitor<'tcx> {
125 tcx: TyCtxt<'tcx>,
126
127 abort: Cell<bool>,
129}
130
131impl<'tcx> CheckAttrVisitor<'tcx> {
132 fn dcx(&self) -> DiagCtxtHandle<'tcx> {
133 self.tcx.dcx()
134 }
135
136 fn check_attributes(
138 &self,
139 hir_id: HirId,
140 span: Span,
141 target: Target,
142 item: Option<ItemLike<'_>>,
143 ) {
144 let mut doc_aliases = FxHashMap::default();
145 let mut specified_inline = None;
146 let mut seen = FxHashMap::default();
147 let attrs = self.tcx.hir_attrs(hir_id);
148 for attr in attrs {
149 let mut style = None;
150 match attr {
151 Attribute::Parsed(AttributeKind::ProcMacro(_)) => {
152 self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
153 }
154 Attribute::Parsed(AttributeKind::ProcMacroAttribute(_)) => {
155 self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
156 }
157 Attribute::Parsed(AttributeKind::ProcMacroDerive { .. }) => {
158 self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
159 }
160 Attribute::Parsed(
161 AttributeKind::Stability {
162 span: attr_span,
163 stability: Stability { level, feature },
164 }
165 | AttributeKind::ConstStability {
166 span: attr_span,
167 stability: PartialConstStability { level, feature, .. },
168 },
169 ) => self.check_stability(*attr_span, span, level, *feature),
170 Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
172 self.check_inline(hir_id, *attr_span, kind, target)
173 }
174 Attribute::Parsed(AttributeKind::LoopMatch(attr_span)) => {
175 self.check_loop_match(hir_id, *attr_span, target)
176 }
177 Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
178 self.check_const_continue(hir_id, *attr_span, target)
179 }
180 Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span) | AttributeKind::AllowInternalUnstable(.., attr_span)) => {
181 self.check_macro_only_attr(*attr_span, span, target, attrs)
182 }
183 Attribute::Parsed(AttributeKind::AllowConstFnUnstable(_, first_span)) => {
184 self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target)
185 }
186 Attribute::Parsed(AttributeKind::Deprecation {span: attr_span, .. }) => {
187 self.check_deprecated(hir_id, *attr_span, target)
188 }
189 Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, ..}) => {
190 self.check_target_feature(hir_id, *attr_span, target, attrs)
191 }
192 Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => {
193 self.check_object_lifetime_default(hir_id);
194 }
195 &Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => {
196 self.check_rustc_pub_transparent(attr_span, span, attrs)
197 }
198 Attribute::Parsed(AttributeKind::Align { align, span: attr_span }) => {
199 self.check_align(*align, *attr_span)
200 }
201 Attribute::Parsed(AttributeKind::Naked(..)) => {
202 self.check_naked(hir_id, target)
203 }
204 Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
205 self.check_track_caller(hir_id, *attr_span, attrs, target)
206 }
207 Attribute::Parsed(AttributeKind::NonExhaustive(attr_span)) => {
208 self.check_non_exhaustive(*attr_span, span, target, item)
209 }
210 &Attribute::Parsed(AttributeKind::FfiPure(attr_span)) => {
211 self.check_ffi_pure(attr_span, attrs)
212 }
213 Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
214 self.check_may_dangle(hir_id, *attr_span)
215 }
216 &Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => {
217 self.check_custom_mir(dialect, phase, attr_span)
218 }
219 &Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, rtsan: _, span: attr_span}) => {
220 self.check_sanitize(attr_span, on_set | off_set, span, target);
221 },
222 Attribute::Parsed(AttributeKind::Link(_, attr_span)) => {
223 self.check_link(hir_id, *attr_span, span, target)
224 },
225 Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => {
226 self.check_macro_export(hir_id, *span, target)
227 },
228 Attribute::Parsed(
229 AttributeKind::BodyStability { .. }
230 | AttributeKind::ConstStabilityIndirect
231 | AttributeKind::MacroTransparency(_)
232 | AttributeKind::Pointee(..)
233 | AttributeKind::Dummy
234 | AttributeKind::RustcBuiltinMacro { .. }
235 | AttributeKind::Ignore { .. }
236 | AttributeKind::Path(..)
237 | AttributeKind::NoImplicitPrelude(..)
238 | AttributeKind::AutomaticallyDerived(..)
239 | AttributeKind::Marker(..)
240 | AttributeKind::SkipDuringMethodDispatch { .. }
241 | AttributeKind::Coinductive(..)
242 | AttributeKind::DenyExplicitImpl(..)
243 | AttributeKind::DoNotImplementViaObject(..)
244 | AttributeKind::SpecializationTrait(..)
245 | AttributeKind::UnsafeSpecializationMarker(..)
246 | AttributeKind::ParenSugar(..)
247 | AttributeKind::AllowIncoherentImpl(..)
248 | AttributeKind::Confusables { .. }
249 | AttributeKind::TypeConst{..}
250 | AttributeKind::DocComment {..}
252 | AttributeKind::Repr { .. }
254 | AttributeKind::Cold(..)
255 | AttributeKind::ExportName { .. }
256 | AttributeKind::Fundamental
257 | AttributeKind::Optimize(..)
258 | AttributeKind::LinkSection { .. }
259 | AttributeKind::MacroUse { .. }
260 | AttributeKind::MacroEscape( .. )
261 | AttributeKind::RustcLayoutScalarValidRangeStart(..)
262 | AttributeKind::RustcLayoutScalarValidRangeEnd(..)
263 | AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
264 | AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
265 | AttributeKind::ExportStable
266 | AttributeKind::FfiConst(..)
267 | AttributeKind::UnstableFeatureBound(..)
268 | AttributeKind::AsPtr(..)
269 | AttributeKind::LinkName { .. }
270 | AttributeKind::LinkOrdinal { .. }
271 | AttributeKind::NoMangle(..)
272 | AttributeKind::Used { .. }
273 | AttributeKind::PassByValue (..)
274 | AttributeKind::StdInternalSymbol (..)
275 | AttributeKind::Coverage (..)
276 | AttributeKind::ShouldPanic { .. }
277 | AttributeKind::Coroutine(..)
278 | AttributeKind::Linkage(..)
279 | AttributeKind::MustUse { .. }
280 | AttributeKind::CrateName { .. }
281 | AttributeKind::RecursionLimit { .. }
282 | AttributeKind::MoveSizeLimit { .. }
283 | AttributeKind::TypeLengthLimit { .. }
284 | AttributeKind::PatternComplexityLimit { .. }
285 | AttributeKind::NoCore { .. }
286 | AttributeKind::NoStd { .. }
287 | AttributeKind::ObjcClass { .. }
288 | AttributeKind::ObjcSelector { .. }
289 | AttributeKind::RustcCoherenceIsCore(..)
290 | AttributeKind::DebuggerVisualizer(..)
291 | AttributeKind::RustcMain
292 | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
293 | AttributeKind::PinV2(..)
294 | AttributeKind::WindowsSubsystem(..)
295 ) => { }
296 Attribute::Unparsed(attr_item) => {
297 style = Some(attr_item.style);
298 match attr.path().as_slice() {
299 [sym::diagnostic, sym::do_not_recommend, ..] => {
300 self.check_do_not_recommend(attr.span(), hir_id, target, attr, item)
301 }
302 [sym::diagnostic, sym::on_unimplemented, ..] => {
303 self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
304 }
305 [sym::diagnostic, sym::on_const, ..] => {
306 self.check_diagnostic_on_const(attr.span(), hir_id, target, item)
307 }
308 [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
309 [sym::doc, ..] => self.check_doc_attrs(
310 attr,
311 attr.span(),
312 attr_item.style,
313 hir_id,
314 target,
315 &mut specified_inline,
316 &mut doc_aliases,
317 ),
318 [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
319 [sym::rustc_no_implicit_autorefs, ..] => {
320 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
321 }
322 [sym::rustc_never_returns_null_ptr, ..] => {
323 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
324 }
325 [sym::rustc_legacy_const_generics, ..] => {
326 self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
327 }
328 [sym::rustc_lint_query_instability, ..] => {
329 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
330 }
331 [sym::rustc_lint_untracked_query_information, ..] => {
332 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
333 }
334 [sym::rustc_lint_diagnostics, ..] => {
335 self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
336 }
337 [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
338 [sym::rustc_lint_opt_deny_field_access, ..] => {
339 self.check_rustc_lint_opt_deny_field_access(attr, span, target)
340 }
341 [sym::rustc_clean, ..]
342 | [sym::rustc_dirty, ..]
343 | [sym::rustc_if_this_changed, ..]
344 | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
345 [sym::rustc_must_implement_one_of, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
346 [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
347 [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
348 [sym::rustc_has_incoherent_inherent_impls, ..] => {
349 self.check_has_incoherent_inherent_impls(attr, span, target)
350 }
351 [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
352 self.check_autodiff(hir_id, attr, span, target)
353 }
354 [
355 sym::allow
357 | sym::expect
358 | sym::warn
359 | sym::deny
360 | sym::forbid
361 | sym::cfg
362 | sym::cfg_attr
363 | sym::cfg_trace
364 | sym::cfg_attr_trace
365 | sym::cfi_encoding | sym::instruction_set | sym::patchable_function_entry | sym::deprecated_safe | sym::prelude_import
372 | sym::panic_handler
373 | sym::lang
374 | sym::needs_allocator
375 | sym::default_lib_allocator,
376 ..
377 ] => {}
378 [name, rest@..] => {
379 match BUILTIN_ATTRIBUTE_MAP.get(name) {
380 Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
382 Some(_) => {
383 if rest.len() > 0 && AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(name)) {
384 continue
388 }
389
390 if !name.as_str().starts_with("rustc_") {
394 span_bug!(
395 attr.span(),
396 "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
397 )
398 }
399 }
400 None => (),
401 }
402 }
403 [] => unreachable!(),
404 }
405 }
406 }
407
408 if hir_id != CRATE_HIR_ID {
409 match attr {
410 Attribute::Parsed(_) => { }
411 Attribute::Unparsed(attr) => {
412 if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
415 attr.path
416 .segments
417 .first()
418 .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
419 {
420 match attr.style {
421 ast::AttrStyle::Outer => {
422 let attr_span = attr.span;
423 let bang_position = self
424 .tcx
425 .sess
426 .source_map()
427 .span_until_char(attr_span, '[')
428 .shrink_to_hi();
429
430 self.tcx.emit_node_span_lint(
431 UNUSED_ATTRIBUTES,
432 hir_id,
433 attr.span,
434 errors::OuterCrateLevelAttr {
435 suggestion: errors::OuterCrateLevelAttrSuggestion {
436 bang_position,
437 },
438 },
439 )
440 }
441 ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
442 UNUSED_ATTRIBUTES,
443 hir_id,
444 attr.span,
445 errors::InnerCrateLevelAttr,
446 ),
447 }
448 }
449 }
450 }
451 }
452
453 if let Attribute::Unparsed(unparsed_attr) = attr
454 && let Some(BuiltinAttribute { duplicates, .. }) =
455 attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
456 {
457 check_duplicates(
458 self.tcx,
459 unparsed_attr.span,
460 attr,
461 hir_id,
462 *duplicates,
463 &mut seen,
464 );
465 }
466
467 self.check_unused_attribute(hir_id, attr, style)
468 }
469
470 self.check_repr(attrs, span, target, item, hir_id);
471 self.check_rustc_force_inline(hir_id, attrs, target);
472 self.check_mix_no_mangle_export(hir_id, attrs);
473 }
474
475 fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) {
476 self.tcx.emit_node_span_lint(
477 UNUSED_ATTRIBUTES,
478 hir_id,
479 attr_span,
480 errors::IgnoredAttrWithMacro { sym },
481 );
482 }
483
484 fn check_do_not_recommend(
487 &self,
488 attr_span: Span,
489 hir_id: HirId,
490 target: Target,
491 attr: &Attribute,
492 item: Option<ItemLike<'_>>,
493 ) {
494 if !matches!(target, Target::Impl { .. })
495 || matches!(
496 item,
497 Some(ItemLike::Item(hir::Item { kind: hir::ItemKind::Impl(_impl),.. }))
498 if _impl.of_trait.is_none()
499 )
500 {
501 self.tcx.emit_node_span_lint(
502 MISPLACED_DIAGNOSTIC_ATTRIBUTES,
503 hir_id,
504 attr_span,
505 errors::IncorrectDoNotRecommendLocation,
506 );
507 }
508 if !attr.is_word() {
509 self.tcx.emit_node_span_lint(
510 MALFORMED_DIAGNOSTIC_ATTRIBUTES,
511 hir_id,
512 attr_span,
513 errors::DoNotRecommendDoesNotExpectArgs,
514 );
515 }
516 }
517
518 fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
520 if !matches!(target, Target::Trait) {
521 self.tcx.emit_node_span_lint(
522 MISPLACED_DIAGNOSTIC_ATTRIBUTES,
523 hir_id,
524 attr_span,
525 DiagnosticOnUnimplementedOnlyForTraits,
526 );
527 }
528 }
529
530 fn check_diagnostic_on_const(
532 &self,
533 attr_span: Span,
534 hir_id: HirId,
535 target: Target,
536 item: Option<ItemLike<'_>>,
537 ) {
538 if matches!(target, Target::Impl { of_trait: true }) {
539 match item.unwrap() {
540 ItemLike::Item(it) => match it.expect_impl().constness {
541 Constness::Const => {}
542 Constness::NotConst => return,
543 },
544 ItemLike::ForeignItem => {}
545 }
546 }
547 let item_span = self.tcx.hir_span(hir_id);
548 self.tcx.emit_node_span_lint(
549 MISPLACED_DIAGNOSTIC_ATTRIBUTES,
550 hir_id,
551 attr_span,
552 DiagnosticOnConstOnlyForTraitImpls { item_span },
553 );
554 }
555
556 fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {
558 match target {
559 Target::Fn
560 | Target::Closure
561 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
562 if let Some(did) = hir_id.as_owner()
564 && self.tcx.def_kind(did).has_codegen_attrs()
565 && kind != &InlineAttr::Never
566 {
567 let attrs = self.tcx.codegen_fn_attrs(did);
568 if attrs.contains_extern_indicator() {
570 self.tcx.emit_node_span_lint(
571 UNUSED_ATTRIBUTES,
572 hir_id,
573 attr_span,
574 errors::InlineIgnoredForExported {},
575 );
576 }
577 }
578 }
579 _ => {}
580 }
581 }
582
583 fn check_sanitize(
586 &self,
587 attr_span: Span,
588 set: SanitizerSet,
589 target_span: Span,
590 target: Target,
591 ) {
592 let mut not_fn_impl_mod = None;
593 let mut no_body = None;
594
595 match target {
596 Target::Fn
597 | Target::Closure
598 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
599 | Target::Impl { .. }
600 | Target::Mod => return,
601 Target::Static
602 if set & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
605 == SanitizerSet::empty() =>
606 {
607 return;
608 }
609
610 Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
613 no_body = Some(target_span);
614 }
615
616 _ => {
617 not_fn_impl_mod = Some(target_span);
618 }
619 }
620
621 self.dcx().emit_err(errors::SanitizeAttributeNotAllowed {
622 attr_span,
623 not_fn_impl_mod,
624 no_body,
625 help: (),
626 });
627 }
628
629 fn check_naked(&self, hir_id: HirId, target: Target) {
631 match target {
632 Target::Fn
633 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
634 let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
635 let abi = fn_sig.header.abi;
636 if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() {
637 feature_err(
638 &self.tcx.sess,
639 sym::naked_functions_rustic_abi,
640 fn_sig.span,
641 format!(
642 "`#[naked]` is currently unstable on `extern \"{}\"` functions",
643 abi.as_str()
644 ),
645 )
646 .emit();
647 }
648 }
649 _ => {}
650 }
651 }
652
653 fn check_object_lifetime_default(&self, hir_id: HirId) {
655 let tcx = self.tcx;
656 if let Some(owner_id) = hir_id.as_owner()
657 && let Some(generics) = tcx.hir_get_generics(owner_id.def_id)
658 {
659 for p in generics.params {
660 let hir::GenericParamKind::Type { .. } = p.kind else { continue };
661 let default = tcx.object_lifetime_default(p.def_id);
662 let repr = match default {
663 ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
664 ObjectLifetimeDefault::Static => "'static".to_owned(),
665 ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
666 ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
667 };
668 tcx.dcx().emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
669 }
670 }
671 }
672 fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) {
674 match target {
675 Target::MacroDef => {}
676 _ => {
677 self.tcx.dcx().emit_err(errors::CollapseDebuginfo {
678 attr_span: attr.span(),
679 defn_span: span,
680 });
681 }
682 }
683 }
684
685 fn check_track_caller(
687 &self,
688 hir_id: HirId,
689 attr_span: Span,
690 attrs: &[Attribute],
691 target: Target,
692 ) {
693 match target {
694 Target::Fn => {
695 if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
698 && let Some(item) = hir::LangItem::from_name(lang_item)
699 && item.is_weak()
700 {
701 let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
702
703 self.dcx().emit_err(errors::LangItemWithTrackCaller {
704 attr_span,
705 name: lang_item,
706 sig_span: sig.span,
707 });
708 }
709 }
710 _ => {}
711 }
712 }
713
714 fn check_non_exhaustive(
716 &self,
717 attr_span: Span,
718 span: Span,
719 target: Target,
720 item: Option<ItemLike<'_>>,
721 ) {
722 match target {
723 Target::Struct => {
724 if let Some(ItemLike::Item(hir::Item {
725 kind: hir::ItemKind::Struct(_, _, hir::VariantData::Struct { fields, .. }),
726 ..
727 })) = item
728 && !fields.is_empty()
729 && fields.iter().any(|f| f.default.is_some())
730 {
731 self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
732 attr_span,
733 defn_span: span,
734 });
735 }
736 }
737 _ => {}
738 }
739 }
740
741 fn check_target_feature(
743 &self,
744 hir_id: HirId,
745 attr_span: Span,
746 target: Target,
747 attrs: &[Attribute],
748 ) {
749 match target {
750 Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
751 | Target::Fn => {
752 if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
754 && !self.tcx.sess.target.is_like_wasm
757 && !self.tcx.sess.opts.actually_rustdoc
758 {
759 let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
760
761 self.dcx().emit_err(errors::LangItemWithTargetFeature {
762 attr_span,
763 name: lang_item,
764 sig_span: sig.span,
765 });
766 }
767 }
768 _ => {}
769 }
770 }
771
772 fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) {
774 match target {
775 Target::ForeignStatic | Target::Static => {}
776 _ => {
777 self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
778 attr_span: attr.span(),
779 defn_span: span,
780 });
781 }
782 }
783 }
784
785 fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) {
786 self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
787 }
788
789 fn check_doc_alias_value(
790 &self,
791 meta: &MetaItemInner,
792 doc_alias: Symbol,
793 hir_id: HirId,
794 target: Target,
795 is_list: bool,
796 aliases: &mut FxHashMap<String, Span>,
797 ) {
798 let tcx = self.tcx;
799 let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
800 let attr_str =
801 &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
802 if doc_alias == sym::empty {
803 tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
804 return;
805 }
806
807 let doc_alias_str = doc_alias.as_str();
808 if let Some(c) = doc_alias_str
809 .chars()
810 .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
811 {
812 tcx.dcx().emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
813 return;
814 }
815 if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
816 tcx.dcx().emit_err(errors::DocAliasStartEnd { span, attr_str });
817 return;
818 }
819
820 let span = meta.span();
821 if let Some(location) = match target {
822 Target::AssocTy => {
823 if let DefKind::Impl { .. } =
824 self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id))
825 {
826 Some("type alias in implementation block")
827 } else {
828 None
829 }
830 }
831 Target::AssocConst => {
832 let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
833 let containing_item = self.tcx.hir_expect_item(parent_def_id);
834 let err = "associated constant in trait implementation block";
836 match containing_item.kind {
837 ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
838 _ => None,
839 }
840 }
841 Target::Param => return,
843 Target::Expression
844 | Target::Statement
845 | Target::Arm
846 | Target::ForeignMod
847 | Target::Closure
848 | Target::Impl { .. }
849 | Target::WherePredicate => Some(target.name()),
850 Target::ExternCrate
851 | Target::Use
852 | Target::Static
853 | Target::Const
854 | Target::Fn
855 | Target::Mod
856 | Target::GlobalAsm
857 | Target::TyAlias
858 | Target::Enum
859 | Target::Variant
860 | Target::Struct
861 | Target::Field
862 | Target::Union
863 | Target::Trait
864 | Target::TraitAlias
865 | Target::Method(..)
866 | Target::ForeignFn
867 | Target::ForeignStatic
868 | Target::ForeignTy
869 | Target::GenericParam { .. }
870 | Target::MacroDef
871 | Target::PatField
872 | Target::ExprField
873 | Target::Crate
874 | Target::MacroCall
875 | Target::Delegation { .. } => None,
876 } {
877 tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location });
878 return;
879 }
880 if self.tcx.hir_opt_name(hir_id) == Some(doc_alias) {
881 tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str });
882 return;
883 }
884 if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
885 self.tcx.emit_node_span_lint(
886 UNUSED_ATTRIBUTES,
887 hir_id,
888 span,
889 errors::DocAliasDuplicated { first_defn: *entry.entry.get() },
890 );
891 }
892 }
893
894 fn check_doc_alias(
895 &self,
896 meta: &MetaItemInner,
897 hir_id: HirId,
898 target: Target,
899 aliases: &mut FxHashMap<String, Span>,
900 ) {
901 if let Some(values) = meta.meta_item_list() {
902 for v in values {
903 match v.lit() {
904 Some(l) => match l.kind {
905 LitKind::Str(s, _) => {
906 self.check_doc_alias_value(v, s, hir_id, target, true, aliases);
907 }
908 _ => {
909 self.tcx
910 .dcx()
911 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
912 }
913 },
914 None => {
915 self.tcx
916 .dcx()
917 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
918 }
919 }
920 }
921 } else if let Some(doc_alias) = meta.value_str() {
922 self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
923 } else {
924 self.dcx().emit_err(errors::DocAliasMalformed { span: meta.span() });
925 }
926 }
927
928 fn check_doc_keyword_and_attribute(
929 &self,
930 meta: &MetaItemInner,
931 hir_id: HirId,
932 attr_kind: DocFakeItemKind,
933 ) {
934 fn is_doc_keyword(s: Symbol) -> bool {
935 s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy
939 }
940
941 fn is_builtin_attr(s: Symbol) -> bool {
943 rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s)
944 }
945
946 let value = match meta.value_str() {
947 Some(value) if value != sym::empty => value,
948 _ => return self.doc_attr_str_error(meta, attr_kind.name()),
949 };
950
951 let item_kind = match self.tcx.hir_node(hir_id) {
952 hir::Node::Item(item) => Some(&item.kind),
953 _ => None,
954 };
955 match item_kind {
956 Some(ItemKind::Mod(_, module)) => {
957 if !module.item_ids.is_empty() {
958 self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod {
959 span: meta.span(),
960 attr_name: attr_kind.name(),
961 });
962 return;
963 }
964 }
965 _ => {
966 self.dcx().emit_err(errors::DocKeywordAttributeNotMod {
967 span: meta.span(),
968 attr_name: attr_kind.name(),
969 });
970 return;
971 }
972 }
973 match attr_kind {
974 DocFakeItemKind::Keyword => {
975 if !is_doc_keyword(value) {
976 self.dcx().emit_err(errors::DocKeywordNotKeyword {
977 span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
978 keyword: value,
979 });
980 }
981 }
982 DocFakeItemKind::Attribute => {
983 if !is_builtin_attr(value) {
984 self.dcx().emit_err(errors::DocAttributeNotAttribute {
985 span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
986 attribute: value,
987 });
988 }
989 }
990 }
991 }
992
993 fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) {
994 let item_kind = match self.tcx.hir_node(hir_id) {
995 hir::Node::Item(item) => Some(&item.kind),
996 _ => None,
997 };
998 match item_kind {
999 Some(ItemKind::Impl(i)) => {
1000 let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
1001 || if let Some(&[hir::GenericArg::Type(ty)]) = i
1002 .of_trait
1003 .and_then(|of_trait| of_trait.trait_ref.path.segments.last())
1004 .map(|last_segment| last_segment.args().args)
1005 {
1006 matches!(&ty.kind, hir::TyKind::Tup([_]))
1007 } else {
1008 false
1009 };
1010 if !is_valid {
1011 self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
1012 }
1013 }
1014 _ => {
1015 self.dcx().emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
1016 }
1017 }
1018 }
1019
1020 fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) {
1021 let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
1022 self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
1023 return;
1024 };
1025 match item.kind {
1026 ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _)
1027 if generics.params.len() != 0 => {}
1028 ItemKind::Trait(_, _, _, _, generics, _, items)
1029 if generics.params.len() != 0
1030 || items.iter().any(|item| {
1031 matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy)
1032 }) => {}
1033 ItemKind::TyAlias(_, generics, _) if generics.params.len() != 0 => {}
1034 _ => {
1035 self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
1036 }
1037 }
1038 }
1039
1040 fn check_doc_inline(
1050 &self,
1051 style: AttrStyle,
1052 meta: &MetaItemInner,
1053 hir_id: HirId,
1054 target: Target,
1055 specified_inline: &mut Option<(bool, Span)>,
1056 ) {
1057 match target {
1058 Target::Use | Target::ExternCrate => {
1059 let do_inline = meta.has_name(sym::inline);
1060 if let Some((prev_inline, prev_span)) = *specified_inline {
1061 if do_inline != prev_inline {
1062 let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
1063 spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
1064 spans.push_span_label(
1065 meta.span(),
1066 fluent::passes_doc_inline_conflict_second,
1067 );
1068 self.dcx().emit_err(errors::DocKeywordConflict { spans });
1069 }
1070 } else {
1071 *specified_inline = Some((do_inline, meta.span()));
1072 }
1073 }
1074 _ => {
1075 self.tcx.emit_node_span_lint(
1076 INVALID_DOC_ATTRIBUTES,
1077 hir_id,
1078 meta.span(),
1079 errors::DocInlineOnlyUse {
1080 attr_span: meta.span(),
1081 item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
1082 },
1083 );
1084 }
1085 }
1086 }
1087
1088 fn check_doc_masked(
1089 &self,
1090 style: AttrStyle,
1091 meta: &MetaItemInner,
1092 hir_id: HirId,
1093 target: Target,
1094 ) {
1095 if target != Target::ExternCrate {
1096 self.tcx.emit_node_span_lint(
1097 INVALID_DOC_ATTRIBUTES,
1098 hir_id,
1099 meta.span(),
1100 errors::DocMaskedOnlyExternCrate {
1101 attr_span: meta.span(),
1102 item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
1103 },
1104 );
1105 return;
1106 }
1107
1108 if self.tcx.extern_mod_stmt_cnum(hir_id.owner.def_id).is_none() {
1109 self.tcx.emit_node_span_lint(
1110 INVALID_DOC_ATTRIBUTES,
1111 hir_id,
1112 meta.span(),
1113 errors::DocMaskedNotExternCrateSelf {
1114 attr_span: meta.span(),
1115 item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)),
1116 },
1117 );
1118 }
1119 }
1120
1121 fn check_attr_not_crate_level(
1123 &self,
1124 meta: &MetaItemInner,
1125 hir_id: HirId,
1126 attr_name: &str,
1127 ) -> bool {
1128 if CRATE_HIR_ID == hir_id {
1129 self.dcx().emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
1130 return false;
1131 }
1132 true
1133 }
1134
1135 fn check_attr_crate_level(
1137 &self,
1138 attr_span: Span,
1139 style: AttrStyle,
1140 meta: &MetaItemInner,
1141 hir_id: HirId,
1142 ) -> bool {
1143 if hir_id != CRATE_HIR_ID {
1144 let bang_span = attr_span.lo() + BytePos(1);
1146 let sugg = (style == AttrStyle::Outer
1147 && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
1148 .then_some(errors::AttrCrateLevelOnlySugg {
1149 attr: attr_span.with_lo(bang_span).with_hi(bang_span),
1150 });
1151 self.tcx.emit_node_span_lint(
1152 INVALID_DOC_ATTRIBUTES,
1153 hir_id,
1154 meta.span(),
1155 errors::AttrCrateLevelOnly { sugg },
1156 );
1157 return false;
1158 }
1159 true
1160 }
1161
1162 fn check_doc_attr_string_value(&self, meta: &MetaItemInner, hir_id: HirId) {
1163 if meta.value_str().is_none() {
1164 self.tcx.emit_node_span_lint(
1165 INVALID_DOC_ATTRIBUTES,
1166 hir_id,
1167 meta.span(),
1168 errors::DocAttrExpectsString { attr_name: meta.name().unwrap() },
1169 );
1170 }
1171 }
1172
1173 fn check_doc_attr_no_value(&self, meta: &MetaItemInner, hir_id: HirId) {
1174 if !meta.is_word() {
1175 self.tcx.emit_node_span_lint(
1176 INVALID_DOC_ATTRIBUTES,
1177 hir_id,
1178 meta.span(),
1179 errors::DocAttrExpectsNoValue { attr_name: meta.name().unwrap() },
1180 );
1181 }
1182 }
1183
1184 fn check_test_attr(
1186 &self,
1187 attr_span: Span,
1188 style: AttrStyle,
1189 meta: &MetaItemInner,
1190 hir_id: HirId,
1191 ) {
1192 if let Some(metas) = meta.meta_item_list() {
1193 for i_meta in metas {
1194 match (i_meta.name(), i_meta.meta_item()) {
1195 (Some(sym::attr), _) => {
1196 }
1198 (Some(sym::no_crate_inject), _) => {
1199 self.check_attr_crate_level(attr_span, style, meta, hir_id);
1200 }
1201 (_, Some(m)) => {
1202 self.tcx.emit_node_span_lint(
1203 INVALID_DOC_ATTRIBUTES,
1204 hir_id,
1205 i_meta.span(),
1206 errors::DocTestUnknown {
1207 path: rustc_ast_pretty::pprust::path_to_string(&m.path),
1208 },
1209 );
1210 }
1211 (_, None) => {
1212 self.tcx.emit_node_span_lint(
1213 INVALID_DOC_ATTRIBUTES,
1214 hir_id,
1215 i_meta.span(),
1216 errors::DocTestLiteral,
1217 );
1218 }
1219 }
1220 }
1221 } else {
1222 self.tcx.emit_node_span_lint(
1223 INVALID_DOC_ATTRIBUTES,
1224 hir_id,
1225 meta.span(),
1226 errors::DocTestTakesList,
1227 );
1228 }
1229 }
1230
1231 fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) {
1233 match &meta.kind {
1234 MetaItemKind::Word => {}
1235 MetaItemKind::NameValue(lit) => {
1236 if !matches!(lit.kind, LitKind::Bool(_)) {
1237 self.tcx.emit_node_span_lint(
1238 INVALID_DOC_ATTRIBUTES,
1239 hir_id,
1240 meta.span,
1241 errors::DocAutoCfgWrongLiteral,
1242 );
1243 }
1244 }
1245 MetaItemKind::List(list) => {
1246 for item in list {
1247 let Some(attr_name @ (sym::hide | sym::show)) = item.name() else {
1248 self.tcx.emit_node_span_lint(
1249 INVALID_DOC_ATTRIBUTES,
1250 hir_id,
1251 meta.span,
1252 errors::DocAutoCfgExpectsHideOrShow,
1253 );
1254 continue;
1255 };
1256 if let Some(list) = item.meta_item_list() {
1257 for item in list {
1258 let valid = item.meta_item().is_some_and(|meta| {
1259 meta.path.segments.len() == 1
1260 && matches!(
1261 &meta.kind,
1262 MetaItemKind::Word | MetaItemKind::NameValue(_)
1263 )
1264 });
1265 if !valid {
1266 self.tcx.emit_node_span_lint(
1267 INVALID_DOC_ATTRIBUTES,
1268 hir_id,
1269 item.span(),
1270 errors::DocAutoCfgHideShowUnexpectedItem { attr_name },
1271 );
1272 }
1273 }
1274 } else {
1275 self.tcx.emit_node_span_lint(
1276 INVALID_DOC_ATTRIBUTES,
1277 hir_id,
1278 meta.span,
1279 errors::DocAutoCfgHideShowExpectsList { attr_name },
1280 );
1281 }
1282 }
1283 }
1284 }
1285 }
1286
1287 fn check_doc_attrs(
1294 &self,
1295 attr: &Attribute,
1296 attr_span: Span,
1297 style: AttrStyle,
1298 hir_id: HirId,
1299 target: Target,
1300 specified_inline: &mut Option<(bool, Span)>,
1301 aliases: &mut FxHashMap<String, Span>,
1302 ) {
1303 if let Some(list) = attr.meta_item_list() {
1304 for meta in &list {
1305 if let Some(i_meta) = meta.meta_item() {
1306 match i_meta.name() {
1307 Some(sym::alias) => {
1308 if self.check_attr_not_crate_level(meta, hir_id, "alias") {
1309 self.check_doc_alias(meta, hir_id, target, aliases);
1310 }
1311 }
1312
1313 Some(sym::keyword) => {
1314 if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
1315 self.check_doc_keyword_and_attribute(
1316 meta,
1317 hir_id,
1318 DocFakeItemKind::Keyword,
1319 );
1320 }
1321 }
1322
1323 Some(sym::attribute) => {
1324 if self.check_attr_not_crate_level(meta, hir_id, "attribute") {
1325 self.check_doc_keyword_and_attribute(
1326 meta,
1327 hir_id,
1328 DocFakeItemKind::Attribute,
1329 );
1330 }
1331 }
1332
1333 Some(sym::fake_variadic) => {
1334 if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1335 self.check_doc_fake_variadic(meta, hir_id);
1336 }
1337 }
1338
1339 Some(sym::search_unbox) => {
1340 if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1341 self.check_doc_search_unbox(meta, hir_id);
1342 }
1343 }
1344
1345 Some(sym::test) => {
1346 self.check_test_attr(attr_span, style, meta, hir_id);
1347 }
1348
1349 Some(
1350 sym::html_favicon_url
1351 | sym::html_logo_url
1352 | sym::html_playground_url
1353 | sym::issue_tracker_base_url
1354 | sym::html_root_url,
1355 ) => {
1356 self.check_attr_crate_level(attr_span, style, meta, hir_id);
1357 self.check_doc_attr_string_value(meta, hir_id);
1358 }
1359
1360 Some(sym::html_no_source) => {
1361 self.check_attr_crate_level(attr_span, style, meta, hir_id);
1362 self.check_doc_attr_no_value(meta, hir_id);
1363 }
1364
1365 Some(sym::auto_cfg) => {
1366 self.check_doc_auto_cfg(i_meta, hir_id);
1367 }
1368
1369 Some(sym::inline | sym::no_inline) => {
1370 self.check_doc_inline(style, meta, hir_id, target, specified_inline)
1371 }
1372
1373 Some(sym::masked) => self.check_doc_masked(style, meta, hir_id, target),
1374
1375 Some(sym::cfg | sym::hidden | sym::notable_trait) => {}
1376
1377 Some(sym::rust_logo) => {
1378 if self.check_attr_crate_level(attr_span, style, meta, hir_id)
1379 && !self.tcx.features().rustdoc_internals()
1380 {
1381 feature_err(
1382 &self.tcx.sess,
1383 sym::rustdoc_internals,
1384 meta.span(),
1385 fluent::passes_doc_rust_logo,
1386 )
1387 .emit();
1388 }
1389 }
1390
1391 _ => {
1392 let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
1393 if i_meta.has_name(sym::spotlight) {
1394 self.tcx.emit_node_span_lint(
1395 INVALID_DOC_ATTRIBUTES,
1396 hir_id,
1397 i_meta.span,
1398 errors::DocTestUnknownSpotlight { path, span: i_meta.span },
1399 );
1400 } else if i_meta.has_name(sym::include)
1401 && let Some(value) = i_meta.value_str()
1402 {
1403 let applicability = if list.len() == 1 {
1404 Applicability::MachineApplicable
1405 } else {
1406 Applicability::MaybeIncorrect
1407 };
1408 self.tcx.emit_node_span_lint(
1411 INVALID_DOC_ATTRIBUTES,
1412 hir_id,
1413 i_meta.span,
1414 errors::DocTestUnknownInclude {
1415 path,
1416 value: value.to_string(),
1417 inner: match style {
1418 AttrStyle::Inner => "!",
1419 AttrStyle::Outer => "",
1420 },
1421 sugg: (attr.span(), applicability),
1422 },
1423 );
1424 } else if i_meta.has_name(sym::passes)
1425 || i_meta.has_name(sym::no_default_passes)
1426 {
1427 self.tcx.emit_node_span_lint(
1428 INVALID_DOC_ATTRIBUTES,
1429 hir_id,
1430 i_meta.span,
1431 errors::DocTestUnknownPasses { path, span: i_meta.span },
1432 );
1433 } else if i_meta.has_name(sym::plugins) {
1434 self.tcx.emit_node_span_lint(
1435 INVALID_DOC_ATTRIBUTES,
1436 hir_id,
1437 i_meta.span,
1438 errors::DocTestUnknownPlugins { path, span: i_meta.span },
1439 );
1440 } else {
1441 self.tcx.emit_node_span_lint(
1442 INVALID_DOC_ATTRIBUTES,
1443 hir_id,
1444 i_meta.span,
1445 errors::DocTestUnknownAny { path },
1446 );
1447 }
1448 }
1449 }
1450 } else {
1451 self.tcx.emit_node_span_lint(
1452 INVALID_DOC_ATTRIBUTES,
1453 hir_id,
1454 meta.span(),
1455 errors::DocInvalid,
1456 );
1457 }
1458 }
1459 }
1460 }
1461
1462 fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) {
1463 match target {
1464 Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {}
1465 _ => {
1466 self.tcx
1467 .dcx()
1468 .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span });
1469 }
1470 }
1471 }
1472
1473 fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute]) {
1474 if find_attr!(attrs, AttributeKind::FfiConst(_)) {
1475 self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span });
1477 }
1478 }
1479
1480 fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
1482 match target {
1483 Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
1484 _ => {
1485 self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span });
1486 }
1487 }
1488 }
1489
1490 fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) {
1492 if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id)
1493 && matches!(
1494 param.kind,
1495 hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }
1496 )
1497 && matches!(param.source, hir::GenericParamSource::Generics)
1498 && let parent_hir_id = self.tcx.parent_hir_id(hir_id)
1499 && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
1500 && let hir::ItemKind::Impl(impl_) = item.kind
1501 && let Some(of_trait) = impl_.of_trait
1502 && let Some(def_id) = of_trait.trait_ref.trait_def_id()
1503 && self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
1504 {
1505 return;
1506 }
1507
1508 self.dcx().emit_err(errors::InvalidMayDangle { attr_span });
1509 }
1510
1511 fn check_link(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
1513 if target == Target::ForeignMod
1514 && let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
1515 && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
1516 && !matches!(abi, ExternAbi::Rust)
1517 {
1518 return;
1519 }
1520
1521 self.tcx.emit_node_span_lint(
1522 UNUSED_ATTRIBUTES,
1523 hir_id,
1524 attr_span,
1525 errors::Link { span: (target != Target::ForeignMod).then_some(span) },
1526 );
1527 }
1528
1529 fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1531 match target {
1532 Target::ExternCrate => {}
1533 Target::Field | Target::Arm | Target::MacroDef => {
1538 self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link");
1539 }
1540 _ => {
1541 self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span });
1542 }
1543 }
1544 }
1545
1546 fn check_rustc_legacy_const_generics(
1548 &self,
1549 hir_id: HirId,
1550 attr: &Attribute,
1551 span: Span,
1552 target: Target,
1553 item: Option<ItemLike<'_>>,
1554 ) {
1555 let is_function = matches!(target, Target::Fn);
1556 if !is_function {
1557 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
1558 attr_span: attr.span(),
1559 defn_span: span,
1560 on_crate: hir_id == CRATE_HIR_ID,
1561 });
1562 return;
1563 }
1564
1565 let Some(list) = attr.meta_item_list() else {
1566 return;
1568 };
1569
1570 let Some(ItemLike::Item(Item {
1571 kind: ItemKind::Fn { sig: FnSig { decl, .. }, generics, .. },
1572 ..
1573 })) = item
1574 else {
1575 bug!("should be a function item");
1576 };
1577
1578 for param in generics.params {
1579 match param.kind {
1580 hir::GenericParamKind::Const { .. } => {}
1581 _ => {
1582 self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly {
1583 attr_span: attr.span(),
1584 param_span: param.span,
1585 });
1586 return;
1587 }
1588 }
1589 }
1590
1591 if list.len() != generics.params.len() {
1592 self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex {
1593 attr_span: attr.span(),
1594 generics_span: generics.span,
1595 });
1596 return;
1597 }
1598
1599 let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
1600 let mut invalid_args = vec![];
1601 for meta in list {
1602 if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) {
1603 if *val >= arg_count {
1604 let span = meta.span();
1605 self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed {
1606 span,
1607 arg_count: arg_count as usize,
1608 });
1609 return;
1610 }
1611 } else {
1612 invalid_args.push(meta.span());
1613 }
1614 }
1615
1616 if !invalid_args.is_empty() {
1617 self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
1618 }
1619 }
1620
1621 fn check_applied_to_fn_or_method(
1624 &self,
1625 hir_id: HirId,
1626 attr_span: Span,
1627 defn_span: Span,
1628 target: Target,
1629 ) {
1630 let is_function = matches!(target, Target::Fn | Target::Method(..));
1631 if !is_function {
1632 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
1633 attr_span,
1634 defn_span,
1635 on_crate: hir_id == CRATE_HIR_ID,
1636 });
1637 }
1638 }
1639
1640 fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
1642 match target {
1643 Target::Struct => {}
1644 _ => {
1645 self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span(), span });
1646 }
1647 }
1648 }
1649
1650 fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) {
1652 match target {
1653 Target::Field => {}
1654 _ => {
1655 self.tcx
1656 .dcx()
1657 .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span });
1658 }
1659 }
1660 }
1661
1662 fn check_rustc_dirty_clean(&self, attr: &Attribute) {
1665 if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
1666 self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span() });
1667 }
1668 }
1669
1670 fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) {
1672 match target {
1673 Target::Trait => {}
1674 _ => {
1675 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span });
1676 }
1677 }
1678 }
1679
1680 fn check_repr(
1682 &self,
1683 attrs: &[Attribute],
1684 span: Span,
1685 target: Target,
1686 item: Option<ItemLike<'_>>,
1687 hir_id: HirId,
1688 ) {
1689 let (reprs, first_attr_span) = find_attr!(attrs, AttributeKind::Repr { reprs, first_span } => (reprs.as_slice(), Some(*first_span))).unwrap_or((&[], None));
1695
1696 let mut int_reprs = 0;
1697 let mut is_explicit_rust = false;
1698 let mut is_c = false;
1699 let mut is_simd = false;
1700 let mut is_transparent = false;
1701
1702 for (repr, repr_span) in reprs {
1703 match repr {
1704 ReprAttr::ReprRust => {
1705 is_explicit_rust = true;
1706 match target {
1707 Target::Struct | Target::Union | Target::Enum => continue,
1708 _ => {
1709 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1710 hint_span: *repr_span,
1711 span,
1712 });
1713 }
1714 }
1715 }
1716 ReprAttr::ReprC => {
1717 is_c = true;
1718 match target {
1719 Target::Struct | Target::Union | Target::Enum => continue,
1720 _ => {
1721 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1722 hint_span: *repr_span,
1723 span,
1724 });
1725 }
1726 }
1727 }
1728 ReprAttr::ReprAlign(align) => {
1729 match target {
1730 Target::Struct | Target::Union | Target::Enum => {}
1731 Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => {
1732 self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
1733 span: *repr_span,
1734 item: target.plural_name(),
1735 });
1736 }
1737 Target::Static if self.tcx.features().static_align() => {
1738 self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic {
1739 span: *repr_span,
1740 item: target.plural_name(),
1741 });
1742 }
1743 _ => {
1744 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1745 hint_span: *repr_span,
1746 span,
1747 });
1748 }
1749 }
1750
1751 self.check_align(*align, *repr_span);
1752 }
1753 ReprAttr::ReprPacked(_) => {
1754 if target != Target::Struct && target != Target::Union {
1755 self.dcx().emit_err(errors::AttrApplication::StructUnion {
1756 hint_span: *repr_span,
1757 span,
1758 });
1759 } else {
1760 continue;
1761 }
1762 }
1763 ReprAttr::ReprSimd => {
1764 is_simd = true;
1765 if target != Target::Struct {
1766 self.dcx().emit_err(errors::AttrApplication::Struct {
1767 hint_span: *repr_span,
1768 span,
1769 });
1770 } else {
1771 continue;
1772 }
1773 }
1774 ReprAttr::ReprTransparent => {
1775 is_transparent = true;
1776 match target {
1777 Target::Struct | Target::Union | Target::Enum => continue,
1778 _ => {
1779 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1780 hint_span: *repr_span,
1781 span,
1782 });
1783 }
1784 }
1785 }
1786 ReprAttr::ReprInt(_) => {
1787 int_reprs += 1;
1788 if target != Target::Enum {
1789 self.dcx().emit_err(errors::AttrApplication::Enum {
1790 hint_span: *repr_span,
1791 span,
1792 });
1793 } else {
1794 continue;
1795 }
1796 }
1797 };
1798 }
1799
1800 if let Some(first_attr_span) = first_attr_span
1802 && reprs.is_empty()
1803 && item.is_some()
1804 {
1805 match target {
1806 Target::Struct | Target::Union | Target::Enum => {}
1807 Target::Fn | Target::Method(_) => {
1808 self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
1809 span: first_attr_span,
1810 item: target.plural_name(),
1811 });
1812 }
1813 _ => {
1814 self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1815 hint_span: first_attr_span,
1816 span,
1817 });
1818 }
1819 }
1820 return;
1821 }
1822
1823 let hint_spans = reprs.iter().map(|(_, span)| *span);
1826
1827 if is_transparent && reprs.len() > 1 {
1829 let hint_spans = hint_spans.clone().collect();
1830 self.dcx().emit_err(errors::TransparentIncompatible {
1831 hint_spans,
1832 target: target.to_string(),
1833 });
1834 }
1835 if is_transparent
1838 && let Some(&pass_indirectly_span) =
1839 find_attr!(attrs, AttributeKind::RustcPassIndirectlyInNonRusticAbis(span) => span)
1840 {
1841 self.dcx().emit_err(errors::TransparentIncompatible {
1842 hint_spans: vec![span, pass_indirectly_span],
1843 target: target.to_string(),
1844 });
1845 }
1846 if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
1847 let hint_spans = hint_spans.clone().collect();
1848 self.dcx().emit_err(errors::ReprConflicting { hint_spans });
1849 }
1850 if (int_reprs > 1)
1852 || (is_simd && is_c)
1853 || (int_reprs == 1
1854 && is_c
1855 && item.is_some_and(|item| {
1856 if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false }
1857 }))
1858 {
1859 self.tcx.emit_node_span_lint(
1860 CONFLICTING_REPR_HINTS,
1861 hir_id,
1862 hint_spans.collect::<Vec<Span>>(),
1863 errors::ReprConflictingLint,
1864 );
1865 }
1866 }
1867
1868 fn check_align(&self, align: Align, span: Span) {
1869 if align.bytes() > 2_u64.pow(29) {
1870 self.dcx().span_delayed_bug(
1872 span,
1873 "alignment greater than 2^29 should be errored on elsewhere",
1874 );
1875 } else {
1876 let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
1881 if align.bytes() > max {
1882 self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max });
1883 }
1884 }
1885 }
1886
1887 fn check_macro_only_attr(
1892 &self,
1893 attr_span: Span,
1894 span: Span,
1895 target: Target,
1896 attrs: &[Attribute],
1897 ) {
1898 match target {
1899 Target::Fn => {
1900 for attr in attrs {
1901 if attr.is_proc_macro_attr() {
1902 return;
1904 }
1905 }
1906 self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span });
1907 }
1908 _ => {}
1909 }
1910 }
1911
1912 fn check_rustc_allow_const_fn_unstable(
1915 &self,
1916 hir_id: HirId,
1917 attr_span: Span,
1918 span: Span,
1919 target: Target,
1920 ) {
1921 match target {
1922 Target::Fn | Target::Method(_) => {
1923 if !self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) {
1924 self.tcx.dcx().emit_err(errors::RustcAllowConstFnUnstable { attr_span, span });
1925 }
1926 }
1927 _ => {}
1928 }
1929 }
1930
1931 fn check_stability(
1932 &self,
1933 attr_span: Span,
1934 item_span: Span,
1935 level: &StabilityLevel,
1936 feature: Symbol,
1937 ) {
1938 if level.is_unstable()
1941 && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some()
1942 {
1943 self.tcx
1944 .dcx()
1945 .emit_err(errors::UnstableAttrForAlreadyStableFeature { attr_span, item_span });
1946 }
1947 }
1948
1949 fn check_deprecated(&self, hir_id: HirId, attr_span: Span, target: Target) {
1950 match target {
1951 Target::AssocConst | Target::Method(..) | Target::AssocTy
1952 if matches!(
1953 self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)),
1954 DefKind::Impl { of_trait: true }
1955 ) =>
1956 {
1957 self.tcx.emit_node_span_lint(
1958 UNUSED_ATTRIBUTES,
1959 hir_id,
1960 attr_span,
1961 errors::DeprecatedAnnotationHasNoEffect { span: attr_span },
1962 );
1963 }
1964 _ => {}
1965 }
1966 }
1967
1968 fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) {
1969 if target != Target::MacroDef {
1970 return;
1971 }
1972
1973 let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
1975 let is_decl_macro = !macro_definition.macro_rules;
1976
1977 if is_decl_macro {
1978 self.tcx.emit_node_span_lint(
1979 UNUSED_ATTRIBUTES,
1980 hir_id,
1981 attr_span,
1982 errors::MacroExport::OnDeclMacro,
1983 );
1984 }
1985 }
1986
1987 fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
1988 let note = if attr.has_any_name(&[
1991 sym::allow,
1992 sym::expect,
1993 sym::warn,
1994 sym::deny,
1995 sym::forbid,
1996 sym::feature,
1997 ]) && attr.meta_item_list().is_some_and(|list| list.is_empty())
1998 {
1999 errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
2000 } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
2001 && let Some(meta) = attr.meta_item_list()
2002 && let [meta] = meta.as_slice()
2003 && let Some(item) = meta.meta_item()
2004 && let MetaItemKind::NameValue(_) = &item.kind
2005 && item.path == sym::reason
2006 {
2007 errors::UnusedNote::NoLints { name: attr.name().unwrap() }
2008 } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
2009 && let Some(meta) = attr.meta_item_list()
2010 && meta.iter().any(|meta| {
2011 meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
2012 })
2013 {
2014 if hir_id != CRATE_HIR_ID {
2015 match style {
2016 Some(ast::AttrStyle::Outer) => {
2017 let attr_span = attr.span();
2018 let bang_position = self
2019 .tcx
2020 .sess
2021 .source_map()
2022 .span_until_char(attr_span, '[')
2023 .shrink_to_hi();
2024
2025 self.tcx.emit_node_span_lint(
2026 UNUSED_ATTRIBUTES,
2027 hir_id,
2028 attr_span,
2029 errors::OuterCrateLevelAttr {
2030 suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position },
2031 },
2032 )
2033 }
2034 Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
2035 UNUSED_ATTRIBUTES,
2036 hir_id,
2037 attr.span(),
2038 errors::InnerCrateLevelAttr,
2039 ),
2040 };
2041 return;
2042 } else {
2043 let never_needs_link = self
2044 .tcx
2045 .crate_types()
2046 .iter()
2047 .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib));
2048 if never_needs_link {
2049 errors::UnusedNote::LinkerMessagesBinaryCrateOnly
2050 } else {
2051 return;
2052 }
2053 }
2054 } else if attr.has_name(sym::default_method_body_is_const) {
2055 errors::UnusedNote::DefaultMethodBodyConst
2056 } else {
2057 return;
2058 };
2059
2060 self.tcx.emit_node_span_lint(
2061 UNUSED_ATTRIBUTES,
2062 hir_id,
2063 attr.span(),
2064 errors::Unused { attr_span: attr.span(), note },
2065 );
2066 }
2067
2068 fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
2072 if target != Target::Fn {
2073 return;
2074 }
2075
2076 let tcx = self.tcx;
2077 let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else {
2078 return;
2079 };
2080 let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else {
2081 return;
2082 };
2083
2084 let def_id = hir_id.expect_owner().def_id;
2085 let param_env = ty::ParamEnv::empty();
2086
2087 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
2088 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
2089
2090 let span = tcx.def_span(def_id);
2091 let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id());
2092 let sig = tcx.liberate_late_bound_regions(
2093 def_id.to_def_id(),
2094 tcx.fn_sig(def_id).instantiate(tcx, fresh_args),
2095 );
2096
2097 let mut cause = ObligationCause::misc(span, def_id);
2098 let sig = ocx.normalize(&cause, param_env, sig);
2099
2100 let errors = ocx.try_evaluate_obligations();
2102 if !errors.is_empty() {
2103 return;
2104 }
2105
2106 let expected_sig = tcx.mk_fn_sig(
2107 std::iter::repeat_n(
2108 token_stream,
2109 match kind {
2110 ProcMacroKind::Attribute => 2,
2111 ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
2112 },
2113 ),
2114 token_stream,
2115 false,
2116 Safety::Safe,
2117 ExternAbi::Rust,
2118 );
2119
2120 if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
2121 let mut diag = tcx.dcx().create_err(errors::ProcMacroBadSig { span, kind });
2122
2123 let hir_sig = tcx.hir_fn_sig_by_hir_id(hir_id);
2124 if let Some(hir_sig) = hir_sig {
2125 #[allow(rustc::diagnostic_outside_of_impl)] match terr {
2127 TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
2128 if let Some(ty) = hir_sig.decl.inputs.get(idx) {
2129 diag.span(ty.span);
2130 cause.span = ty.span;
2131 } else if idx == hir_sig.decl.inputs.len() {
2132 let span = hir_sig.decl.output.span();
2133 diag.span(span);
2134 cause.span = span;
2135 }
2136 }
2137 TypeError::ArgCount => {
2138 if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
2139 diag.span(ty.span);
2140 cause.span = ty.span;
2141 }
2142 }
2143 TypeError::SafetyMismatch(_) => {
2144 }
2146 TypeError::AbiMismatch(_) => {
2147 }
2149 TypeError::VariadicMismatch(_) => {
2150 }
2152 _ => {}
2153 }
2154 }
2155
2156 infcx.err_ctxt().note_type_err(
2157 &mut diag,
2158 &cause,
2159 None,
2160 Some(param_env.and(ValuePairs::PolySigs(ExpectedFound {
2161 expected: ty::Binder::dummy(expected_sig),
2162 found: ty::Binder::dummy(sig),
2163 }))),
2164 terr,
2165 false,
2166 None,
2167 );
2168 diag.emit();
2169 self.abort.set(true);
2170 }
2171
2172 let errors = ocx.evaluate_obligations_error_on_ambiguity();
2173 if !errors.is_empty() {
2174 infcx.err_ctxt().report_fulfillment_errors(errors);
2175 self.abort.set(true);
2176 }
2177 }
2178
2179 fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) {
2180 if !find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent))
2181 .unwrap_or(false)
2182 {
2183 self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span });
2184 }
2185 }
2186
2187 fn check_rustc_force_inline(&self, hir_id: HirId, attrs: &[Attribute], target: Target) {
2188 if let (Target::Closure, None) = (
2189 target,
2190 find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span),
2191 ) {
2192 let is_coro = matches!(
2193 self.tcx.hir_expect_expr(hir_id).kind,
2194 hir::ExprKind::Closure(hir::Closure {
2195 kind: hir::ClosureKind::Coroutine(..) | hir::ClosureKind::CoroutineClosure(..),
2196 ..
2197 })
2198 );
2199 let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id();
2200 let parent_span = self.tcx.def_span(parent_did);
2201
2202 if let Some(attr_span) = find_attr!(
2203 self.tcx.get_all_attrs(parent_did),
2204 AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span
2205 ) && is_coro
2206 {
2207 self.dcx().emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span });
2208 }
2209 }
2210 }
2211
2212 fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) {
2213 if let Some(export_name_span) = find_attr!(attrs, AttributeKind::ExportName { span: export_name_span, .. } => *export_name_span)
2214 && let Some(no_mangle_span) =
2215 find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
2216 {
2217 let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 {
2218 "#[unsafe(no_mangle)]"
2219 } else {
2220 "#[no_mangle]"
2221 };
2222 let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 {
2223 "#[unsafe(export_name)]"
2224 } else {
2225 "#[export_name]"
2226 };
2227
2228 self.tcx.emit_node_span_lint(
2229 lint::builtin::UNUSED_ATTRIBUTES,
2230 hir_id,
2231 no_mangle_span,
2232 errors::MixedExportNameAndNoMangle {
2233 no_mangle_span,
2234 export_name_span,
2235 no_mangle_attr,
2236 export_name_attr,
2237 },
2238 );
2239 }
2240 }
2241
2242 fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) {
2244 debug!("check_autodiff");
2245 match target {
2246 Target::Fn => {}
2247 _ => {
2248 self.dcx().emit_err(errors::AutoDiffAttr { attr_span: span });
2249 self.abort.set(true);
2250 }
2251 }
2252 }
2253
2254 fn check_loop_match(&self, hir_id: HirId, attr_span: Span, target: Target) {
2255 let node_span = self.tcx.hir_span(hir_id);
2256
2257 if !matches!(target, Target::Expression) {
2258 return; }
2260
2261 if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Loop(..)) {
2262 self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span });
2263 };
2264 }
2265
2266 fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) {
2267 let node_span = self.tcx.hir_span(hir_id);
2268
2269 if !matches!(target, Target::Expression) {
2270 return; }
2272
2273 if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Break(..)) {
2274 self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
2275 };
2276 }
2277
2278 fn check_custom_mir(
2279 &self,
2280 dialect: Option<(MirDialect, Span)>,
2281 phase: Option<(MirPhase, Span)>,
2282 attr_span: Span,
2283 ) {
2284 let Some((dialect, dialect_span)) = dialect else {
2285 if let Some((_, phase_span)) = phase {
2286 self.dcx()
2287 .emit_err(errors::CustomMirPhaseRequiresDialect { attr_span, phase_span });
2288 }
2289 return;
2290 };
2291
2292 match dialect {
2293 MirDialect::Analysis => {
2294 if let Some((MirPhase::Optimized, phase_span)) = phase {
2295 self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
2296 dialect,
2297 phase: MirPhase::Optimized,
2298 attr_span,
2299 dialect_span,
2300 phase_span,
2301 });
2302 }
2303 }
2304
2305 MirDialect::Built => {
2306 if let Some((phase, phase_span)) = phase {
2307 self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
2308 dialect,
2309 phase,
2310 attr_span,
2311 dialect_span,
2312 phase_span,
2313 });
2314 }
2315 }
2316 MirDialect::Runtime => {}
2317 }
2318 }
2319}
2320
2321impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
2322 type NestedFilter = nested_filter::OnlyBodies;
2323
2324 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
2325 self.tcx
2326 }
2327
2328 fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
2329 if let ItemKind::Macro(_, macro_def, _) = item.kind {
2333 let def_id = item.owner_id.to_def_id();
2334 if macro_def.macro_rules
2335 && !find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. })
2336 {
2337 check_non_exported_macro_for_invalid_attrs(self.tcx, item);
2338 }
2339 }
2340
2341 let target = Target::from_item(item);
2342 self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
2343 intravisit::walk_item(self, item)
2344 }
2345
2346 fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<'tcx>) {
2347 const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace];
2352 let spans = self
2353 .tcx
2354 .hir_attrs(where_predicate.hir_id)
2355 .iter()
2356 .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym)))
2357 .filter(|attr| !attr.is_parsed_attr())
2358 .map(|attr| attr.span())
2359 .collect::<Vec<_>>();
2360 if !spans.is_empty() {
2361 self.tcx.dcx().emit_err(errors::UnsupportedAttributesInWhere { span: spans.into() });
2362 }
2363 self.check_attributes(
2364 where_predicate.hir_id,
2365 where_predicate.span,
2366 Target::WherePredicate,
2367 None,
2368 );
2369 intravisit::walk_where_predicate(self, where_predicate)
2370 }
2371
2372 fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
2373 let target = Target::from_generic_param(generic_param);
2374 self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
2375 intravisit::walk_generic_param(self, generic_param)
2376 }
2377
2378 fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
2379 let target = Target::from_trait_item(trait_item);
2380 self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
2381 intravisit::walk_trait_item(self, trait_item)
2382 }
2383
2384 fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
2385 self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
2386 intravisit::walk_field_def(self, struct_field);
2387 }
2388
2389 fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
2390 self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
2391 intravisit::walk_arm(self, arm);
2392 }
2393
2394 fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
2395 let target = Target::from_foreign_item(f_item);
2396 self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
2397 intravisit::walk_foreign_item(self, f_item)
2398 }
2399
2400 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
2401 let target = target_from_impl_item(self.tcx, impl_item);
2402 self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
2403 intravisit::walk_impl_item(self, impl_item)
2404 }
2405
2406 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
2407 if let hir::StmtKind::Let(l) = stmt.kind {
2409 self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
2410 }
2411 intravisit::walk_stmt(self, stmt)
2412 }
2413
2414 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
2415 let target = match expr.kind {
2416 hir::ExprKind::Closure { .. } => Target::Closure,
2417 _ => Target::Expression,
2418 };
2419
2420 self.check_attributes(expr.hir_id, expr.span, target, None);
2421 intravisit::walk_expr(self, expr)
2422 }
2423
2424 fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
2425 self.check_attributes(field.hir_id, field.span, Target::ExprField, None);
2426 intravisit::walk_expr_field(self, field)
2427 }
2428
2429 fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
2430 self.check_attributes(variant.hir_id, variant.span, Target::Variant, None);
2431 intravisit::walk_variant(self, variant)
2432 }
2433
2434 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
2435 self.check_attributes(param.hir_id, param.span, Target::Param, None);
2436
2437 intravisit::walk_param(self, param);
2438 }
2439
2440 fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
2441 self.check_attributes(field.hir_id, field.span, Target::PatField, None);
2442 intravisit::walk_pat_field(self, field);
2443 }
2444}
2445
2446fn is_c_like_enum(item: &Item<'_>) -> bool {
2447 if let ItemKind::Enum(_, _, ref def) = item.kind {
2448 for variant in def.variants {
2449 match variant.data {
2450 hir::VariantData::Unit(..) => { }
2451 _ => return false,
2452 }
2453 }
2454 true
2455 } else {
2456 false
2457 }
2458}
2459
2460fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
2463 const ATTRS_TO_CHECK: &[Symbol] =
2467 &[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench];
2468
2469 for attr in attrs {
2470 let (span, name) = if let Some(a) =
2472 ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check))
2473 {
2474 (attr.span(), *a)
2475 } else if let Attribute::Parsed(AttributeKind::Repr {
2476 reprs: _,
2477 first_span: first_attr_span,
2478 }) = attr
2479 {
2480 (*first_attr_span, sym::repr)
2481 } else {
2482 continue;
2483 };
2484
2485 let item = tcx
2486 .hir_free_items()
2487 .map(|id| tcx.hir_item(id))
2488 .find(|item| !item.span.is_dummy()) .map(|item| errors::ItemFollowingInnerAttr {
2490 span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span },
2491 kind: tcx.def_descr(item.owner_id.to_def_id()),
2492 });
2493 let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {
2494 span,
2495 sugg_span: tcx
2496 .sess
2497 .source_map()
2498 .span_to_snippet(span)
2499 .ok()
2500 .filter(|src| src.starts_with("#!["))
2501 .map(|_| span.with_lo(span.lo() + BytePos(1)).with_hi(span.lo() + BytePos(2))),
2502 name,
2503 item,
2504 });
2505
2506 if let Attribute::Unparsed(p) = attr {
2507 tcx.dcx().try_steal_replace_and_emit_err(
2508 p.path.span,
2509 StashKey::UndeterminedMacroResolution,
2510 err,
2511 );
2512 } else {
2513 err.emit();
2514 }
2515 }
2516}
2517
2518fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
2519 let attrs = tcx.hir_attrs(item.hir_id());
2520
2521 if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span)
2522 {
2523 tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span });
2524 }
2525}
2526
2527fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
2528 let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
2529 tcx.hir_visit_item_likes_in_module(module_def_id, check_attr_visitor);
2530 if module_def_id.to_local_def_id().is_top_level_module() {
2531 check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
2532 check_invalid_crate_level_attr(tcx, tcx.hir_krate_attrs());
2533 }
2534 if check_attr_visitor.abort.get() {
2535 tcx.dcx().abort_if_errors()
2536 }
2537}
2538
2539pub(crate) fn provide(providers: &mut Providers) {
2540 *providers = Providers { check_mod_attrs, ..*providers };
2541}
2542
2543fn check_duplicates(
2545 tcx: TyCtxt<'_>,
2546 attr_span: Span,
2547 attr: &Attribute,
2548 hir_id: HirId,
2549 duplicates: AttributeDuplicates,
2550 seen: &mut FxHashMap<Symbol, Span>,
2551) {
2552 use AttributeDuplicates::*;
2553 if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
2554 return;
2555 }
2556 let attr_name = attr.name().unwrap();
2557 match duplicates {
2558 DuplicatesOk => {}
2559 WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
2560 match seen.entry(attr_name) {
2561 Entry::Occupied(mut entry) => {
2562 let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
2563 let to_remove = entry.insert(attr_span);
2564 (to_remove, attr_span)
2565 } else {
2566 (attr_span, *entry.get())
2567 };
2568 tcx.emit_node_span_lint(
2569 UNUSED_ATTRIBUTES,
2570 hir_id,
2571 this,
2572 errors::UnusedDuplicate {
2573 this,
2574 other,
2575 warning: matches!(
2576 duplicates,
2577 FutureWarnFollowing | FutureWarnPreceding
2578 ),
2579 },
2580 );
2581 }
2582 Entry::Vacant(entry) => {
2583 entry.insert(attr_span);
2584 }
2585 }
2586 }
2587 ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
2588 Entry::Occupied(mut entry) => {
2589 let (this, other) = if matches!(duplicates, ErrorPreceding) {
2590 let to_remove = entry.insert(attr_span);
2591 (to_remove, attr_span)
2592 } else {
2593 (attr_span, *entry.get())
2594 };
2595 tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
2596 }
2597 Entry::Vacant(entry) => {
2598 entry.insert(attr_span);
2599 }
2600 },
2601 }
2602}
2603
2604fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
2605 matches!(&self_ty.kind, hir::TyKind::Tup([_]))
2606 || if let hir::TyKind::FnPtr(fn_ptr_ty) = &self_ty.kind {
2607 fn_ptr_ty.decl.inputs.len() == 1
2608 } else {
2609 false
2610 }
2611 || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind
2612 && let Some(&[hir::GenericArg::Type(ty)]) =
2613 path.segments.last().map(|last| last.args().args)
2614 {
2615 doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
2616 } else {
2617 false
2618 })
2619}