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