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