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