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