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