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