rustc_hir/attrs/data_structures.rs
1use std::borrow::Cow;
2use std::path::PathBuf;
3
4pub use ReprAttr::*;
5use rustc_abi::Align;
6use rustc_ast::token::CommentKind;
7use rustc_ast::{AttrStyle, ast};
8use rustc_error_messages::{DiagArgValue, IntoDiagArg};
9use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
10use rustc_span::def_id::DefId;
11use rustc_span::hygiene::Transparency;
12use rustc_span::{Ident, Span, Symbol};
13pub use rustc_target::spec::SanitizerSet;
14use thin_vec::ThinVec;
15
16use crate::attrs::pretty_printing::PrintAttribute;
17use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
18
19#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
20pub enum InlineAttr {
21 None,
22 Hint,
23 Always,
24 Never,
25 /// `#[rustc_force_inline]` forces inlining to happen in the MIR inliner - it reports an error
26 /// if the inlining cannot happen. It is limited to only free functions so that the calls
27 /// can always be resolved.
28 Force {
29 attr_span: Span,
30 reason: Option<Symbol>,
31 },
32}
33
34impl InlineAttr {
35 pub fn always(&self) -> bool {
36 match self {
37 InlineAttr::Always | InlineAttr::Force { .. } => true,
38 InlineAttr::None | InlineAttr::Hint | InlineAttr::Never => false,
39 }
40 }
41}
42
43#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
44pub enum InstructionSetAttr {
45 ArmA32,
46 ArmT32,
47}
48
49#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, PrintAttribute)]
50#[derive(Encodable, Decodable, HashStable_Generic)]
51pub enum OptimizeAttr {
52 /// No `#[optimize(..)]` attribute
53 #[default]
54 Default,
55 /// `#[optimize(none)]`
56 DoNotOptimize,
57 /// `#[optimize(speed)]`
58 Speed,
59 /// `#[optimize(size)]`
60 Size,
61}
62
63impl OptimizeAttr {
64 pub fn do_not_optimize(&self) -> bool {
65 matches!(self, Self::DoNotOptimize)
66 }
67}
68
69#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
70pub enum ReprAttr {
71 ReprInt(IntType),
72 ReprRust,
73 ReprC,
74 ReprPacked(Align),
75 ReprSimd,
76 ReprTransparent,
77 ReprAlign(Align),
78}
79
80pub enum TransparencyError {
81 UnknownTransparency(Symbol, Span),
82 MultipleTransparencyAttrs(Span, Span),
83}
84
85#[derive(Eq, PartialEq, Debug, Copy, Clone)]
86#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)]
87pub enum IntType {
88 SignedInt(ast::IntTy),
89 UnsignedInt(ast::UintTy),
90}
91
92#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
93pub struct Deprecation {
94 pub since: DeprecatedSince,
95 /// The note to issue a reason.
96 pub note: Option<Symbol>,
97 /// A text snippet used to completely replace any use of the deprecated item in an expression.
98 ///
99 /// This is currently unstable.
100 pub suggestion: Option<Symbol>,
101}
102
103/// Release in which an API is deprecated.
104#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
105pub enum DeprecatedSince {
106 RustcVersion(RustcVersion),
107 /// Deprecated in the future ("to be determined").
108 Future,
109 /// `feature(staged_api)` is off. Deprecation versions outside the standard
110 /// library are allowed to be arbitrary strings, for better or worse.
111 NonStandard(Symbol),
112 /// Deprecation version is unspecified but optional.
113 Unspecified,
114 /// Failed to parse a deprecation version, or the deprecation version is
115 /// unspecified and required. An error has already been emitted.
116 Err,
117}
118
119/// Successfully-parsed value of a `#[coverage(..)]` attribute.
120#[derive(Copy, Debug, Eq, PartialEq, Encodable, Decodable, Clone)]
121#[derive(HashStable_Generic, PrintAttribute)]
122pub enum CoverageAttrKind {
123 On,
124 Off,
125}
126
127impl Deprecation {
128 /// Whether an item marked with #[deprecated(since = "X")] is currently
129 /// deprecated (i.e., whether X is not greater than the current rustc
130 /// version).
131 pub fn is_in_effect(&self) -> bool {
132 match self.since {
133 DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT,
134 DeprecatedSince::Future => false,
135 // The `since` field doesn't have semantic purpose without `#![staged_api]`.
136 DeprecatedSince::NonStandard(_) => true,
137 // Assume deprecation is in effect if "since" field is absent or invalid.
138 DeprecatedSince::Unspecified | DeprecatedSince::Err => true,
139 }
140 }
141
142 pub fn is_since_rustc_version(&self) -> bool {
143 matches!(self.since, DeprecatedSince::RustcVersion(_))
144 }
145}
146
147/// There are three valid forms of the attribute:
148/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable.
149/// `#[used(compiler)]`
150/// `#[used(linker)]`
151#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
152#[derive(HashStable_Generic, PrintAttribute)]
153pub enum UsedBy {
154 Compiler,
155 Linker,
156}
157
158#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)]
159#[derive(HashStable_Generic, PrintAttribute)]
160pub enum MacroUseArgs {
161 UseAll,
162 UseSpecific(ThinVec<Ident>),
163}
164
165impl Default for MacroUseArgs {
166 fn default() -> Self {
167 Self::UseSpecific(ThinVec::new())
168 }
169}
170
171#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
172pub struct StrippedCfgItem<ModId = DefId> {
173 pub parent_module: ModId,
174 pub ident: Ident,
175 pub cfg: (CfgEntry, Span),
176}
177
178impl<ModId> StrippedCfgItem<ModId> {
179 pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
180 StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg }
181 }
182}
183
184#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)]
185#[derive(HashStable_Generic, PrintAttribute)]
186pub enum CfgEntry {
187 All(ThinVec<CfgEntry>, Span),
188 Any(ThinVec<CfgEntry>, Span),
189 Not(Box<CfgEntry>, Span),
190 Bool(bool, Span),
191 NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span },
192 Version(Option<RustcVersion>, Span),
193}
194
195/// Possible values for the `#[linkage]` attribute, allowing to specify the
196/// linkage type for a `MonoItem`.
197///
198/// See <https://llvm.org/docs/LangRef.html#linkage-types> for more details about these variants.
199#[derive(Encodable, Decodable, Clone, Copy, Debug, PartialEq, Eq, Hash)]
200#[derive(HashStable_Generic, PrintAttribute)]
201pub enum Linkage {
202 AvailableExternally,
203 Common,
204 ExternalWeak,
205 External,
206 Internal,
207 LinkOnceAny,
208 LinkOnceODR,
209 WeakAny,
210 WeakODR,
211}
212
213#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)]
214#[derive(HashStable_Generic, PrintAttribute)]
215pub enum MirDialect {
216 Analysis,
217 Built,
218 Runtime,
219}
220
221impl IntoDiagArg for MirDialect {
222 fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
223 let arg = match self {
224 MirDialect::Analysis => "analysis",
225 MirDialect::Built => "built",
226 MirDialect::Runtime => "runtime",
227 };
228 DiagArgValue::Str(Cow::Borrowed(arg))
229 }
230}
231
232#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)]
233#[derive(HashStable_Generic, PrintAttribute)]
234pub enum MirPhase {
235 Initial,
236 PostCleanup,
237 Optimized,
238}
239
240impl IntoDiagArg for MirPhase {
241 fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
242 let arg = match self {
243 MirPhase::Initial => "initial",
244 MirPhase::PostCleanup => "post-cleanup",
245 MirPhase::Optimized => "optimized",
246 };
247 DiagArgValue::Str(Cow::Borrowed(arg))
248 }
249}
250
251/// Represents parsed *built-in* inert attributes.
252///
253/// ## Overview
254/// These attributes are markers that guide the compilation process and are never expanded into other code.
255/// They persist throughout the compilation phases, from AST to HIR and beyond.
256///
257/// ## Attribute Processing
258/// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams
259/// because different attributes have different internal structures. This enum represents the final,
260/// fully parsed form of these attributes, where each variant contains all the information and
261/// structure relevant for the specific attribute.
262///
263/// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single
264/// semantic attribute. For example:
265/// ```rust
266/// #[repr(C)]
267/// #[repr(packed)]
268/// struct S { }
269/// ```
270/// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing
271/// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the
272/// data structures defined in this enum.
273///
274/// ## Usage
275/// These parsed attributes are used throughout the compiler to:
276/// - Control code generation (e.g., `#[repr]`)
277/// - Mark API stability (`#[stable]`, `#[unstable]`)
278/// - Provide documentation (`#[doc]`)
279/// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`)
280///
281/// ## Note on Attribute Organization
282/// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately
283/// from this enum because they are used in specific compiler phases (like code generation) and don't
284/// need to persist throughout the entire compilation process. They are typically processed and
285/// converted into their final form earlier in the compilation pipeline.
286///
287/// For example:
288/// - `InlineAttr` is used during code generation to control function inlining
289/// - `OptimizeAttr` is used to control optimization levels
290/// - `InstructionSetAttr` is used for target-specific code generation
291///
292/// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate
293/// and don't need to be preserved in the same way as the attributes in this enum.
294///
295/// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate.
296///
297/// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html
298/// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html
299/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html
300#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
301pub enum AttributeKind {
302 // tidy-alphabetical-start
303 /// Represents `#[align(N)]`.
304 // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
305 Align { align: Align, span: Span },
306
307 /// Represents `#[rustc_allow_const_fn_unstable]`.
308 AllowConstFnUnstable(ThinVec<Symbol>, Span),
309
310 /// Represents `#[rustc_allow_incoherent_impl]`.
311 AllowIncoherentImpl(Span),
312
313 /// Represents `#[allow_internal_unsafe]`.
314 AllowInternalUnsafe(Span),
315
316 /// Represents `#[allow_internal_unstable]`.
317 AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
318
319 /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
320 AsPtr(Span),
321
322 /// Represents `#[automatically_derived]`
323 AutomaticallyDerived(Span),
324
325 /// Represents `#[rustc_default_body_unstable]`.
326 BodyStability {
327 stability: DefaultBodyStability,
328 /// Span of the `#[rustc_default_body_unstable(...)]` attribute
329 span: Span,
330 },
331
332 /// Represents `#[rustc_coherence_is_core]`.
333 CoherenceIsCore,
334
335 /// Represents `#[rustc_coinductive]`.
336 Coinductive(Span),
337
338 /// Represents `#[cold]`.
339 Cold(Span),
340
341 /// Represents `#[rustc_confusables]`.
342 Confusables {
343 symbols: ThinVec<Symbol>,
344 // FIXME(jdonszelmann): remove when target validation code is moved
345 first_span: Span,
346 },
347
348 /// Represents `#[const_continue]`.
349 ConstContinue(Span),
350
351 /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
352 ConstStability {
353 stability: PartialConstStability,
354 /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
355 span: Span,
356 },
357
358 /// Represents `#[rustc_const_stable_indirect]`.
359 ConstStabilityIndirect,
360
361 /// Represents `#[const_trait]`.
362 ConstTrait(Span),
363
364 /// Represents `#[coroutine]`.
365 Coroutine(Span),
366
367 /// Represents `#[coverage(..)]`.
368 Coverage(Span, CoverageAttrKind),
369
370 /// Represents `#[crate_name = ...]`
371 CrateName { name: Symbol, name_span: Span, attr_span: Span, style: AttrStyle },
372
373 /// Represents `#[custom_mir]`.
374 CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
375
376 ///Represents `#[rustc_deny_explicit_impl]`.
377 DenyExplicitImpl(Span),
378
379 /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
380 Deprecation { deprecation: Deprecation, span: Span },
381
382 /// Represents `#[rustc_do_not_implement_via_object]`.
383 DoNotImplementViaObject(Span),
384
385 /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
386 DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
387
388 /// Represents `#[rustc_dummy]`.
389 Dummy,
390
391 /// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
392 ExportName {
393 /// The name to export this item with.
394 /// It may not contain \0 bytes as it will be converted to a null-terminated string.
395 name: Symbol,
396 span: Span,
397 },
398
399 /// Represents `#[export_stable]`.
400 ExportStable,
401
402 /// Represents `#[ffi_const]`.
403 FfiConst(Span),
404
405 /// Represents `#[ffi_pure]`.
406 FfiPure(Span),
407
408 /// Represents `#[fundamental]`.
409 Fundamental,
410
411 /// Represents `#[ignore]`
412 Ignore {
413 span: Span,
414 /// ignore can optionally have a reason: `#[ignore = "reason this is ignored"]`
415 reason: Option<Symbol>,
416 },
417
418 /// Represents `#[inline]` and `#[rustc_force_inline]`.
419 Inline(InlineAttr, Span),
420
421 /// Represents `#[link_name]`.
422 LinkName { name: Symbol, span: Span },
423
424 /// Represents `#[link_ordinal]`.
425 LinkOrdinal { ordinal: u16, span: Span },
426
427 /// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
428 LinkSection { name: Symbol, span: Span },
429
430 /// Represents `#[linkage]`.
431 Linkage(Linkage, Span),
432
433 /// Represents `#[loop_match]`.
434 LoopMatch(Span),
435
436 /// Represents `#[macro_escape]`.
437 MacroEscape(Span),
438
439 /// Represents `#[rustc_macro_transparency]`.
440 MacroTransparency(Transparency),
441
442 /// Represents `#[macro_use]`.
443 MacroUse { span: Span, arguments: MacroUseArgs },
444
445 /// Represents `#[marker]`.
446 Marker(Span),
447
448 /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html).
449 MayDangle(Span),
450
451 /// Represents `#[must_use]`.
452 MustUse {
453 span: Span,
454 /// must_use can optionally have a reason: `#[must_use = "reason this must be used"]`
455 reason: Option<Symbol>,
456 },
457
458 /// Represents `#[naked]`
459 Naked(Span),
460
461 /// Represents `#[no_implicit_prelude]`
462 NoImplicitPrelude(Span),
463
464 /// Represents `#[no_mangle]`
465 NoMangle(Span),
466
467 /// Represents `#[non_exhaustive]`
468 NonExhaustive(Span),
469
470 /// Represents `#[optimize(size|speed)]`
471 Optimize(OptimizeAttr, Span),
472
473 /// Represents `#[rustc_paren_sugar]`.
474 ParenSugar(Span),
475
476 /// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
477 PassByValue(Span),
478
479 /// Represents `#[path]`
480 Path(Symbol, Span),
481
482 /// Represents `#[pointee]`
483 Pointee(Span),
484
485 /// Represents `#[proc_macro]`
486 ProcMacro(Span),
487
488 /// Represents `#[proc_macro_attribute]`
489 ProcMacroAttribute(Span),
490
491 /// Represents `#[proc_macro_derive]`
492 ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
493
494 /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
495 PubTransparent(Span),
496
497 /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
498 Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
499
500 /// Represents `#[rustc_builtin_macro]`.
501 RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
502
503 /// Represents `#[rustc_layout_scalar_valid_range_end]`.
504 RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
505
506 /// Represents `#[rustc_layout_scalar_valid_range_start]`.
507 RustcLayoutScalarValidRangeStart(Box<u128>, Span),
508
509 /// Represents `#[rustc_object_lifetime_default]`.
510 RustcObjectLifetimeDefault,
511
512 /// Represents `#[sanitize]`
513 ///
514 /// the on set and off set are distjoint since there's a third option: unset.
515 /// a node may not set the sanitizer setting in which case it inherits from parents.
516 Sanitize { on_set: SanitizerSet, off_set: SanitizerSet, span: Span },
517
518 /// Represents `#[should_panic]`
519 ShouldPanic { reason: Option<Symbol>, span: Span },
520
521 /// Represents `#[rustc_skip_during_method_dispatch]`.
522 SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
523
524 /// Represents `#[rustc_specialization_trait]`.
525 SpecializationTrait(Span),
526
527 /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
528 Stability {
529 stability: Stability,
530 /// Span of the attribute.
531 span: Span,
532 },
533
534 /// Represents `#[rustc_std_internal_symbol]`.
535 StdInternalSymbol(Span),
536
537 /// Represents `#[target_feature(enable = "...")]` and
538 /// `#[unsafe(force_target_feature(enable = "...")]`.
539 TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
540
541 /// Represents `#[track_caller]`
542 TrackCaller(Span),
543
544 /// Represents `#[type_const]`.
545 TypeConst(Span),
546
547 /// Represents `#[rustc_unsafe_specialization_marker]`.
548 UnsafeSpecializationMarker(Span),
549
550 /// Represents `#[unstable_feature_bound]`.
551 UnstableFeatureBound(ThinVec<(Symbol, Span)>),
552
553 /// Represents `#[used]`
554 Used { used_by: UsedBy, span: Span },
555 // tidy-alphabetical-end
556}