]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_passes/src/check_attr.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_passes / src / check_attr.rs
CommitLineData
041b39d2
XL
1//! This module implements some validity checks for attributes.
2//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
3//! attached to items that actually support them and if there are
4//! conflicts between multiple such attributes attached to the same
5//! item.
6
2b03887a
FG
7use crate::errors::{
8 self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
9 OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
10};
487cf647 11use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
3c0e092e 12use rustc_data_structures::fx::FxHashMap;
2b03887a 13use rustc_errors::{fluent, Applicability, MultiSpan};
923072b8 14use rustc_expand::base::resolve_path;
3c0e092e 15use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
dfeec247 16use rustc_hir as hir;
2b03887a 17use rustc_hir::def_id::LocalDefId;
5099ac24 18use rustc_hir::intravisit::{self, Visitor};
2b03887a
FG
19use rustc_hir::{
20 self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
21};
74b04a01 22use rustc_hir::{MethodKind, Target};
5099ac24 23use rustc_middle::hir::nested_filter;
f2b60f7d 24use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
5099ac24
FG
25use rustc_middle::ty::query::Providers;
26use rustc_middle::ty::TyCtxt;
6a06907d
XL
27use rustc_session::lint::builtin::{
28 CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
29};
74b04a01 30use rustc_session::parse::feature_err;
04454e1e
FG
31use rustc_span::symbol::{kw, sym, Symbol};
32use rustc_span::{Span, DUMMY_SP};
923072b8 33use rustc_target::spec::abi::Abi;
3c0e092e 34use std::collections::hash_map::Entry;
b039eaaf 35
f035d41b
XL
36pub(crate) fn target_from_impl_item<'tcx>(
37 tcx: TyCtxt<'tcx>,
38 impl_item: &hir::ImplItem<'_>,
39) -> Target {
74b04a01
XL
40 match impl_item.kind {
41 hir::ImplItemKind::Const(..) => Target::AssocConst,
ba9703b0 42 hir::ImplItemKind::Fn(..) => {
2b03887a
FG
43 let parent_def_id = tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
44 let containing_item = tcx.hir().expect_item(parent_def_id);
74b04a01 45 let containing_impl_is_for_trait = match &containing_item.kind {
5869c6ff 46 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
74b04a01
XL
47 _ => bug!("parent of an ImplItem must be an Impl"),
48 };
49 if containing_impl_is_for_trait {
e74abb32 50 Target::Method(MethodKind::Trait { body: true })
74b04a01
XL
51 } else {
52 Target::Method(MethodKind::Inherent)
e74abb32 53 }
b039eaaf 54 }
2b03887a 55 hir::ImplItemKind::Type(..) => Target::AssocTy,
b039eaaf
SL
56 }
57}
58
1b1a35ee
XL
59#[derive(Clone, Copy)]
60enum ItemLike<'tcx> {
61 Item(&'tcx Item<'tcx>),
064997fb 62 ForeignItem,
1b1a35ee
XL
63}
64
dc9dc135
XL
65struct CheckAttrVisitor<'tcx> {
66 tcx: TyCtxt<'tcx>,
b039eaaf
SL
67}
68
a2a8927a 69impl CheckAttrVisitor<'_> {
9fa01778 70 /// Checks any attribute.
e74abb32
XL
71 fn check_attributes(
72 &self,
73 hir_id: HirId,
5099ac24 74 span: Span,
e74abb32 75 target: Target,
1b1a35ee 76 item: Option<ItemLike<'_>>,
e74abb32 77 ) {
c295e0f8 78 let mut doc_aliases = FxHashMap::default();
e74abb32 79 let mut is_valid = true;
17df50a5 80 let mut specified_inline = None;
3c0e092e 81 let mut seen = FxHashMap::default();
6a06907d 82 let attrs = self.tcx.hir().attrs(hir_id);
e74abb32 83 for attr in attrs {
94222f64 84 let attr_is_valid = match attr.name_or_empty() {
cdc7bbd5 85 sym::inline => self.check_inline(hir_id, attr, span, target),
923072b8 86 sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
cdc7bbd5
XL
87 sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
88 sym::marker => self.check_marker(hir_id, attr, span, target),
5099ac24
FG
89 sym::rustc_must_implement_one_of => {
90 self.check_rustc_must_implement_one_of(attr, span, target)
91 }
cdc7bbd5 92 sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
04454e1e 93 sym::thread_local => self.check_thread_local(attr, span, target),
cdc7bbd5 94 sym::track_caller => {
5099ac24 95 self.check_track_caller(hir_id, attr.span, attrs, span, target)
1b1a35ee 96 }
c295e0f8
XL
97 sym::doc => self.check_doc_attrs(
98 attr,
99 hir_id,
100 target,
101 &mut specified_inline,
102 &mut doc_aliases,
103 ),
cdc7bbd5
XL
104 sym::no_link => self.check_no_link(hir_id, &attr, span, target),
105 sym::export_name => self.check_export_name(hir_id, &attr, span, target),
cdc7bbd5
XL
106 sym::rustc_layout_scalar_valid_range_start
107 | sym::rustc_layout_scalar_valid_range_end => {
108 self.check_rustc_layout_scalar_valid_range(&attr, span, target)
109 }
110 sym::allow_internal_unstable => {
111 self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
112 }
04454e1e 113 sym::debugger_visualizer => self.check_debugger_visualizer(&attr, target),
cdc7bbd5
XL
114 sym::rustc_allow_const_fn_unstable => {
115 self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
116 }
04454e1e
FG
117 sym::rustc_std_internal_symbol => {
118 self.check_rustc_std_internal_symbol(&attr, span, target)
119 }
cdc7bbd5
XL
120 sym::naked => self.check_naked(hir_id, attr, span, target),
121 sym::rustc_legacy_const_generics => {
487cf647 122 self.check_rustc_legacy_const_generics(hir_id, &attr, span, target, item)
cdc7bbd5 123 }
5099ac24 124 sym::rustc_lint_query_instability => {
487cf647 125 self.check_rustc_lint_query_instability(hir_id, &attr, span, target)
5099ac24 126 }
923072b8 127 sym::rustc_lint_diagnostics => {
487cf647 128 self.check_rustc_lint_diagnostics(hir_id, &attr, span, target)
923072b8 129 }
064997fb
FG
130 sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(&attr, span, target),
131 sym::rustc_lint_opt_deny_field_access => {
132 self.check_rustc_lint_opt_deny_field_access(&attr, span, target)
133 }
cdc7bbd5
XL
134 sym::rustc_clean
135 | sym::rustc_dirty
136 | sym::rustc_if_this_changed
137 | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
487cf647
FG
138 sym::cmse_nonsecure_entry => {
139 self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
140 }
f2b60f7d 141 sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
923072b8 142 sym::const_trait => self.check_const_trait(attr, span, target),
c295e0f8 143 sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
487cf647 144 sym::must_use => self.check_must_use(hir_id, &attr, target),
5099ac24 145 sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
5e7ed085
FG
146 sym::rustc_allow_incoherent_impl => {
147 self.check_allow_incoherent_impl(&attr, span, target)
148 }
04454e1e
FG
149 sym::rustc_has_incoherent_inherent_impls => {
150 self.check_has_incoherent_inherent_impls(&attr, span, target)
151 }
94222f64
XL
152 sym::rustc_const_unstable
153 | sym::rustc_const_stable
154 | sym::unstable
155 | sym::stable
064997fb 156 | sym::rustc_allowed_through_unstable_modules
94222f64 157 | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
f2b60f7d 158 sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
cdc7bbd5 159 _ => true,
e74abb32 160 };
94222f64
XL
161 is_valid &= attr_is_valid;
162
cdc7bbd5
XL
163 // lint-only checks
164 match attr.name_or_empty() {
165 sym::cold => self.check_cold(hir_id, attr, span, target),
5099ac24 166 sym::link => self.check_link(hir_id, attr, span, target),
cdc7bbd5
XL
167 sym::link_name => self.check_link_name(hir_id, attr, span, target),
168 sym::link_section => self.check_link_section(hir_id, attr, span, target),
169 sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
923072b8 170 sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
94222f64 171 sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
2b03887a 172 sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
94222f64
XL
173 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
174 sym::macro_export => self.check_macro_export(hir_id, attr, target),
175 sym::ignore | sym::should_panic | sym::proc_macro_derive => {
2b03887a 176 self.check_generic_attr(hir_id, attr, target, Target::Fn)
94222f64
XL
177 }
178 sym::automatically_derived => {
2b03887a 179 self.check_generic_attr(hir_id, attr, target, Target::Impl)
94222f64
XL
180 }
181 sym::no_implicit_prelude => {
2b03887a 182 self.check_generic_attr(hir_id, attr, target, Target::Mod)
94222f64 183 }
f2b60f7d 184 sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
94222f64
XL
185 _ => {}
186 }
187
3c0e092e
XL
188 let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
189
94222f64 190 if hir_id != CRATE_HIR_ID {
3c0e092e 191 if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
94222f64
XL
192 attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
193 {
064997fb
FG
194 match attr.style {
195 ast::AttrStyle::Outer => self.tcx.emit_spanned_lint(
196 UNUSED_ATTRIBUTES,
197 hir_id,
198 attr.span,
199 errors::OuterCrateLevelAttr,
200 ),
201 ast::AttrStyle::Inner => self.tcx.emit_spanned_lint(
202 UNUSED_ATTRIBUTES,
203 hir_id,
204 attr.span,
205 errors::InnerCrateLevelAttr,
206 ),
207 }
94222f64
XL
208 }
209 }
210
3c0e092e
XL
211 if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
212 check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
213 }
214
5e7ed085 215 self.check_unused_attribute(hir_id, attr)
041b39d2 216 }
2c00a5a8 217
e74abb32
XL
218 if !is_valid {
219 return;
220 }
221
dfeec247 222 self.check_repr(attrs, span, target, item, hir_id);
e74abb32
XL
223 self.check_used(attrs, target);
224 }
225
5869c6ff 226 fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
064997fb
FG
227 self.tcx.emit_spanned_lint(
228 UNUSED_ATTRIBUTES,
229 hir_id,
230 attr.span,
231 errors::IgnoredAttrWithMacro { sym },
232 );
5869c6ff
XL
233 }
234
235 fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
064997fb
FG
236 self.tcx.emit_spanned_lint(
237 UNUSED_ATTRIBUTES,
238 hir_id,
239 attr.span,
240 errors::IgnoredAttr { sym },
241 );
5869c6ff
XL
242 }
243
e74abb32 244 /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
5099ac24 245 fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
e74abb32 246 match target {
dfeec247
XL
247 Target::Fn
248 | Target::Closure
ba9703b0 249 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
e74abb32 250 Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
064997fb
FG
251 self.tcx.emit_spanned_lint(
252 UNUSED_ATTRIBUTES,
253 hir_id,
254 attr.span,
255 errors::IgnoredInlineAttrFnProto,
256 );
e74abb32
XL
257 true
258 }
259 // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
260 // just a lint, because we previously erroneously allowed it and some crates used it
2b03887a 261 // accidentally, to be compatible with crates depending on them, we can't throw an
e74abb32
XL
262 // error here.
263 Target::AssocConst => {
064997fb
FG
264 self.tcx.emit_spanned_lint(
265 UNUSED_ATTRIBUTES,
266 hir_id,
267 attr.span,
268 errors::IgnoredInlineAttrConstants,
269 );
e74abb32
XL
270 true
271 }
5869c6ff
XL
272 // FIXME(#80564): Same for fields, arms, and macro defs
273 Target::Field | Target::Arm | Target::MacroDef => {
274 self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
275 true
276 }
e74abb32 277 _ => {
064997fb
FG
278 self.tcx.sess.emit_err(errors::InlineNotFnOrClosure {
279 attr_span: attr.span,
280 defn_span: span,
281 });
e74abb32
XL
282 false
283 }
284 }
041b39d2
XL
285 }
286
923072b8
FG
287 /// Checks if a `#[no_coverage]` is applied directly to a function
288 fn check_no_coverage(
289 &self,
290 hir_id: HirId,
291 attr: &Attribute,
292 span: Span,
293 target: Target,
294 ) -> bool {
295 match target {
296 // no_coverage on function is fine
297 Target::Fn
298 | Target::Closure
299 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
300
301 // function prototypes can't be covered
302 Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
064997fb
FG
303 self.tcx.emit_spanned_lint(
304 UNUSED_ATTRIBUTES,
305 hir_id,
306 attr.span,
307 errors::IgnoredNoCoverageFnProto,
308 );
923072b8
FG
309 true
310 }
311
312 Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
064997fb
FG
313 self.tcx.emit_spanned_lint(
314 UNUSED_ATTRIBUTES,
315 hir_id,
316 attr.span,
317 errors::IgnoredNoCoveragePropagate,
318 );
923072b8
FG
319 true
320 }
321
322 Target::Expression | Target::Statement | Target::Arm => {
064997fb
FG
323 self.tcx.emit_spanned_lint(
324 UNUSED_ATTRIBUTES,
325 hir_id,
326 attr.span,
327 errors::IgnoredNoCoverageFnDefn,
328 );
923072b8
FG
329 true
330 }
331
332 _ => {
064997fb
FG
333 self.tcx.sess.emit_err(errors::IgnoredNoCoverageNotCoverable {
334 attr_span: attr.span,
335 defn_span: span,
336 });
923072b8
FG
337 false
338 }
339 }
340 }
341
94222f64
XL
342 fn check_generic_attr(
343 &self,
344 hir_id: HirId,
345 attr: &Attribute,
346 target: Target,
2b03887a 347 allowed_target: Target,
94222f64 348 ) {
2b03887a
FG
349 if target != allowed_target {
350 self.tcx.emit_spanned_lint(
351 UNUSED_ATTRIBUTES,
352 hir_id,
353 attr.span,
354 OnlyHasEffectOn {
355 attr_name: attr.name_or_empty(),
487cf647 356 target_name: allowed_target.name().replace(' ', "_"),
2b03887a
FG
357 },
358 );
94222f64
XL
359 }
360 }
361
fc512014 362 /// Checks if `#[naked]` is applied to a function definition.
5099ac24 363 fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
fc512014
XL
364 match target {
365 Target::Fn
366 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
5869c6ff
XL
367 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
368 // `#[allow_internal_unstable]` attribute with just a lint, because we previously
2b03887a 369 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
370 // with crates depending on them, we can't throw an error here.
371 Target::Field | Target::Arm | Target::MacroDef => {
372 self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
373 true
374 }
fc512014 375 _ => {
064997fb
FG
376 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
377 attr_span: attr.span,
378 defn_span: span,
487cf647 379 on_crate: hir_id == CRATE_HIR_ID,
064997fb 380 });
fc512014
XL
381 false
382 }
383 }
384 }
385
136023e0 386 /// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition.
487cf647
FG
387 fn check_cmse_nonsecure_entry(
388 &self,
389 hir_id: HirId,
390 attr: &Attribute,
391 span: Span,
392 target: Target,
393 ) -> bool {
136023e0
XL
394 match target {
395 Target::Fn
396 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
397 _ => {
064997fb
FG
398 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
399 attr_span: attr.span,
400 defn_span: span,
487cf647 401 on_crate: hir_id == CRATE_HIR_ID,
064997fb 402 });
136023e0
XL
403 false
404 }
405 }
406 }
407
f2b60f7d
FG
408 /// Debugging aid for `object_lifetime_default` query.
409 fn check_object_lifetime_default(&self, hir_id: HirId) {
410 let tcx = self.tcx;
411 if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) {
412 for p in generics.params {
413 let hir::GenericParamKind::Type { .. } = p.kind else { continue };
487cf647 414 let default = tcx.object_lifetime_default(p.def_id);
f2b60f7d
FG
415 let repr = match default {
416 ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
417 ObjectLifetimeDefault::Static => "'static".to_owned(),
418 ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
419 ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
420 };
2b03887a 421 tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr });
f2b60f7d
FG
422 }
423 }
424 }
425
426 /// Checks if `#[collapse_debuginfo]` is applied to a macro.
427 fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) -> bool {
428 match target {
429 Target::MacroDef => true,
430 _ => {
431 self.tcx
432 .sess
433 .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
434 false
435 }
436 }
437 }
438
e74abb32
XL
439 /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
440 fn check_track_caller(
441 &self,
5869c6ff 442 hir_id: HirId,
5099ac24 443 attr_span: Span,
a2a8927a 444 attrs: &[Attribute],
5099ac24 445 span: Span,
e74abb32
XL
446 target: Target,
447 ) -> bool {
448 match target {
fc512014 449 _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
064997fb 450 self.tcx.sess.emit_err(errors::NakedTrackedCaller { attr_span });
e74abb32
XL
451 false
452 }
1b1a35ee 453 Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
5869c6ff
XL
454 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
455 // `#[track_caller]` attribute with just a lint, because we previously
2b03887a 456 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
457 // with crates depending on them, we can't throw an error here.
458 Target::Field | Target::Arm | Target::MacroDef => {
459 for attr in attrs {
460 self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
461 }
462 true
463 }
e74abb32 464 _ => {
487cf647
FG
465 self.tcx.sess.emit_err(errors::TrackedCallerWrongLocation {
466 attr_span,
467 defn_span: span,
468 on_crate: hir_id == CRATE_HIR_ID,
469 });
e74abb32
XL
470 false
471 }
83c7162d
XL
472 }
473 }
474
e74abb32 475 /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
5869c6ff
XL
476 fn check_non_exhaustive(
477 &self,
478 hir_id: HirId,
479 attr: &Attribute,
5099ac24 480 span: Span,
5869c6ff
XL
481 target: Target,
482 ) -> bool {
83c7162d 483 match target {
29967ef6 484 Target::Struct | Target::Enum | Target::Variant => true,
5869c6ff
XL
485 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
486 // `#[non_exhaustive]` attribute with just a lint, because we previously
2b03887a 487 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
488 // with crates depending on them, we can't throw an error here.
489 Target::Field | Target::Arm | Target::MacroDef => {
490 self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
491 true
492 }
83c7162d 493 _ => {
064997fb
FG
494 self.tcx.sess.emit_err(errors::NonExhaustiveWrongLocation {
495 attr_span: attr.span,
496 defn_span: span,
497 });
e74abb32 498 false
83c7162d
XL
499 }
500 }
b039eaaf
SL
501 }
502
e74abb32 503 /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
5099ac24 504 fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
0bf4aa26 505 match target {
e74abb32 506 Target::Trait => true,
5869c6ff
XL
507 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
508 // `#[marker]` attribute with just a lint, because we previously
2b03887a 509 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
510 // with crates depending on them, we can't throw an error here.
511 Target::Field | Target::Arm | Target::MacroDef => {
512 self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
513 true
514 }
0bf4aa26 515 _ => {
064997fb
FG
516 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
517 attr_span: attr.span,
518 defn_span: span,
519 });
5099ac24
FG
520 false
521 }
522 }
523 }
524
525 /// Checks if the `#[rustc_must_implement_one_of]` attribute on a `target` is valid. Returns `true` if valid.
526 fn check_rustc_must_implement_one_of(
527 &self,
528 attr: &Attribute,
529 span: Span,
530 target: Target,
531 ) -> bool {
532 match target {
533 Target::Trait => true,
534 _ => {
064997fb
FG
535 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
536 attr_span: attr.span,
537 defn_span: span,
538 });
e74abb32 539 false
0bf4aa26
XL
540 }
541 }
0bf4aa26
XL
542 }
543
e74abb32 544 /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
1b1a35ee
XL
545 fn check_target_feature(
546 &self,
547 hir_id: HirId,
548 attr: &Attribute,
5099ac24 549 span: Span,
1b1a35ee
XL
550 target: Target,
551 ) -> bool {
e74abb32 552 match target {
dfeec247 553 Target::Fn
ba9703b0 554 | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
1b1a35ee
XL
555 // FIXME: #[target_feature] was previously erroneously allowed on statements and some
556 // crates used this, so only emit a warning.
557 Target::Statement => {
064997fb
FG
558 self.tcx.emit_spanned_lint(
559 UNUSED_ATTRIBUTES,
560 hir_id,
561 attr.span,
562 errors::TargetFeatureOnStatement,
563 );
1b1a35ee
XL
564 true
565 }
5869c6ff
XL
566 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
567 // `#[target_feature]` attribute with just a lint, because we previously
2b03887a 568 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
569 // with crates depending on them, we can't throw an error here.
570 Target::Field | Target::Arm | Target::MacroDef => {
571 self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
572 true
573 }
e74abb32 574 _ => {
064997fb
FG
575 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
576 attr_span: attr.span,
577 defn_span: span,
487cf647 578 on_crate: hir_id == CRATE_HIR_ID,
064997fb 579 });
e74abb32 580 false
dfeec247 581 }
e74abb32
XL
582 }
583 }
584
04454e1e
FG
585 /// Checks if the `#[thread_local]` attribute on `item` is valid. Returns `true` if valid.
586 fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) -> bool {
587 match target {
588 Target::ForeignStatic | Target::Static => true,
589 _ => {
064997fb
FG
590 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToStatic {
591 attr_span: attr.span,
592 defn_span: span,
593 });
04454e1e
FG
594 false
595 }
596 }
597 }
598
fc512014 599 fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) {
064997fb 600 self.tcx.sess.emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
1b1a35ee
XL
601 }
602
6a06907d
XL
603 fn check_doc_alias_value(
604 &self,
605 meta: &NestedMetaItem,
04454e1e 606 doc_alias: Symbol,
6a06907d
XL
607 hir_id: HirId,
608 target: Target,
609 is_list: bool,
c295e0f8 610 aliases: &mut FxHashMap<String, Span>,
6a06907d
XL
611 ) -> bool {
612 let tcx = self.tcx;
064997fb
FG
613 let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
614 let attr_str =
615 &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
04454e1e 616 if doc_alias == kw::Empty {
064997fb
FG
617 tcx.sess.emit_err(errors::DocAliasEmpty { span, attr_str });
618 return false;
fc512014 619 }
04454e1e
FG
620
621 let doc_alias_str = doc_alias.as_str();
622 if let Some(c) = doc_alias_str
623 .chars()
624 .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
fc512014 625 {
064997fb 626 tcx.sess.emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
fc512014
XL
627 return false;
628 }
04454e1e 629 if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
064997fb
FG
630 tcx.sess.emit_err(errors::DocAliasStartEnd { span, attr_str });
631 return false;
fc512014 632 }
064997fb
FG
633
634 let span = meta.span();
635 if let Some(location) = match target {
fc512014 636 Target::AssocTy => {
2b03887a
FG
637 let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
638 let containing_item = self.tcx.hir().expect_item(parent_def_id);
fc512014
XL
639 if Target::from_item(containing_item) == Target::Impl {
640 Some("type alias in implementation block")
641 } else {
642 None
643 }
644 }
645 Target::AssocConst => {
2b03887a
FG
646 let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
647 let containing_item = self.tcx.hir().expect_item(parent_def_id);
fc512014
XL
648 // We can't link to trait impl's consts.
649 let err = "associated constant in trait implementation block";
650 match containing_item.kind {
5869c6ff 651 ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
fc512014
XL
652 _ => None,
653 }
654 }
136023e0
XL
655 // we check the validity of params elsewhere
656 Target::Param => return false,
064997fb
FG
657 Target::Expression
658 | Target::Statement
659 | Target::Arm
660 | Target::ForeignMod
661 | Target::Closure
662 | Target::Impl => Some(target.name()),
663 Target::ExternCrate
664 | Target::Use
665 | Target::Static
666 | Target::Const
667 | Target::Fn
668 | Target::Mod
669 | Target::GlobalAsm
670 | Target::TyAlias
671 | Target::OpaqueTy
f2b60f7d 672 | Target::ImplTraitPlaceholder
064997fb
FG
673 | Target::Enum
674 | Target::Variant
675 | Target::Struct
676 | Target::Field
677 | Target::Union
678 | Target::Trait
679 | Target::TraitAlias
680 | Target::Method(..)
681 | Target::ForeignFn
682 | Target::ForeignStatic
683 | Target::ForeignTy
684 | Target::GenericParam(..)
f2b60f7d
FG
685 | Target::MacroDef
686 | Target::PatField
687 | Target::ExprField => None,
fc512014 688 } {
064997fb
FG
689 tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
690 return false;
fc512014 691 }
5869c6ff 692 let item_name = self.tcx.hir().name(hir_id);
04454e1e 693 if item_name == doc_alias {
064997fb
FG
694 tcx.sess.emit_err(errors::DocAliasNotAnAlias { span, attr_str });
695 return false;
6a06907d 696 }
04454e1e 697 if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
064997fb
FG
698 self.tcx.emit_spanned_lint(
699 UNUSED_ATTRIBUTES,
700 hir_id,
701 span,
702 errors::DocAliasDuplicated { first_defn: *entry.entry.get() },
703 );
c295e0f8 704 }
6a06907d
XL
705 true
706 }
707
c295e0f8
XL
708 fn check_doc_alias(
709 &self,
710 meta: &NestedMetaItem,
711 hir_id: HirId,
712 target: Target,
713 aliases: &mut FxHashMap<String, Span>,
714 ) -> bool {
6a06907d
XL
715 if let Some(values) = meta.meta_item_list() {
716 let mut errors = 0;
717 for v in values {
487cf647 718 match v.lit() {
6a06907d
XL
719 Some(l) => match l.kind {
720 LitKind::Str(s, _) => {
04454e1e 721 if !self.check_doc_alias_value(v, s, hir_id, target, true, aliases) {
6a06907d
XL
722 errors += 1;
723 }
724 }
725 _ => {
726 self.tcx
727 .sess
064997fb 728 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
6a06907d
XL
729 errors += 1;
730 }
731 },
732 None => {
064997fb 733 self.tcx.sess.emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
6a06907d
XL
734 errors += 1;
735 }
736 }
737 }
738 errors == 0
04454e1e
FG
739 } else if let Some(doc_alias) = meta.value_str() {
740 self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
6a06907d 741 } else {
064997fb 742 self.tcx.sess.emit_err(errors::DocAliasMalformed { span: meta.span() });
6a06907d 743 false
5869c6ff 744 }
fc512014
XL
745 }
746
747 fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
04454e1e
FG
748 let doc_keyword = meta.value_str().unwrap_or(kw::Empty);
749 if doc_keyword == kw::Empty {
fc512014
XL
750 self.doc_attr_str_error(meta, "keyword");
751 return false;
752 }
136023e0
XL
753 match self.tcx.hir().find(hir_id).and_then(|node| match node {
754 hir::Node::Item(item) => Some(&item.kind),
755 _ => None,
756 }) {
757 Some(ItemKind::Mod(ref module)) => {
fc512014 758 if !module.item_ids.is_empty() {
064997fb 759 self.tcx.sess.emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
fc512014
XL
760 return false;
761 }
762 }
763 _ => {
064997fb 764 self.tcx.sess.emit_err(errors::DocKeywordNotMod { span: meta.span() });
fc512014
XL
765 return false;
766 }
767 }
04454e1e 768 if !rustc_lexer::is_ident(doc_keyword.as_str()) {
064997fb
FG
769 self.tcx.sess.emit_err(errors::DocKeywordInvalidIdent {
770 span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
771 doc_keyword,
772 });
fc512014
XL
773 return false;
774 }
775 true
776 }
777
064997fb 778 fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
923072b8
FG
779 match self.tcx.hir().find(hir_id).and_then(|node| match node {
780 hir::Node::Item(item) => Some(&item.kind),
781 _ => None,
782 }) {
783 Some(ItemKind::Impl(ref i)) => {
064997fb
FG
784 let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_]))
785 || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind {
786 bare_fn_ty.decl.inputs.len() == 1
787 } else {
788 false
789 };
790 if !is_valid {
791 self.tcx.sess.emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
923072b8
FG
792 return false;
793 }
794 }
795 _ => {
064997fb 796 self.tcx.sess.emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
923072b8
FG
797 return false;
798 }
799 }
800 true
801 }
802
17df50a5
XL
803 /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes. Returns `true` if valid.
804 ///
805 /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
806 /// if there are conflicting attributes for one item.
807 ///
808 /// `specified_inline` is used to keep track of whether we have
809 /// already seen an inlining attribute for this item.
810 /// If so, `specified_inline` holds the value and the span of
811 /// the first `inline`/`no_inline` attribute.
812 fn check_doc_inline(
813 &self,
814 attr: &Attribute,
815 meta: &NestedMetaItem,
816 hir_id: HirId,
817 target: Target,
818 specified_inline: &mut Option<(bool, Span)>,
819 ) -> bool {
820 if target == Target::Use || target == Target::ExternCrate {
821 let do_inline = meta.name_or_empty() == sym::inline;
822 if let Some((prev_inline, prev_span)) = *specified_inline {
823 if do_inline != prev_inline {
824 let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
2b03887a
FG
825 spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
826 spans.push_span_label(meta.span(), fluent::passes_doc_inline_conflict_second);
064997fb 827 self.tcx.sess.emit_err(errors::DocKeywordConflict { spans });
17df50a5
XL
828 return false;
829 }
830 true
831 } else {
832 *specified_inline = Some((do_inline, meta.span()));
833 true
834 }
835 } else {
064997fb 836 self.tcx.emit_spanned_lint(
17df50a5
XL
837 INVALID_DOC_ATTRIBUTES,
838 hir_id,
839 meta.span(),
064997fb
FG
840 errors::DocInlineOnlyUse {
841 attr_span: meta.span(),
842 item_span: (attr.style == AttrStyle::Outer)
843 .then(|| self.tcx.hir().span(hir_id)),
17df50a5
XL
844 },
845 );
846 false
847 }
848 }
849
850 /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
851 fn check_attr_not_crate_level(
fc512014
XL
852 &self,
853 meta: &NestedMetaItem,
854 hir_id: HirId,
855 attr_name: &str,
856 ) -> bool {
857 if CRATE_HIR_ID == hir_id {
064997fb 858 self.tcx.sess.emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
fc512014
XL
859 return false;
860 }
861 true
862 }
863
17df50a5
XL
864 /// Checks that an attribute is used at the crate level. Returns `true` if valid.
865 fn check_attr_crate_level(
866 &self,
867 attr: &Attribute,
868 meta: &NestedMetaItem,
869 hir_id: HirId,
870 ) -> bool {
871 if hir_id != CRATE_HIR_ID {
2b03887a
FG
872 self.tcx.struct_span_lint_hir(
873 INVALID_DOC_ATTRIBUTES,
874 hir_id,
875 meta.span(),
876 fluent::passes_attr_crate_level,
877 |err| {
878 if attr.style == AttrStyle::Outer
879 && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
880 {
881 if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
882 src.insert(1, '!');
883 err.span_suggestion_verbose(
884 attr.span,
885 fluent::suggestion,
886 src,
887 Applicability::MaybeIncorrect,
888 );
889 } else {
890 err.span_help(attr.span, fluent::help);
891 }
17df50a5 892 }
2b03887a
FG
893 err.note(fluent::note);
894 err
895 },
896 );
17df50a5
XL
897 return false;
898 }
899 true
900 }
901
94222f64
XL
902 /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if
903 /// valid.
904 fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
905 let mut is_valid = true;
906 if let Some(metas) = meta.meta_item_list() {
907 for i_meta in metas {
908 match i_meta.name_or_empty() {
909 sym::attr | sym::no_crate_inject => {}
910 _ => {
064997fb 911 self.tcx.emit_spanned_lint(
94222f64
XL
912 INVALID_DOC_ATTRIBUTES,
913 hir_id,
914 i_meta.span(),
064997fb
FG
915 errors::DocTestUnknown {
916 path: rustc_ast_pretty::pprust::path_to_string(
917 &i_meta.meta_item().unwrap().path,
918 ),
94222f64
XL
919 },
920 );
921 is_valid = false;
922 }
923 }
924 }
925 } else {
064997fb
FG
926 self.tcx.emit_spanned_lint(
927 INVALID_DOC_ATTRIBUTES,
928 hir_id,
929 meta.span(),
930 errors::DocTestTakesList,
931 );
94222f64
XL
932 is_valid = false;
933 }
934 is_valid
935 }
936
2b03887a
FG
937 /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
938 /// Returns `true` if valid.
939 fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
940 if meta.meta_item_list().is_some() {
941 true
942 } else {
943 self.tcx.emit_spanned_lint(
944 INVALID_DOC_ATTRIBUTES,
945 hir_id,
946 meta.span(),
947 errors::DocCfgHideTakesList,
948 );
949 false
950 }
951 }
952
17df50a5
XL
953 /// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
954 ///
955 /// `specified_inline` should be initialized to `None` and kept for the scope
956 /// of one item. Read the documentation of [`check_doc_inline`] for more information.
957 ///
958 /// [`check_doc_inline`]: Self::check_doc_inline
959 fn check_doc_attrs(
960 &self,
961 attr: &Attribute,
962 hir_id: HirId,
963 target: Target,
964 specified_inline: &mut Option<(bool, Span)>,
c295e0f8 965 aliases: &mut FxHashMap<String, Span>,
17df50a5 966 ) -> bool {
6a06907d
XL
967 let mut is_valid = true;
968
04454e1e
FG
969 if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
970 for meta in list {
6a06907d
XL
971 if let Some(i_meta) = meta.meta_item() {
972 match i_meta.name_or_empty() {
973 sym::alias
04454e1e
FG
974 if !self.check_attr_not_crate_level(meta, hir_id, "alias")
975 || !self.check_doc_alias(meta, hir_id, target, aliases) =>
3dfed10e 976 {
6a06907d 977 is_valid = false
29967ef6 978 }
6a06907d
XL
979
980 sym::keyword
04454e1e
FG
981 if !self.check_attr_not_crate_level(meta, hir_id, "keyword")
982 || !self.check_doc_keyword(meta, hir_id) =>
fc512014 983 {
6a06907d
XL
984 is_valid = false
985 }
986
064997fb
FG
987 sym::fake_variadic
988 if !self.check_attr_not_crate_level(meta, hir_id, "fake_variadic")
989 || !self.check_doc_fake_variadic(meta, hir_id) =>
923072b8
FG
990 {
991 is_valid = false
992 }
993
17df50a5
XL
994 sym::html_favicon_url
995 | sym::html_logo_url
996 | sym::html_playground_url
997 | sym::issue_tracker_base_url
998 | sym::html_root_url
999 | sym::html_no_source
1000 | sym::test
04454e1e 1001 if !self.check_attr_crate_level(attr, meta, hir_id) =>
17df50a5
XL
1002 {
1003 is_valid = false;
1004 }
1005
2b03887a
FG
1006 sym::cfg_hide
1007 if !self.check_attr_crate_level(attr, meta, hir_id)
1008 || !self.check_doc_cfg_hide(meta, hir_id) =>
1009 {
1010 is_valid = false;
1011 }
1012
17df50a5
XL
1013 sym::inline | sym::no_inline
1014 if !self.check_doc_inline(
04454e1e
FG
1015 attr,
1016 meta,
6a06907d 1017 hir_id,
17df50a5
XL
1018 target,
1019 specified_inline,
1020 ) =>
1021 {
6a06907d
XL
1022 is_valid = false;
1023 }
1024
1025 // no_default_passes: deprecated
1026 // passes: deprecated
1027 // plugins: removed, but rustdoc warns about it itself
1028 sym::alias
1029 | sym::cfg
c295e0f8 1030 | sym::cfg_hide
6a06907d
XL
1031 | sym::hidden
1032 | sym::html_favicon_url
1033 | sym::html_logo_url
1034 | sym::html_no_source
1035 | sym::html_playground_url
1036 | sym::html_root_url
6a06907d
XL
1037 | sym::inline
1038 | sym::issue_tracker_base_url
1039 | sym::keyword
1040 | sym::masked
1041 | sym::no_default_passes
1042 | sym::no_inline
cdc7bbd5 1043 | sym::notable_trait
6a06907d 1044 | sym::passes
923072b8 1045 | sym::plugins
064997fb 1046 | sym::fake_variadic => {}
94222f64
XL
1047
1048 sym::test => {
04454e1e 1049 if !self.check_test_attr(meta, hir_id) {
94222f64
XL
1050 is_valid = false;
1051 }
1052 }
1053
1054 sym::primitive => {
3c0e092e 1055 if !self.tcx.features().rustdoc_internals {
064997fb 1056 self.tcx.emit_spanned_lint(
94222f64
XL
1057 INVALID_DOC_ATTRIBUTES,
1058 hir_id,
1059 i_meta.span,
064997fb 1060 errors::DocPrimitive,
94222f64
XL
1061 );
1062 }
1063 }
6a06907d
XL
1064
1065 _ => {
064997fb
FG
1066 let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
1067 if i_meta.has_name(sym::spotlight) {
1068 self.tcx.emit_spanned_lint(
1069 INVALID_DOC_ATTRIBUTES,
1070 hir_id,
1071 i_meta.span,
1072 errors::DocTestUnknownSpotlight {
1073 path,
1074 span: i_meta.span
cdc7bbd5 1075 }
064997fb
FG
1076 );
1077 } else if i_meta.has_name(sym::include) &&
1078 let Some(value) = i_meta.value_str() {
1079 let applicability = if list.len() == 1 {
1080 Applicability::MachineApplicable
1081 } else {
1082 Applicability::MaybeIncorrect
1083 };
1084 // If there are multiple attributes, the suggestion would suggest
1085 // deleting all of them, which is incorrect.
1086 self.tcx.emit_spanned_lint(
1087 INVALID_DOC_ATTRIBUTES,
1088 hir_id,
1089 i_meta.span,
1090 errors::DocTestUnknownInclude {
1091 path,
1092 value: value.to_string(),
1093 inner: (attr.style == AttrStyle::Inner)
1094 .then_some("!")
1095 .unwrap_or(""),
1096 sugg: (attr.meta().unwrap().span, applicability),
17df50a5 1097 }
064997fb
FG
1098 );
1099 } else {
1100 self.tcx.emit_spanned_lint(
1101 INVALID_DOC_ATTRIBUTES,
1102 hir_id,
1103 i_meta.span,
1104 errors::DocTestUnknownAny { path }
1105 );
1106 }
6a06907d 1107 is_valid = false;
29967ef6 1108 }
3dfed10e 1109 }
6a06907d 1110 } else {
064997fb 1111 self.tcx.emit_spanned_lint(
6a06907d
XL
1112 INVALID_DOC_ATTRIBUTES,
1113 hir_id,
1114 meta.span(),
064997fb 1115 errors::DocInvalid,
6a06907d
XL
1116 );
1117 is_valid = false;
3dfed10e
XL
1118 }
1119 }
1120 }
6a06907d
XL
1121
1122 is_valid
3dfed10e
XL
1123 }
1124
5099ac24
FG
1125 /// Warns against some misuses of `#[pass_by_value]`
1126 fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) -> bool {
1127 match target {
1128 Target::Struct | Target::Enum | Target::TyAlias => true,
1129 _ => {
064997fb 1130 self.tcx.sess.emit_err(errors::PassByValue { attr_span: attr.span, span });
5099ac24
FG
1131 false
1132 }
1133 }
1134 }
1135
5e7ed085
FG
1136 fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) -> bool {
1137 match target {
1138 Target::Method(MethodKind::Inherent) => true,
1139 _ => {
064997fb 1140 self.tcx.sess.emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
5e7ed085 1141 false
3c0e092e
XL
1142 }
1143 }
5e7ed085
FG
1144 }
1145
04454e1e
FG
1146 fn check_has_incoherent_inherent_impls(
1147 &self,
1148 attr: &Attribute,
1149 span: Span,
1150 target: Target,
1151 ) -> bool {
1152 match target {
1153 Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {
1154 true
1155 }
1156 _ => {
1157 self.tcx
1158 .sess
064997fb 1159 .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span });
04454e1e
FG
1160 false
1161 }
1162 }
1163 }
1164
5e7ed085 1165 /// Warns against some misuses of `#[must_use]`
487cf647 1166 fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool {
5e7ed085
FG
1167 if !matches!(
1168 target,
1169 Target::Fn
1170 | Target::Enum
1171 | Target::Struct
1172 | Target::Union
1173 | Target::Method(_)
1174 | Target::ForeignFn
1175 // `impl Trait` in return position can trip
1176 // `unused_must_use` if `Trait` is marked as
1177 // `#[must_use]`
1178 | Target::Trait
1179 ) {
1180 let article = match target {
1181 Target::ExternCrate
1182 | Target::OpaqueTy
1183 | Target::Enum
1184 | Target::Impl
1185 | Target::Expression
1186 | Target::Arm
1187 | Target::AssocConst
1188 | Target::AssocTy => "an",
1189 _ => "a",
1190 };
1191
064997fb
FG
1192 self.tcx.emit_spanned_lint(
1193 UNUSED_ATTRIBUTES,
1194 hir_id,
1195 attr.span,
1196 errors::MustUseNoEffect { article, target },
1197 );
5e7ed085 1198 }
3c0e092e
XL
1199
1200 // For now, its always valid
1201 true
1202 }
1203
c295e0f8 1204 /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
5099ac24 1205 fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) -> bool {
c295e0f8
XL
1206 match target {
1207 Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
1208 _ => {
064997fb 1209 self.tcx.sess.emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
c295e0f8
XL
1210 false
1211 }
1212 }
1213 }
1214
1b1a35ee 1215 /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
5099ac24 1216 fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1b1a35ee
XL
1217 match target {
1218 Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
5869c6ff
XL
1219 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1220 // `#[cold]` attribute with just a lint, because we previously
2b03887a 1221 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1222 // with crates depending on them, we can't throw an error here.
1223 Target::Field | Target::Arm | Target::MacroDef => {
1224 self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
1225 }
1b1a35ee
XL
1226 _ => {
1227 // FIXME: #[cold] was previously allowed on non-functions and some crates used
1228 // this, so only emit a warning.
064997fb
FG
1229 self.tcx.emit_spanned_lint(
1230 UNUSED_ATTRIBUTES,
1231 hir_id,
1232 attr.span,
487cf647 1233 errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID },
064997fb 1234 );
1b1a35ee
XL
1235 }
1236 }
1237 }
1238
5099ac24
FG
1239 /// Checks if `#[link]` is applied to an item other than a foreign module.
1240 fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
923072b8
FG
1241 if target == Target::ForeignMod
1242 && let hir::Node::Item(item) = self.tcx.hir().get(hir_id)
1243 && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
1244 && !matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic)
1245 {
1246 return;
1247 }
5099ac24 1248
064997fb
FG
1249 self.tcx.emit_spanned_lint(
1250 UNUSED_ATTRIBUTES,
1251 hir_id,
1252 attr.span,
1253 errors::Link { span: (target != Target::ForeignMod).then_some(span) },
1254 );
5099ac24
FG
1255 }
1256
1b1a35ee 1257 /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
5099ac24 1258 fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1b1a35ee
XL
1259 match target {
1260 Target::ForeignFn | Target::ForeignStatic => {}
5869c6ff
XL
1261 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1262 // `#[link_name]` attribute with just a lint, because we previously
2b03887a 1263 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1264 // with crates depending on them, we can't throw an error here.
1265 Target::Field | Target::Arm | Target::MacroDef => {
1266 self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
1267 }
1b1a35ee
XL
1268 _ => {
1269 // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
1270 // used this, so only emit a warning.
064997fb
FG
1271 let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span);
1272 if let Some(s) = attr.value_str() {
1273 self.tcx.emit_spanned_lint(
1274 UNUSED_ATTRIBUTES,
1275 hir_id,
1276 attr.span,
1277 errors::LinkName { span, attr_span, value: s.as_str() },
1b1a35ee 1278 );
064997fb
FG
1279 } else {
1280 self.tcx.emit_spanned_lint(
1281 UNUSED_ATTRIBUTES,
1282 hir_id,
1283 attr.span,
1284 errors::LinkName { span, attr_span, value: "..." },
1285 );
1286 };
1b1a35ee
XL
1287 }
1288 }
1289 }
1290
1291 /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
5099ac24 1292 fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
5869c6ff
XL
1293 match target {
1294 Target::ExternCrate => true,
1295 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1296 // `#[no_link]` attribute with just a lint, because we previously
2b03887a 1297 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1298 // with crates depending on them, we can't throw an error here.
1299 Target::Field | Target::Arm | Target::MacroDef => {
1300 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
1301 true
1302 }
1303 _ => {
064997fb 1304 self.tcx.sess.emit_err(errors::NoLink { attr_span: attr.span, span });
5869c6ff
XL
1305 false
1306 }
1b1a35ee
XL
1307 }
1308 }
1309
94222f64
XL
1310 fn is_impl_item(&self, hir_id: HirId) -> bool {
1311 matches!(self.tcx.hir().get(hir_id), hir::Node::ImplItem(..))
1312 }
1313
1b1a35ee 1314 /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
5869c6ff
XL
1315 fn check_export_name(
1316 &self,
1317 hir_id: HirId,
1318 attr: &Attribute,
5099ac24 1319 span: Span,
5869c6ff
XL
1320 target: Target,
1321 ) -> bool {
1b1a35ee 1322 match target {
94222f64
XL
1323 Target::Static | Target::Fn => true,
1324 Target::Method(..) if self.is_impl_item(hir_id) => true,
5869c6ff
XL
1325 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1326 // `#[export_name]` attribute with just a lint, because we previously
2b03887a 1327 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1328 // with crates depending on them, we can't throw an error here.
1329 Target::Field | Target::Arm | Target::MacroDef => {
1330 self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
1331 true
1332 }
1b1a35ee 1333 _ => {
064997fb 1334 self.tcx.sess.emit_err(errors::ExportName { attr_span: attr.span, span });
1b1a35ee
XL
1335 false
1336 }
1337 }
1338 }
1339
6a06907d
XL
1340 fn check_rustc_layout_scalar_valid_range(
1341 &self,
1342 attr: &Attribute,
5099ac24 1343 span: Span,
6a06907d
XL
1344 target: Target,
1345 ) -> bool {
1346 if target != Target::Struct {
064997fb
FG
1347 self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
1348 attr_span: attr.span,
1349 span,
1350 });
6a06907d
XL
1351 return false;
1352 }
1353
5e7ed085
FG
1354 let Some(list) = attr.meta_item_list() else {
1355 return false;
6a06907d
XL
1356 };
1357
487cf647 1358 if matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
6a06907d
XL
1359 true
1360 } else {
064997fb 1361 self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
6a06907d
XL
1362 false
1363 }
1364 }
1365
1366 /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
1367 fn check_rustc_legacy_const_generics(
1368 &self,
487cf647 1369 hir_id: HirId,
6a06907d 1370 attr: &Attribute,
5099ac24 1371 span: Span,
6a06907d
XL
1372 target: Target,
1373 item: Option<ItemLike<'_>>,
1374 ) -> bool {
5e7ed085 1375 let is_function = matches!(target, Target::Fn);
6a06907d 1376 if !is_function {
064997fb
FG
1377 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
1378 attr_span: attr.span,
1379 defn_span: span,
487cf647 1380 on_crate: hir_id == CRATE_HIR_ID,
064997fb 1381 });
6a06907d
XL
1382 return false;
1383 }
1384
5e7ed085 1385 let Some(list) = attr.meta_item_list() else {
6a06907d 1386 // The attribute form is validated on AST.
5e7ed085 1387 return false;
6a06907d
XL
1388 };
1389
5e7ed085
FG
1390 let Some(ItemLike::Item(Item {
1391 kind: ItemKind::Fn(FnSig { decl, .. }, generics, _),
1392 ..
1393 })) = item else {
1394 bug!("should be a function item");
6a06907d
XL
1395 };
1396
1397 for param in generics.params {
1398 match param.kind {
1399 hir::GenericParamKind::Const { .. } => {}
1400 _ => {
064997fb
FG
1401 self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsOnly {
1402 attr_span: attr.span,
1403 param_span: param.span,
1404 });
6a06907d
XL
1405 return false;
1406 }
1407 }
1408 }
1409
1410 if list.len() != generics.params.len() {
064997fb
FG
1411 self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndex {
1412 attr_span: attr.span,
1413 generics_span: generics.span,
1414 });
6a06907d
XL
1415 return false;
1416 }
1417
1418 let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
1419 let mut invalid_args = vec![];
1420 for meta in list {
487cf647 1421 if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) {
6a06907d
XL
1422 if *val >= arg_count {
1423 let span = meta.span();
064997fb
FG
1424 self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed {
1425 span,
1426 arg_count: arg_count as usize,
1427 });
6a06907d
XL
1428 return false;
1429 }
1430 } else {
1431 invalid_args.push(meta.span());
1432 }
1433 }
1434
1435 if !invalid_args.is_empty() {
064997fb 1436 self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
6a06907d
XL
1437 false
1438 } else {
1439 true
1440 }
1441 }
1442
923072b8
FG
1443 /// Helper function for checking that the provided attribute is only applied to a function or
1444 /// method.
487cf647
FG
1445 fn check_applied_to_fn_or_method(
1446 &self,
1447 hir_id: HirId,
1448 attr: &Attribute,
1449 span: Span,
1450 target: Target,
1451 ) -> bool {
5099ac24
FG
1452 let is_function = matches!(target, Target::Fn | Target::Method(..));
1453 if !is_function {
064997fb
FG
1454 self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
1455 attr_span: attr.span,
1456 defn_span: span,
487cf647 1457 on_crate: hir_id == CRATE_HIR_ID,
064997fb 1458 });
5099ac24
FG
1459 false
1460 } else {
1461 true
1462 }
1463 }
1464
923072b8
FG
1465 /// Checks that the `#[rustc_lint_query_instability]` attribute is only applied to a function
1466 /// or method.
1467 fn check_rustc_lint_query_instability(
1468 &self,
487cf647 1469 hir_id: HirId,
923072b8
FG
1470 attr: &Attribute,
1471 span: Span,
1472 target: Target,
1473 ) -> bool {
487cf647 1474 self.check_applied_to_fn_or_method(hir_id, attr, span, target)
923072b8
FG
1475 }
1476
1477 /// Checks that the `#[rustc_lint_diagnostics]` attribute is only applied to a function or
1478 /// method.
487cf647
FG
1479 fn check_rustc_lint_diagnostics(
1480 &self,
1481 hir_id: HirId,
1482 attr: &Attribute,
1483 span: Span,
1484 target: Target,
1485 ) -> bool {
1486 self.check_applied_to_fn_or_method(hir_id, attr, span, target)
923072b8
FG
1487 }
1488
064997fb
FG
1489 /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
1490 fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) -> bool {
1491 match target {
1492 Target::Struct => true,
1493 _ => {
1494 self.tcx.sess.emit_err(errors::RustcLintOptTy { attr_span: attr.span, span });
1495 false
1496 }
1497 }
1498 }
1499
1500 /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field.
1501 fn check_rustc_lint_opt_deny_field_access(
1502 &self,
1503 attr: &Attribute,
1504 span: Span,
1505 target: Target,
1506 ) -> bool {
1507 match target {
1508 Target::Field => true,
1509 _ => {
1510 self.tcx
1511 .sess
1512 .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span });
1513 false
1514 }
1515 }
1516 }
1517
cdc7bbd5
XL
1518 /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
1519 /// option is passed to the compiler.
1520 fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
064997fb 1521 if self.tcx.sess.opts.unstable_opts.query_dep_graph {
cdc7bbd5
XL
1522 true
1523 } else {
064997fb 1524 self.tcx.sess.emit_err(errors::RustcDirtyClean { span: attr.span });
cdc7bbd5
XL
1525 false
1526 }
1527 }
1528
1b1a35ee 1529 /// Checks if `#[link_section]` is applied to a function or static.
5099ac24 1530 fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1b1a35ee
XL
1531 match target {
1532 Target::Static | Target::Fn | Target::Method(..) => {}
5869c6ff
XL
1533 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1534 // `#[link_section]` attribute with just a lint, because we previously
2b03887a 1535 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1536 // with crates depending on them, we can't throw an error here.
1537 Target::Field | Target::Arm | Target::MacroDef => {
1538 self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
1539 }
1b1a35ee
XL
1540 _ => {
1541 // FIXME: #[link_section] was previously allowed on non-functions/statics and some
1542 // crates used this, so only emit a warning.
064997fb
FG
1543 self.tcx.emit_spanned_lint(
1544 UNUSED_ATTRIBUTES,
1545 hir_id,
1546 attr.span,
1547 errors::LinkSection { span },
1548 );
1b1a35ee
XL
1549 }
1550 }
1551 }
1552
1553 /// Checks if `#[no_mangle]` is applied to a function or static.
5099ac24 1554 fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1b1a35ee 1555 match target {
94222f64
XL
1556 Target::Static | Target::Fn => {}
1557 Target::Method(..) if self.is_impl_item(hir_id) => {}
5869c6ff
XL
1558 // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1559 // `#[no_mangle]` attribute with just a lint, because we previously
2b03887a 1560 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1561 // with crates depending on them, we can't throw an error here.
1562 Target::Field | Target::Arm | Target::MacroDef => {
1563 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
1564 }
94222f64
XL
1565 // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error
1566 // The error should specify that the item that is wrong is specifically a *foreign* fn/static
1567 // otherwise the error seems odd
1568 Target::ForeignFn | Target::ForeignStatic => {
1569 let foreign_item_kind = match target {
1570 Target::ForeignFn => "function",
1571 Target::ForeignStatic => "static",
1572 _ => unreachable!(),
1573 };
064997fb
FG
1574 self.tcx.emit_spanned_lint(
1575 UNUSED_ATTRIBUTES,
1576 hir_id,
1577 attr.span,
1578 errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind },
1579 );
94222f64 1580 }
1b1a35ee
XL
1581 _ => {
1582 // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
1583 // crates used this, so only emit a warning.
064997fb
FG
1584 self.tcx.emit_spanned_lint(
1585 UNUSED_ATTRIBUTES,
1586 hir_id,
1587 attr.span,
1588 errors::NoMangle { span },
1589 );
1b1a35ee
XL
1590 }
1591 }
1592 }
1593
9fa01778 1594 /// Checks if the `#[repr]` attributes on `item` are valid.
e74abb32
XL
1595 fn check_repr(
1596 &self,
a2a8927a 1597 attrs: &[Attribute],
5099ac24 1598 span: Span,
e74abb32 1599 target: Target,
1b1a35ee 1600 item: Option<ItemLike<'_>>,
dfeec247 1601 hir_id: HirId,
e74abb32 1602 ) {
2c00a5a8
XL
1603 // Extract the names of all repr hints, e.g., [foo, bar, align] for:
1604 // ```
1605 // #[repr(foo)]
1606 // #[repr(bar, align(8))]
1607 // ```
e74abb32 1608 let hints: Vec<_> = attrs
2c00a5a8 1609 .iter()
cdc7bbd5 1610 .filter(|attr| attr.has_name(sym::repr))
2c00a5a8 1611 .filter_map(|attr| attr.meta_item_list())
b7449926 1612 .flatten()
2c00a5a8 1613 .collect();
9e0c209e 1614
ff7c6d11
XL
1615 let mut int_reprs = 0;
1616 let mut is_c = false;
1617 let mut is_simd = false;
2c00a5a8
XL
1618 let mut is_transparent = false;
1619
1620 for hint in &hints {
136023e0 1621 if !hint.is_meta_item() {
064997fb 1622 self.tcx.sess.emit_err(errors::ReprIdent { span: hint.span() });
136023e0
XL
1623 continue;
1624 }
1625
2b03887a 1626 match hint.name_or_empty() {
136023e0
XL
1627 sym::C => {
1628 is_c = true;
dc9dc135
XL
1629 match target {
1630 Target::Struct | Target::Union | Target::Enum => continue,
2b03887a
FG
1631 _ => {
1632 self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
1633 hint_span: hint.span(),
1634 span,
1635 });
1636 }
9e0c209e
SL
1637 }
1638 }
136023e0 1639 sym::align => {
04454e1e 1640 if let (Target::Fn, false) = (target, self.tcx.features().fn_align) {
136023e0
XL
1641 feature_err(
1642 &self.tcx.sess.parse_sess,
1643 sym::fn_align,
1644 hint.span(),
1645 "`repr(align)` attributes on functions are unstable",
1646 )
1647 .emit();
1648 }
1649
1650 match target {
1651 Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
2b03887a
FG
1652 _ => {
1653 self.tcx.sess.emit_err(AttrApplication::StructEnumFunctionUnion {
1654 hint_span: hint.span(),
1655 span,
1656 });
1657 }
136023e0
XL
1658 }
1659 }
48663c56 1660 sym::packed => {
dfeec247 1661 if target != Target::Struct && target != Target::Union {
2b03887a
FG
1662 self.tcx.sess.emit_err(AttrApplication::StructUnion {
1663 hint_span: hint.span(),
1664 span,
1665 });
92a42be0 1666 } else {
dfeec247 1667 continue;
b039eaaf
SL
1668 }
1669 }
48663c56 1670 sym::simd => {
ff7c6d11 1671 is_simd = true;
1b1a35ee 1672 if target != Target::Struct {
2b03887a
FG
1673 self.tcx
1674 .sess
1675 .emit_err(AttrApplication::Struct { hint_span: hint.span(), span });
1b1a35ee
XL
1676 } else {
1677 continue;
1678 }
b039eaaf 1679 }
48663c56 1680 sym::transparent => {
2c00a5a8 1681 is_transparent = true;
dc9dc135
XL
1682 match target {
1683 Target::Struct | Target::Union | Target::Enum => continue,
2b03887a
FG
1684 _ => {
1685 self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
1686 hint_span: hint.span(),
1687 span,
1688 });
1689 }
cc61c64b
XL
1690 }
1691 }
dfeec247
XL
1692 sym::i8
1693 | sym::u8
1694 | sym::i16
1695 | sym::u16
1696 | sym::i32
1697 | sym::u32
1698 | sym::i64
1699 | sym::u64
f035d41b
XL
1700 | sym::i128
1701 | sym::u128
dfeec247
XL
1702 | sym::isize
1703 | sym::usize => {
ff7c6d11 1704 int_reprs += 1;
1b1a35ee 1705 if target != Target::Enum {
2b03887a
FG
1706 self.tcx
1707 .sess
1708 .emit_err(AttrApplication::Enum { hint_span: hint.span(), span });
1b1a35ee
XL
1709 } else {
1710 continue;
1711 }
b039eaaf 1712 }
136023e0 1713 _ => {
2b03887a 1714 self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
136023e0
XL
1715 continue;
1716 }
92a42be0 1717 };
9e0c209e 1718 }
ff7c6d11 1719
2c00a5a8
XL
1720 // Just point at all repr hints if there are any incompatibilities.
1721 // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
532ac7d7 1722 let hint_spans = hints.iter().map(|hint| hint.span());
2c00a5a8 1723
064997fb
FG
1724 // Error on repr(transparent, <anything else>).
1725 if is_transparent && hints.len() > 1 {
2c00a5a8 1726 let hint_spans: Vec<_> = hint_spans.clone().collect();
2b03887a
FG
1727 self.tcx
1728 .sess
1729 .emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
2c00a5a8 1730 }
ff7c6d11
XL
1731 // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
1732 if (int_reprs > 1)
dfeec247 1733 || (is_simd && is_c)
1b1a35ee
XL
1734 || (int_reprs == 1
1735 && is_c
1736 && item.map_or(false, |item| {
1737 if let ItemLike::Item(item) = item {
1738 return is_c_like_enum(item);
1739 }
1740 return false;
1741 }))
dfeec247 1742 {
064997fb 1743 self.tcx.emit_spanned_lint(
74b04a01
XL
1744 CONFLICTING_REPR_HINTS,
1745 hir_id,
1746 hint_spans.collect::<Vec<Span>>(),
064997fb 1747 errors::ReprConflicting,
74b04a01 1748 );
b039eaaf
SL
1749 }
1750 }
0531ce1d 1751
a2a8927a 1752 fn check_used(&self, attrs: &[Attribute], target: Target) {
5099ac24
FG
1753 let mut used_linker_span = None;
1754 let mut used_compiler_span = None;
5e7ed085
FG
1755 for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
1756 if target != Target::Static {
064997fb 1757 self.tcx.sess.emit_err(errors::UsedStatic { span: attr.span });
0531ce1d 1758 }
5099ac24
FG
1759 let inner = attr.meta_item_list();
1760 match inner.as_deref() {
1761 Some([item]) if item.has_name(sym::linker) => {
1762 if used_linker_span.is_none() {
1763 used_linker_span = Some(attr.span);
1764 }
1765 }
1766 Some([item]) if item.has_name(sym::compiler) => {
1767 if used_compiler_span.is_none() {
1768 used_compiler_span = Some(attr.span);
1769 }
1770 }
1771 Some(_) => {
2b03887a 1772 // This error case is handled in rustc_hir_analysis::collect.
5099ac24
FG
1773 }
1774 None => {
1775 // Default case (compiler) when arg isn't defined.
1776 if used_compiler_span.is_none() {
1777 used_compiler_span = Some(attr.span);
1778 }
1779 }
1780 }
1781 }
1782 if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
5099ac24
FG
1783 self.tcx
1784 .sess
064997fb 1785 .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
0531ce1d
XL
1786 }
1787 }
1788
29967ef6
XL
1789 /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
1790 /// (Allows proc_macro functions)
1791 fn check_allow_internal_unstable(
1792 &self,
5869c6ff 1793 hir_id: HirId,
29967ef6 1794 attr: &Attribute,
5099ac24 1795 span: Span,
29967ef6
XL
1796 target: Target,
1797 attrs: &[Attribute],
1798 ) -> bool {
1799 debug!("Checking target: {:?}", target);
5869c6ff
XL
1800 match target {
1801 Target::Fn => {
1802 for attr in attrs {
1803 if self.tcx.sess.is_proc_macro_attr(attr) {
1804 debug!("Is proc macro attr");
1805 return true;
1806 }
29967ef6 1807 }
5869c6ff
XL
1808 debug!("Is not proc macro attr");
1809 false
1810 }
1811 Target::MacroDef => true,
1812 // FIXME(#80564): We permit struct fields and match arms to have an
1813 // `#[allow_internal_unstable]` attribute with just a lint, because we previously
2b03887a 1814 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1815 // with crates depending on them, we can't throw an error here.
1816 Target::Field | Target::Arm => {
1817 self.inline_attr_str_error_without_macro_def(
1818 hir_id,
1819 attr,
1820 "allow_internal_unstable",
1821 );
1822 true
1823 }
1824 _ => {
1825 self.tcx
1826 .sess
064997fb 1827 .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
5869c6ff 1828 false
0531ce1d
XL
1829 }
1830 }
1831 }
83c7162d 1832
04454e1e
FG
1833 /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
1834 fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
1835 match target {
1836 Target::Mod => {}
1837 _ => {
064997fb 1838 self.tcx.sess.emit_err(errors::DebugVisualizerPlacement { span: attr.span });
04454e1e
FG
1839 return false;
1840 }
1841 }
1842
923072b8 1843 let Some(hints) = attr.meta_item_list() else {
064997fb 1844 self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
923072b8 1845 return false;
04454e1e
FG
1846 };
1847
1848 let hint = match hints.len() {
1849 1 => &hints[0],
1850 _ => {
064997fb 1851 self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
04454e1e
FG
1852 return false;
1853 }
1854 };
1855
923072b8 1856 let Some(meta_item) = hint.meta_item() else {
064997fb 1857 self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
04454e1e 1858 return false;
923072b8 1859 };
04454e1e 1860
923072b8
FG
1861 let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) {
1862 (sym::natvis_file, Some(value)) => value,
1863 (sym::gdb_script_file, Some(value)) => value,
1864 (_, _) => {
064997fb 1865 self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span });
04454e1e
FG
1866 return false;
1867 }
1868 };
1869
923072b8
FG
1870 let file =
1871 match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) {
1872 Ok(file) => file,
1873 Err(mut err) => {
1874 err.emit();
1875 return false;
1876 }
1877 };
1878
1879 match std::fs::File::open(&file) {
1880 Ok(_) => true,
2b03887a
FG
1881 Err(error) => {
1882 self.tcx.sess.emit_err(DebugVisualizerUnreadable {
1883 span: meta_item.span,
1884 file: &file,
1885 error,
1886 });
04454e1e
FG
1887 false
1888 }
1889 }
1890 }
1891
29967ef6
XL
1892 /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
1893 /// (Allows proc_macro functions)
1894 fn check_rustc_allow_const_fn_unstable(
1895 &self,
1896 hir_id: HirId,
1897 attr: &Attribute,
5099ac24 1898 span: Span,
29967ef6
XL
1899 target: Target,
1900 ) -> bool {
5869c6ff
XL
1901 match target {
1902 Target::Fn | Target::Method(_)
5e7ed085 1903 if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id).to_def_id()) =>
5869c6ff
XL
1904 {
1905 true
1906 }
1907 // FIXME(#80564): We permit struct fields and match arms to have an
1908 // `#[allow_internal_unstable]` attribute with just a lint, because we previously
2b03887a 1909 // erroneously allowed it and some crates used it accidentally, to be compatible
5869c6ff
XL
1910 // with crates depending on them, we can't throw an error here.
1911 Target::Field | Target::Arm | Target::MacroDef => {
1912 self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
1913 true
1914 }
1915 _ => {
1916 self.tcx
1917 .sess
064997fb 1918 .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
5869c6ff 1919 false
83c7162d
XL
1920 }
1921 }
1922 }
136023e0 1923
04454e1e
FG
1924 fn check_rustc_std_internal_symbol(
1925 &self,
1926 attr: &Attribute,
1927 span: Span,
1928 target: Target,
1929 ) -> bool {
1930 match target {
1931 Target::Fn | Target::Static => true,
1932 _ => {
1933 self.tcx
1934 .sess
064997fb 1935 .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
04454e1e
FG
1936 false
1937 }
1938 }
1939 }
1940
923072b8
FG
1941 /// `#[const_trait]` only applies to traits.
1942 fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
136023e0 1943 match target {
923072b8 1944 Target::Trait => true,
136023e0 1945 _ => {
064997fb 1946 self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span });
136023e0
XL
1947 false
1948 }
1949 }
1950 }
94222f64 1951
5099ac24 1952 fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
94222f64
XL
1953 match target {
1954 Target::Expression => {
064997fb 1955 self.tcx.sess.emit_err(errors::StabilityPromotable { attr_span: attr.span });
94222f64
XL
1956 false
1957 }
1958 _ => true,
1959 }
1960 }
1961
f2b60f7d
FG
1962 fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
1963 match target {
1964 Target::ForeignFn | Target::ForeignStatic => true,
1965 _ => {
1966 self.tcx.sess.emit_err(errors::LinkOrdinal { attr_span: attr.span });
1967 false
1968 }
1969 }
1970 }
1971
5099ac24 1972 fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
94222f64
XL
1973 match target {
1974 Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
064997fb
FG
1975 self.tcx.emit_spanned_lint(
1976 UNUSED_ATTRIBUTES,
1977 hir_id,
1978 attr.span,
1979 errors::Deprecated,
1980 );
94222f64
XL
1981 }
1982 _ => {}
1983 }
1984 }
1985
1986 fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
1987 let name = attr.name_or_empty();
1988 match target {
1989 Target::ExternCrate | Target::Mod => {}
1990 _ => {
064997fb
FG
1991 self.tcx.emit_spanned_lint(
1992 UNUSED_ATTRIBUTES,
1993 hir_id,
1994 attr.span,
1995 errors::MacroUse { name },
1996 );
94222f64
XL
1997 }
1998 }
1999 }
2000
2001 fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2002 if target != Target::MacroDef {
064997fb 2003 self.tcx.emit_spanned_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::MacroExport);
94222f64
XL
2004 }
2005 }
2006
94222f64
XL
2007 fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2008 if target != Target::Fn {
064997fb
FG
2009 self.tcx.emit_spanned_lint(
2010 UNUSED_ATTRIBUTES,
2011 hir_id,
2012 attr.span,
2013 errors::PluginRegistrar,
2014 );
94222f64
XL
2015 }
2016 }
5e7ed085
FG
2017
2018 fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
2019 // Warn on useless empty attributes.
2020 let note = if matches!(
2021 attr.name_or_empty(),
2022 sym::macro_use
2023 | sym::allow
2024 | sym::expect
2025 | sym::warn
2026 | sym::deny
2027 | sym::forbid
2028 | sym::feature
2029 | sym::repr
2030 | sym::target_feature
2031 ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
2032 {
064997fb 2033 errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
5e7ed085
FG
2034 } else if matches!(
2035 attr.name_or_empty(),
2036 sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
2037 ) && let Some(meta) = attr.meta_item_list()
2038 && meta.len() == 1
2039 && let Some(item) = meta[0].meta_item()
2040 && let MetaItemKind::NameValue(_) = &item.kind
2041 && item.path == sym::reason
2042 {
064997fb 2043 errors::UnusedNote::NoLints { name: attr.name_or_empty() }
923072b8 2044 } else if attr.name_or_empty() == sym::default_method_body_is_const {
064997fb 2045 errors::UnusedNote::DefaultMethodBodyConst
5e7ed085
FG
2046 } else {
2047 return;
2048 };
2049
064997fb
FG
2050 self.tcx.emit_spanned_lint(
2051 UNUSED_ATTRIBUTES,
2052 hir_id,
2053 attr.span,
2054 errors::Unused { attr_span: attr.span, note },
2055 );
5e7ed085 2056 }
b039eaaf
SL
2057}
2058
a2a8927a 2059impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
5099ac24 2060 type NestedFilter = nested_filter::OnlyBodies;
dfeec247 2061
5099ac24
FG
2062 fn nested_visit_map(&mut self) -> Self::Map {
2063 self.tcx.hir()
2c00a5a8
XL
2064 }
2065
dfeec247 2066 fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
94222f64
XL
2067 // Historically we've run more checks on non-exported than exported macros,
2068 // so this lets us continue to run them while maintaining backwards compatibility.
2069 // In the long run, the checks should be harmonized.
5e7ed085 2070 if let ItemKind::Macro(ref macro_def, _) = item.kind {
2b03887a 2071 let def_id = item.owner_id.to_def_id();
94222f64
XL
2072 if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
2073 check_non_exported_macro_for_invalid_attrs(self.tcx, item);
2074 }
2075 }
2076
b039eaaf 2077 let target = Target::from_item(item);
5099ac24 2078 self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
0531ce1d
XL
2079 intravisit::walk_item(self, item)
2080 }
2081
fc512014
XL
2082 fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
2083 let target = Target::from_generic_param(generic_param);
5099ac24 2084 self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
fc512014
XL
2085 intravisit::walk_generic_param(self, generic_param)
2086 }
2087
dfeec247 2088 fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
e74abb32 2089 let target = Target::from_trait_item(trait_item);
5099ac24 2090 self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
e74abb32
XL
2091 intravisit::walk_trait_item(self, trait_item)
2092 }
2093
6a06907d 2094 fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
5099ac24 2095 self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
6a06907d 2096 intravisit::walk_field_def(self, struct_field);
5869c6ff
XL
2097 }
2098
2099 fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
5099ac24 2100 self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
5869c6ff
XL
2101 intravisit::walk_arm(self, arm);
2102 }
2103
1b1a35ee 2104 fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
e74abb32 2105 let target = Target::from_foreign_item(f_item);
064997fb 2106 self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
e74abb32
XL
2107 intravisit::walk_foreign_item(self, f_item)
2108 }
2109
dfeec247 2110 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
74b04a01 2111 let target = target_from_impl_item(self.tcx, impl_item);
5099ac24 2112 self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
e74abb32
XL
2113 intravisit::walk_impl_item(self, impl_item)
2114 }
0531ce1d 2115
dfeec247 2116 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
29967ef6
XL
2117 // When checking statements ignore expressions, they will be checked later.
2118 if let hir::StmtKind::Local(ref l) = stmt.kind {
5099ac24 2119 self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
29967ef6 2120 }
0531ce1d
XL
2121 intravisit::walk_stmt(self, stmt)
2122 }
2123
dfeec247 2124 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
29967ef6 2125 let target = match expr.kind {
923072b8 2126 hir::ExprKind::Closure { .. } => Target::Closure,
29967ef6
XL
2127 _ => Target::Expression,
2128 };
2129
5099ac24 2130 self.check_attributes(expr.hir_id, expr.span, target, None);
0531ce1d 2131 intravisit::walk_expr(self, expr)
b039eaaf 2132 }
29967ef6 2133
f2b60f7d
FG
2134 fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
2135 self.check_attributes(field.hir_id, field.span, Target::ExprField, None);
2136 intravisit::walk_expr_field(self, field)
2137 }
2138
2139 fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
487cf647 2140 self.check_attributes(variant.hir_id, variant.span, Target::Variant, None);
f2b60f7d 2141 intravisit::walk_variant(self, variant)
29967ef6 2142 }
6a06907d 2143
6a06907d 2144 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
5099ac24 2145 self.check_attributes(param.hir_id, param.span, Target::Param, None);
6a06907d
XL
2146
2147 intravisit::walk_param(self, param);
2148 }
f2b60f7d
FG
2149
2150 fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
2151 self.check_attributes(field.hir_id, field.span, Target::PatField, None);
2152 intravisit::walk_pat_field(self, field);
2153 }
b039eaaf
SL
2154}
2155
dfeec247 2156fn is_c_like_enum(item: &Item<'_>) -> bool {
e74abb32 2157 if let ItemKind::Enum(ref def, _) = item.kind {
dfeec247 2158 for variant in def.variants {
e1599b0c 2159 match variant.data {
9fa01778 2160 hir::VariantData::Unit(..) => { /* continue */ }
e74abb32 2161 _ => return false,
ff7c6d11
XL
2162 }
2163 }
2164 true
2165 } else {
2166 false
2167 }
2168}
0731742a 2169
a2a8927a
XL
2170// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
2171// from this check.
29967ef6 2172fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
a2a8927a
XL
2173 // Check for builtin attributes at the crate level
2174 // which were unsuccessfully resolved due to cannot determine
2175 // resolution for the attribute macro error.
29967ef6
XL
2176 const ATTRS_TO_CHECK: &[Symbol] = &[
2177 sym::macro_export,
2178 sym::repr,
2179 sym::path,
2180 sym::automatically_derived,
2181 sym::start,
cdc7bbd5 2182 sym::rustc_main,
f2b60f7d 2183 sym::unix_sigpipe,
a2a8927a
XL
2184 sym::derive,
2185 sym::test,
2186 sym::test_case,
2187 sym::global_allocator,
2188 sym::bench,
29967ef6
XL
2189 ];
2190
2191 for attr in attrs {
a2a8927a
XL
2192 // This function should only be called with crate attributes
2193 // which are inner attributes always but lets check to make sure
2194 if attr.style == AttrStyle::Inner {
2195 for attr_to_check in ATTRS_TO_CHECK {
2196 if attr.has_name(*attr_to_check) {
2b03887a
FG
2197 tcx.sess.emit_err(InvalidAttrAtCrateLevel {
2198 span: attr.span,
2199 snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
2200 name: *attr_to_check,
2201 });
a2a8927a 2202 }
29967ef6
XL
2203 }
2204 }
2205 }
2206}
2207
94222f64
XL
2208fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
2209 let attrs = tcx.hir().attrs(item.hir_id());
2210
5869c6ff 2211 for attr in attrs {
94222f64 2212 if attr.has_name(sym::inline) {
064997fb 2213 tcx.sess.emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
5869c6ff
XL
2214 }
2215 }
2216}
2217
f035d41b 2218fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
5869c6ff 2219 let check_attr_visitor = &mut CheckAttrVisitor { tcx };
064997fb 2220 tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
29967ef6 2221 if module_def_id.is_top_level_module() {
5099ac24 2222 check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
29967ef6
XL
2223 check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
2224 }
0731742a
XL
2225}
2226
f035d41b 2227pub(crate) fn provide(providers: &mut Providers) {
dfeec247 2228 *providers = Providers { check_mod_attrs, ..*providers };
0731742a 2229}
3c0e092e
XL
2230
2231fn check_duplicates(
2232 tcx: TyCtxt<'_>,
2233 attr: &Attribute,
2234 hir_id: HirId,
2235 duplicates: AttributeDuplicates,
2236 seen: &mut FxHashMap<Symbol, Span>,
2237) {
2238 use AttributeDuplicates::*;
2239 if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
2240 return;
2241 }
2242 match duplicates {
2243 DuplicatesOk => {}
2244 WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
2245 match seen.entry(attr.name_or_empty()) {
2246 Entry::Occupied(mut entry) => {
2247 let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
2248 let to_remove = entry.insert(attr.span);
2249 (to_remove, attr.span)
2250 } else {
2251 (attr.span, *entry.get())
2252 };
064997fb
FG
2253 tcx.emit_spanned_lint(
2254 UNUSED_ATTRIBUTES,
2255 hir_id,
2256 this,
2257 errors::UnusedDuplicate {
3c0e092e 2258 this,
064997fb
FG
2259 other,
2260 warning: matches!(
2261 duplicates,
2262 FutureWarnFollowing | FutureWarnPreceding
2263 )
2264 .then_some(()),
2265 },
2266 );
3c0e092e
XL
2267 }
2268 Entry::Vacant(entry) => {
2269 entry.insert(attr.span);
2270 }
2271 }
2272 }
2273 ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
2274 Entry::Occupied(mut entry) => {
2275 let (this, other) = if matches!(duplicates, ErrorPreceding) {
2276 let to_remove = entry.insert(attr.span);
2277 (to_remove, attr.span)
2278 } else {
2279 (attr.span, *entry.get())
2280 };
064997fb
FG
2281 tcx.sess.emit_err(errors::UnusedMultiple {
2282 this,
2283 other,
2284 name: attr.name_or_empty(),
2285 });
3c0e092e
XL
2286 }
2287 Entry::Vacant(entry) => {
2288 entry.insert(attr.span);
2289 }
2290 },
2291 }
2292}