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