diff options
Diffstat (limited to 'compiler/rustc_hir/src')
| -rw-r--r-- | compiler/rustc_hir/src/attrs/data_structures.rs | 473 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 86 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/attrs/mod.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/attrs/pretty_printing.rs | 149 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/def.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/lang_items.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/lib.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/lints.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/stability.rs | 207 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/stable_hash_impls.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/version.rs | 47 |
12 files changed, 1065 insertions, 16 deletions
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs new file mode 100644 index 00000000000..80f5e6177f7 --- /dev/null +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -0,0 +1,473 @@ +pub use ReprAttr::*; +use rustc_abi::Align; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrStyle, ast}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_span::def_id::DefId; +use rustc_span::hygiene::Transparency; +use rustc_span::{Ident, Span, Symbol}; +use thin_vec::ThinVec; + +use crate::attrs::pretty_printing::PrintAttribute; +use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; + +#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] +pub enum InlineAttr { + None, + Hint, + Always, + Never, + /// `#[rustc_force_inline]` forces inlining to happen in the MIR inliner - it reports an error + /// if the inlining cannot happen. It is limited to only free functions so that the calls + /// can always be resolved. + Force { + attr_span: Span, + reason: Option<Symbol>, + }, +} + +impl InlineAttr { + pub fn always(&self) -> bool { + match self { + InlineAttr::Always | InlineAttr::Force { .. } => true, + InlineAttr::None | InlineAttr::Hint | InlineAttr::Never => false, + } + } +} + +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)] +pub enum InstructionSetAttr { + ArmA32, + ArmT32, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, PrintAttribute)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub enum OptimizeAttr { + /// No `#[optimize(..)]` attribute + #[default] + Default, + /// `#[optimize(none)]` + DoNotOptimize, + /// `#[optimize(speed)]` + Speed, + /// `#[optimize(size)]` + Size, +} + +impl OptimizeAttr { + pub fn do_not_optimize(&self) -> bool { + matches!(self, Self::DoNotOptimize) + } +} + +#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)] +pub enum ReprAttr { + ReprInt(IntType), + ReprRust, + ReprC, + ReprPacked(Align), + ReprSimd, + ReprTransparent, + ReprAlign(Align), +} + +pub enum TransparencyError { + UnknownTransparency(Symbol, Span), + MultipleTransparencyAttrs(Span, Span), +} + +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)] +pub enum IntType { + SignedInt(ast::IntTy), + UnsignedInt(ast::UintTy), +} + +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +pub struct Deprecation { + pub since: DeprecatedSince, + /// The note to issue a reason. + pub note: Option<Symbol>, + /// A text snippet used to completely replace any use of the deprecated item in an expression. + /// + /// This is currently unstable. + pub suggestion: Option<Symbol>, +} + +/// Release in which an API is deprecated. +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +pub enum DeprecatedSince { + RustcVersion(RustcVersion), + /// Deprecated in the future ("to be determined"). + Future, + /// `feature(staged_api)` is off. Deprecation versions outside the standard + /// library are allowed to be arbitrary strings, for better or worse. + NonStandard(Symbol), + /// Deprecation version is unspecified but optional. + Unspecified, + /// Failed to parse a deprecation version, or the deprecation version is + /// unspecified and required. An error has already been emitted. + Err, +} + +/// Successfully-parsed value of a `#[coverage(..)]` attribute. +#[derive(Copy, Debug, Eq, PartialEq, Encodable, Decodable, Clone)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum CoverageAttrKind { + On, + Off, +} + +impl Deprecation { + /// Whether an item marked with #[deprecated(since = "X")] is currently + /// deprecated (i.e., whether X is not greater than the current rustc + /// version). + pub fn is_in_effect(&self) -> bool { + match self.since { + DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT, + DeprecatedSince::Future => false, + // The `since` field doesn't have semantic purpose without `#![staged_api]`. + DeprecatedSince::NonStandard(_) => true, + // Assume deprecation is in effect if "since" field is absent or invalid. + DeprecatedSince::Unspecified | DeprecatedSince::Err => true, + } + } + + pub fn is_since_rustc_version(&self) -> bool { + matches!(self.since, DeprecatedSince::RustcVersion(_)) + } +} + +/// There are three valid forms of the attribute: +/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable. +/// `#[used(compiler)]` +/// `#[used(linker)]` +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum UsedBy { + Compiler, + Linker, +} + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum MacroUseArgs { + UseAll, + UseSpecific(ThinVec<Ident>), +} + +impl Default for MacroUseArgs { + fn default() -> Self { + Self::UseSpecific(ThinVec::new()) + } +} + +#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] +pub struct StrippedCfgItem<ModId = DefId> { + pub parent_module: ModId, + pub ident: Ident, + pub cfg: (CfgEntry, Span), +} + +impl<ModId> StrippedCfgItem<ModId> { + pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> { + StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } + } +} + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum CfgEntry { + All(ThinVec<CfgEntry>, Span), + Any(ThinVec<CfgEntry>, Span), + Not(Box<CfgEntry>, Span), + Bool(bool, Span), + NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span }, + Version(Option<RustcVersion>, Span), +} + +/// Represents parsed *built-in* inert attributes. +/// +/// ## Overview +/// These attributes are markers that guide the compilation process and are never expanded into other code. +/// They persist throughout the compilation phases, from AST to HIR and beyond. +/// +/// ## Attribute Processing +/// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams +/// because different attributes have different internal structures. This enum represents the final, +/// fully parsed form of these attributes, where each variant contains all the information and +/// structure relevant for the specific attribute. +/// +/// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single +/// semantic attribute. For example: +/// ```rust +/// #[repr(C)] +/// #[repr(packed)] +/// struct S { } +/// ``` +/// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing +/// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the +/// data structures defined in this enum. +/// +/// ## Usage +/// These parsed attributes are used throughout the compiler to: +/// - Control code generation (e.g., `#[repr]`) +/// - Mark API stability (`#[stable]`, `#[unstable]`) +/// - Provide documentation (`#[doc]`) +/// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`) +/// +/// ## Note on Attribute Organization +/// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately +/// from this enum because they are used in specific compiler phases (like code generation) and don't +/// need to persist throughout the entire compilation process. They are typically processed and +/// converted into their final form earlier in the compilation pipeline. +/// +/// For example: +/// - `InlineAttr` is used during code generation to control function inlining +/// - `OptimizeAttr` is used to control optimization levels +/// - `InstructionSetAttr` is used for target-specific code generation +/// +/// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate +/// and don't need to be preserved in the same way as the attributes in this enum. +/// +/// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate. +/// +/// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html +/// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html +/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum AttributeKind { + // tidy-alphabetical-start + /// Represents `#[align(N)]`. + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity + Align { align: Align, span: Span }, + + /// Represents `#[rustc_allow_const_fn_unstable]`. + AllowConstFnUnstable(ThinVec<Symbol>, Span), + + /// Represents `#[rustc_allow_incoherent_impl]`. + AllowIncoherentImpl(Span), + + /// Represents `#[allow_internal_unstable]`. + AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span), + + /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). + AsPtr(Span), + + /// Represents `#[automatically_derived]` + AutomaticallyDerived(Span), + + /// Represents `#[rustc_default_body_unstable]`. + BodyStability { + stability: DefaultBodyStability, + /// Span of the `#[rustc_default_body_unstable(...)]` attribute + span: Span, + }, + + /// Represents `#[rustc_coherence_is_core]`. + CoherenceIsCore, + + /// Represents `#[rustc_coinductive]`. + Coinductive(Span), + + /// Represents `#[cold]`. + Cold(Span), + + /// Represents `#[rustc_confusables]`. + Confusables { + symbols: ThinVec<Symbol>, + // FIXME(jdonszelmann): remove when target validation code is moved + first_span: Span, + }, + + /// Represents `#[const_continue]`. + ConstContinue(Span), + + /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`. + ConstStability { + stability: PartialConstStability, + /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute + span: Span, + }, + + /// Represents `#[rustc_const_stable_indirect]`. + ConstStabilityIndirect, + + /// Represents `#[const_trait]`. + ConstTrait(Span), + + /// Represents `#[coverage(..)]`. + Coverage(Span, CoverageAttrKind), + + ///Represents `#[rustc_deny_explicit_impl]`. + DenyExplicitImpl(Span), + + /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). + Deprecation { deprecation: Deprecation, span: Span }, + + /// Represents `#[rustc_do_not_implement_via_object]`. + DoNotImplementViaObject(Span), + + /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). + DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + + /// Represents `#[rustc_dummy]`. + Dummy, + + /// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute). + ExportName { + /// The name to export this item with. + /// It may not contain \0 bytes as it will be converted to a null-terminated string. + name: Symbol, + span: Span, + }, + + /// Represents `#[export_stable]`. + ExportStable, + + /// Represents `#[ffi_const]`. + FfiConst(Span), + + /// Represents `#[ffi_pure]`. + FfiPure(Span), + + /// Represents `#[fundamental]`. + Fundamental, + + /// Represents `#[ignore]` + Ignore { + span: Span, + /// ignore can optionally have a reason: `#[ignore = "reason this is ignored"]` + reason: Option<Symbol>, + }, + + /// Represents `#[inline]` and `#[rustc_force_inline]`. + Inline(InlineAttr, Span), + + /// Represents `#[link_name]`. + LinkName { name: Symbol, span: Span }, + + /// Represents `#[link_ordinal]`. + LinkOrdinal { ordinal: u16, span: Span }, + + /// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute) + LinkSection { name: Symbol, span: Span }, + + /// Represents `#[loop_match]`. + LoopMatch(Span), + + /// Represents `#[macro_escape]`. + MacroEscape(Span), + + /// Represents `#[rustc_macro_transparency]`. + MacroTransparency(Transparency), + + /// Represents `#[macro_use]`. + MacroUse { span: Span, arguments: MacroUseArgs }, + + /// Represents `#[marker]`. + Marker(Span), + + /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). + MayDangle(Span), + + /// Represents `#[must_use]`. + MustUse { + span: Span, + /// must_use can optionally have a reason: `#[must_use = "reason this must be used"]` + reason: Option<Symbol>, + }, + + /// Represents `#[naked]` + Naked(Span), + + /// Represents `#[no_implicit_prelude]` + NoImplicitPrelude(Span), + + /// Represents `#[no_mangle]` + NoMangle(Span), + + /// Represents `#[non_exhaustive]` + NonExhaustive(Span), + + /// Represents `#[omit_gdb_pretty_printer_section]` + OmitGdbPrettyPrinterSection, + + /// Represents `#[optimize(size|speed)]` + Optimize(OptimizeAttr, Span), + + /// Represents `#[rustc_paren_sugar]`. + ParenSugar(Span), + + /// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint). + PassByValue(Span), + + /// Represents `#[path]` + Path(Symbol, Span), + + /// Represents `#[pointee]` + Pointee(Span), + + /// Represents `#[proc_macro]` + ProcMacro(Span), + + /// Represents `#[proc_macro_attribute]` + ProcMacroAttribute(Span), + + /// Represents `#[proc_macro_derive]` + ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span }, + + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). + PubTransparent(Span), + + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). + Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span }, + + /// Represents `#[rustc_builtin_macro]`. + RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span }, + + /// Represents `#[rustc_layout_scalar_valid_range_end]`. + RustcLayoutScalarValidRangeEnd(Box<u128>, Span), + + /// Represents `#[rustc_layout_scalar_valid_range_start]`. + RustcLayoutScalarValidRangeStart(Box<u128>, Span), + + /// Represents `#[rustc_object_lifetime_default]`. + RustcObjectLifetimeDefault, + + /// Represents `#[rustc_skip_during_method_dispatch]`. + SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, + + /// Represents `#[rustc_specialization_trait]`. + SpecializationTrait(Span), + + /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. + Stability { + stability: Stability, + /// Span of the attribute. + span: Span, + }, + + /// Represents `#[rustc_std_internal_symbol]`. + StdInternalSymbol(Span), + + /// Represents `#[target_feature(enable = "...")]` + TargetFeature(ThinVec<(Symbol, Span)>, Span), + + /// Represents `#[track_caller]` + TrackCaller(Span), + + /// Represents `#[type_const]`. + TypeConst(Span), + + /// Represents `#[rustc_unsafe_specialization_marker]`. + UnsafeSpecializationMarker(Span), + + /// Represents `#[unstable_feature_bound]`. + UnstableFeatureBound(ThinVec<(Symbol, Span)>), + + /// Represents `#[used]` + Used { used_by: UsedBy, span: Span }, + // tidy-alphabetical-end +} diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs new file mode 100644 index 00000000000..bbdecb2986e --- /dev/null +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -0,0 +1,86 @@ +use crate::attrs::AttributeKind; + +#[derive(PartialEq)] +pub enum EncodeCrossCrate { + Yes, + No, +} + +impl AttributeKind { + pub fn encode_cross_crate(&self) -> EncodeCrossCrate { + use AttributeKind::*; + use EncodeCrossCrate::*; + + match self { + // tidy-alphabetical-start + Align { .. } => No, + AllowConstFnUnstable(..) => No, + AllowIncoherentImpl(..) => No, + AllowInternalUnstable(..) => Yes, + AsPtr(..) => Yes, + AutomaticallyDerived(..) => Yes, + BodyStability { .. } => No, + CoherenceIsCore => No, + Coinductive(..) => No, + Cold(..) => No, + Confusables { .. } => Yes, + ConstContinue(..) => No, + ConstStability { .. } => Yes, + ConstStabilityIndirect => No, + ConstTrait(..) => No, + Coverage(..) => No, + DenyExplicitImpl(..) => No, + Deprecation { .. } => Yes, + DoNotImplementViaObject(..) => No, + DocComment { .. } => Yes, + Dummy => No, + ExportName { .. } => Yes, + ExportStable => No, + FfiConst(..) => No, + FfiPure(..) => No, + Fundamental { .. } => Yes, + Ignore { .. } => No, + Inline(..) => No, + LinkName { .. } => Yes, // Needed for rustdoc + LinkOrdinal { .. } => No, + LinkSection { .. } => Yes, // Needed for rustdoc + LoopMatch(..) => No, + MacroEscape(..) => No, + MacroTransparency(..) => Yes, + MacroUse { .. } => No, + Marker(..) => No, + MayDangle(..) => No, + MustUse { .. } => Yes, + Naked(..) => No, + NoImplicitPrelude(..) => No, + NoMangle(..) => Yes, // Needed for rustdoc + NonExhaustive(..) => Yes, // Needed for rustdoc + OmitGdbPrettyPrinterSection => No, + Optimize(..) => No, + ParenSugar(..) => No, + PassByValue(..) => Yes, + Path(..) => No, + Pointee(..) => No, + ProcMacro(..) => No, + ProcMacroAttribute(..) => No, + ProcMacroDerive { .. } => No, + PubTransparent(..) => Yes, + Repr { .. } => No, + RustcBuiltinMacro { .. } => Yes, + RustcLayoutScalarValidRangeEnd(..) => Yes, + RustcLayoutScalarValidRangeStart(..) => Yes, + RustcObjectLifetimeDefault => No, + SkipDuringMethodDispatch { .. } => No, + SpecializationTrait(..) => No, + Stability { .. } => Yes, + StdInternalSymbol(..) => No, + TargetFeature(..) => No, + TrackCaller(..) => Yes, + TypeConst(..) => Yes, + UnsafeSpecializationMarker(..) => No, + UnstableFeatureBound(..) => No, + Used { .. } => No, + // tidy-alphabetical-end + } + } +} diff --git a/compiler/rustc_hir/src/attrs/mod.rs b/compiler/rustc_hir/src/attrs/mod.rs new file mode 100644 index 00000000000..482e6c90739 --- /dev/null +++ b/compiler/rustc_hir/src/attrs/mod.rs @@ -0,0 +1,54 @@ +//! Data structures for representing parsed attributes in the Rust compiler. +//! Formerly `rustc_attr_data_structures`. +//! +//! For detailed documentation about attribute processing, +//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html). + +pub use data_structures::*; +pub use encode_cross_crate::EncodeCrossCrate; +pub use pretty_printing::PrintAttribute; + +mod data_structures; +mod encode_cross_crate; +mod pretty_printing; + +/// Finds attributes in sequences of attributes by pattern matching. +/// +/// A little like `matches` but for attributes. +/// +/// ```rust,ignore (illustrative) +/// // finds the repr attribute +/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { +/// +/// } +/// +/// // checks if one has matched +/// if find_attr!(attrs, AttributeKind::Repr(_)) { +/// +/// } +/// ``` +/// +/// Often this requires you to first end up with a list of attributes. +/// A common way to get those is through `tcx.get_all_attrs(did)` +#[macro_export] +macro_rules! find_attr { + ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ + $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() + }}; + + ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ + 'done: { + for i in $attributes_list { + let i: &rustc_hir::Attribute = i; + match i { + rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { + break 'done Some($e); + } + _ => {} + } + } + + None + } + }}; +} diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs new file mode 100644 index 00000000000..e44b29141da --- /dev/null +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -0,0 +1,149 @@ +use std::num::NonZero; + +use rustc_abi::Align; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrStyle, IntTy, UintTy}; +use rustc_ast_pretty::pp::Printer; +use rustc_span::hygiene::Transparency; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; +use thin_vec::ThinVec; + +/// This trait is used to print attributes in `rustc_hir_pretty`. +/// +/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`]. +/// The output will look a lot like a `Debug` implementation, but fields of several types +/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the +/// representation much. +pub trait PrintAttribute { + /// Whether or not this will render as something meaningful, or if it's skipped + /// (which will force the containing struct to also skip printing a comma + /// and the field name). + fn should_render(&self) -> bool; + + fn print_attribute(&self, p: &mut Printer); +} + +impl PrintAttribute for u128 { + fn should_render(&self) -> bool { + true + } + + fn print_attribute(&self, p: &mut Printer) { + p.word(self.to_string()) + } +} + +impl<T: PrintAttribute> PrintAttribute for &T { + fn should_render(&self) -> bool { + T::should_render(self) + } + + fn print_attribute(&self, p: &mut Printer) { + T::print_attribute(self, p) + } +} +impl<T: PrintAttribute> PrintAttribute for Option<T> { + fn should_render(&self) -> bool { + self.as_ref().is_some_and(|x| x.should_render()) + } + + fn print_attribute(&self, p: &mut Printer) { + if let Some(i) = self { + T::print_attribute(i, p) + } + } +} +impl<T: PrintAttribute> PrintAttribute for ThinVec<T> { + fn should_render(&self) -> bool { + self.is_empty() || self[0].should_render() + } + + fn print_attribute(&self, p: &mut Printer) { + let mut last_printed = false; + p.word("["); + for i in self { + if last_printed { + p.word_space(","); + } + i.print_attribute(p); + last_printed = i.should_render(); + } + p.word("]"); + } +} +macro_rules! print_skip { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn should_render(&self) -> bool { false } + fn print_attribute(&self, _: &mut Printer) { } + })* + }; +} + +macro_rules! print_disp { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn should_render(&self) -> bool { true } + fn print_attribute(&self, p: &mut Printer) { + p.word(format!("{}", self)); + } + } + )*}; +} +macro_rules! print_debug { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn should_render(&self) -> bool { true } + fn print_attribute(&self, p: &mut Printer) { + p.word(format!("{:?}", self)); + } + } + )*}; +} + +macro_rules! print_tup { + (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* }; + () => {}; + ($t: ident $($ts: ident)*) => { + #[allow(non_snake_case, unused)] + impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) { + fn should_render(&self) -> bool { + let ($t, $($ts),*) = self; + print_tup!(num_should_render $t $($ts)*) != 0 + } + + fn print_attribute(&self, p: &mut Printer) { + let ($t, $($ts),*) = self; + let parens = print_tup!(num_should_render $t $($ts)*) > 1; + if parens { + p.popen(); + } + + let mut printed_anything = $t.should_render(); + + $t.print_attribute(p); + + $( + if $ts.should_render() { + if printed_anything { + p.word_space(","); + } + printed_anything = true; + } + $ts.print_attribute(p); + )* + + if parens { + p.pclose(); + } + } + } + + print_tup!($($ts)*); + }; +} + +print_tup!(A B C D E F G H); +print_skip!(Span, (), ErrorGuaranteed); +print_disp!(u16, bool, NonZero<u32>); +print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index ca57c4f3164..3fee9af01b3 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -295,6 +295,10 @@ impl DefKind { } } + pub fn is_assoc(self) -> bool { + matches!(self, DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy) + } + /// This is a "module" in name resolution sense. #[inline] pub fn is_module_like(self) -> bool { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e7898648c2b..08361718108 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -14,7 +14,6 @@ pub use rustc_ast::{ BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability, Mutability, UnOp, }; -use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::tagged_ptr::TaggedRef; @@ -30,6 +29,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::LangItem; +use crate::attrs::AttributeKind; use crate::def::{CtorKind, DefKind, PerNS, Res}; use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; @@ -148,6 +148,11 @@ impl From<Ident> for LifetimeSyntax { /// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing` /// — there's no way to "elide" these lifetimes. #[derive(Debug, Copy, Clone, HashStable_Generic)] +// Raise the aligement to at least 4 bytes - this is relied on in other parts of the compiler(for pointer tagging): +// https://github.com/rust-lang/rust/blob/ce5fdd7d42aba9a2925692e11af2bd39cf37798a/compiler/rustc_data_structures/src/tagged_ptr.rs#L163 +// Removing this `repr(4)` will cause the compiler to not build on platforms like `m68k` Linux, where the aligement of u32 and usize is only 2. +// Since `repr(align)` may only raise aligement, this has no effect on platforms where the aligement is already sufficient. +#[repr(align(4))] pub struct Lifetime { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -1302,6 +1307,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, + Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, @@ -1362,6 +1368,17 @@ impl AttributeExt for Attribute { _ => None, } } + + fn is_proc_macro_attr(&self) -> bool { + matches!( + self, + Attribute::Parsed( + AttributeKind::ProcMacro(..) + | AttributeKind::ProcMacroAttribute(..) + | AttributeKind::ProcMacroDerive { .. } + ) + ) + } } // FIXME(fn_delegation): use function delegation instead of manually forwarding @@ -2999,7 +3016,7 @@ impl fmt::Display for LoopIdError { } } -#[derive(Copy, Clone, Debug, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable_Generic)] pub struct Destination { /// This is `Some(_)` iff there is an explicit user-specified 'label pub label: Option<Label>, diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 6347f1bfa71..75c04b23ed6 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -345,9 +345,6 @@ language_item_table! { OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1); GlobalAlloc, sym::global_alloc_ty, global_alloc_ty, Target::Struct, GenericRequirement::None; - // Experimental lang item for Miri - PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1); - PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index dafd31336fb..f1212d07ff6 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -18,6 +18,7 @@ extern crate self as rustc_hir; mod arena; +pub mod attrs; pub mod def; pub mod def_path_hash_map; pub mod definitions; @@ -29,8 +30,10 @@ pub mod intravisit; pub mod lang_items; pub mod lints; pub mod pat_util; +mod stability; mod stable_hash_impls; mod target; +mod version; pub mod weak_lang_items; #[cfg(test)] @@ -40,7 +43,9 @@ mod tests; pub use hir::*; pub use hir_id::*; pub use lang_items::{LangItem, LanguageItems}; +pub use stability::*; pub use stable_hash_impls::HashStableContext; pub use target::{MethodKind, Target}; +pub use version::*; arena_types!(rustc_arena::declare_arena); diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 7be6c32e57e..c55a41eb2b7 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,9 +1,16 @@ -use rustc_attr_data_structures::lints::AttributeLint; use rustc_data_structures::fingerprint::Fingerprint; use rustc_macros::HashStable_Generic; +use rustc_span::Span; use crate::HirId; +#[derive(Debug)] +pub struct DelayedLints { + pub lints: Box<[DelayedLint]>, + // Only present when the crate hash is needed. + pub opt_hash: Option<Fingerprint>, +} + /// During ast lowering, no lints can be emitted. /// That is because lints attach to nodes either in the AST, or on the built HIR. /// When attached to AST nodes, they're emitted just before building HIR, @@ -15,9 +22,16 @@ pub enum DelayedLint { AttributeParsing(AttributeLint<HirId>), } -#[derive(Debug)] -pub struct DelayedLints { - pub lints: Box<[DelayedLint]>, - // Only present when the crate hash is needed. - pub opt_hash: Option<Fingerprint>, +#[derive(Clone, Debug, HashStable_Generic)] +pub struct AttributeLint<Id> { + pub id: Id, + pub span: Span, + pub kind: AttributeLintKind, +} + +#[derive(Clone, Debug, HashStable_Generic)] +pub enum AttributeLintKind { + UnusedDuplicate { this: Span, other: Span, warning: bool }, + IllFormedAttributeInput { suggestions: Vec<String> }, + EmptyAttribute { first_span: Span }, } diff --git a/compiler/rustc_hir/src/stability.rs b/compiler/rustc_hir/src/stability.rs new file mode 100644 index 00000000000..2b3a2a79316 --- /dev/null +++ b/compiler/rustc_hir/src/stability.rs @@ -0,0 +1,207 @@ +use std::num::NonZero; + +use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_span::{ErrorGuaranteed, Symbol, sym}; + +use crate::RustcVersion; +use crate::attrs::PrintAttribute; + +/// The version placeholder that recently stabilized features contain inside the +/// `since` field of the `#[stable]` attribute. +/// +/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591). +pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N"); +// Note that the `concat!` macro above prevents `src/tools/replace-version-placeholder` from +// replacing the constant with the current version. Hardcoding the tool to skip this file doesn't +// work as the file can (and at some point will) be moved around. +// +// Turning the `concat!` macro into a string literal will make Pietro cry. That'd be sad :( + +/// Represents the following attributes: +/// +/// - `#[stable]` +/// - `#[unstable]` +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub struct Stability { + pub level: StabilityLevel, + pub feature: Symbol, +} + +impl Stability { + pub fn is_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_stable(&self) -> bool { + self.level.is_stable() + } + + pub fn stable_since(&self) -> Option<StableSince> { + self.level.stable_since() + } +} + +/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub struct ConstStability { + pub level: StabilityLevel, + pub feature: Symbol, + /// whether the function has a `#[rustc_promotable]` attribute + pub promotable: bool, + /// This is true iff the `const_stable_indirect` attribute is present. + pub const_stable_indirect: bool, +} + +impl ConstStability { + pub fn from_partial( + PartialConstStability { level, feature, promotable }: PartialConstStability, + const_stable_indirect: bool, + ) -> Self { + Self { const_stable_indirect, level, feature, promotable } + } + + /// The stability assigned to unmarked items when -Zforce-unstable-if-unmarked is set. + pub fn unmarked(const_stable_indirect: bool, regular_stab: Stability) -> Self { + Self { + feature: regular_stab.feature, + promotable: false, + level: regular_stab.level, + const_stable_indirect, + } + } + + pub fn is_const_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_const_stable(&self) -> bool { + self.level.is_stable() + } +} + +/// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked` +/// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub struct PartialConstStability { + pub level: StabilityLevel, + pub feature: Symbol, + /// whether the function has a `#[rustc_promotable]` attribute + pub promotable: bool, +} + +impl PartialConstStability { + pub fn is_const_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_const_stable(&self) -> bool { + self.level.is_stable() + } +} + +/// The available stability levels. +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum StabilityLevel { + /// `#[unstable]` + Unstable { + /// Reason for the current stability level. + reason: UnstableReason, + /// Relevant `rust-lang/rust` issue. + issue: Option<NonZero<u32>>, + is_soft: bool, + /// If part of a feature is stabilized and a new feature is added for the remaining parts, + /// then the `implied_by` attribute is used to indicate which now-stable feature previously + /// contained an item. + /// + /// ```pseudo-Rust + /// #[unstable(feature = "foo", issue = "...")] + /// fn foo() {} + /// #[unstable(feature = "foo", issue = "...")] + /// fn foobar() {} + /// ``` + /// + /// ...becomes... + /// + /// ```pseudo-Rust + /// #[stable(feature = "foo", since = "1.XX.X")] + /// fn foo() {} + /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")] + /// fn foobar() {} + /// ``` + implied_by: Option<Symbol>, + old_name: Option<Symbol>, + }, + /// `#[stable]` + Stable { + /// Rust release which stabilized this feature. + since: StableSince, + /// This is `Some` if this item allowed to be referred to on stable via unstable modules; + /// the `Symbol` is the deprecation message printed in that case. + allowed_through_unstable_modules: Option<Symbol>, + }, +} + +/// Rust release in which a feature is stabilized. +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum StableSince { + /// also stores the original symbol for printing + Version(RustcVersion), + /// Stabilized in the upcoming version, whatever number that is. + Current, + /// Failed to parse a stabilization version. + Err(ErrorGuaranteed), +} + +impl StabilityLevel { + pub fn is_unstable(&self) -> bool { + matches!(self, StabilityLevel::Unstable { .. }) + } + pub fn is_stable(&self) -> bool { + matches!(self, StabilityLevel::Stable { .. }) + } + pub fn stable_since(&self) -> Option<StableSince> { + match *self { + StabilityLevel::Stable { since, .. } => Some(since), + StabilityLevel::Unstable { .. } => None, + } + } +} + +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum UnstableReason { + None, + Default, + Some(Symbol), +} + +/// Represents the `#[rustc_default_body_unstable]` attribute. +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub struct DefaultBodyStability { + pub level: StabilityLevel, + pub feature: Symbol, +} + +impl UnstableReason { + pub fn from_opt_reason(reason: Option<Symbol>) -> Self { + // UnstableReason::Default constructed manually + match reason { + Some(r) => Self::Some(r), + None => Self::None, + } + } + + pub fn to_opt_reason(&self) -> Option<Symbol> { + match self { + Self::None => None, + Self::Default => Some(sym::unstable_location_reason_default), + Self::Some(r) => Some(*r), + } + } +} diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 6acf1524b60..ecc608d437b 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -11,11 +11,7 @@ use crate::lints::DelayedLints; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: - rustc_attr_data_structures::HashStableContext - + rustc_ast::HashStableContext - + rustc_abi::HashStableContext -{ +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext { fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher); } diff --git a/compiler/rustc_hir/src/version.rs b/compiler/rustc_hir/src/version.rs new file mode 100644 index 00000000000..ab5ab026b4c --- /dev/null +++ b/compiler/rustc_hir/src/version.rs @@ -0,0 +1,47 @@ +use std::fmt::{self, Display}; +use std::sync::OnceLock; + +use rustc_macros::{ + Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, +}; + +use crate::attrs::PrintAttribute; + +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub struct RustcVersion { + pub major: u16, + pub minor: u16, + pub patch: u16, +} + +impl RustcVersion { + pub const CURRENT: Self = current_rustc_version!(); + pub fn current_overridable() -> Self { + *CURRENT_OVERRIDABLE.get_or_init(|| { + if let Ok(override_var) = std::env::var("RUSTC_OVERRIDE_VERSION_STRING") + && let Some(override_) = Self::parse_str(&override_var) + { + override_ + } else { + Self::CURRENT + } + }) + } + fn parse_str(value: &str) -> Option<Self> { + // Ignore any suffixes such as "-dev" or "-nightly". + let mut components = value.split('-').next().unwrap().splitn(3, '.'); + let major = components.next()?.parse().ok()?; + let minor = components.next()?.parse().ok()?; + let patch = components.next().unwrap_or("0").parse().ok()?; + Some(RustcVersion { major, minor, patch }) + } +} + +static CURRENT_OVERRIDABLE: OnceLock<RustcVersion> = OnceLock::new(); + +impl Display for RustcVersion { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) + } +} |
