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