mv compiler to compiler/
This commit is contained in:
parent
db534b3ac2
commit
9e5f7d5631
1686 changed files with 941 additions and 1051 deletions
52
compiler/rustc_hir/src/arena.rs
Normal file
52
compiler/rustc_hir/src/arena.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
/// This declares a list of types which can be allocated by `Arena`.
|
||||
///
|
||||
/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
|
||||
/// This is faster and more memory efficient if there's only a few allocations of the type.
|
||||
/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
|
||||
/// faster and more memory efficient if there is lots of allocations.
|
||||
///
|
||||
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]`,
|
||||
/// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro.
|
||||
#[macro_export]
|
||||
macro_rules! arena_types {
|
||||
($macro:path, $args:tt, $tcx:lifetime) => (
|
||||
$macro!($args, [
|
||||
// HIR types
|
||||
[few] hir_krate: rustc_hir::Crate<$tcx>,
|
||||
[] arm: rustc_hir::Arm<$tcx>,
|
||||
[] asm_operand: rustc_hir::InlineAsmOperand<$tcx>,
|
||||
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
|
||||
[] attribute: rustc_ast::Attribute,
|
||||
[] block: rustc_hir::Block<$tcx>,
|
||||
[] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
|
||||
[few] global_asm: rustc_hir::GlobalAsm,
|
||||
[] generic_arg: rustc_hir::GenericArg<$tcx>,
|
||||
[] generic_args: rustc_hir::GenericArgs<$tcx>,
|
||||
[] generic_bound: rustc_hir::GenericBound<$tcx>,
|
||||
[] generic_param: rustc_hir::GenericParam<$tcx>,
|
||||
[] expr: rustc_hir::Expr<$tcx>,
|
||||
[] field: rustc_hir::Field<$tcx>,
|
||||
[] field_pat: rustc_hir::FieldPat<$tcx>,
|
||||
[] fn_decl: rustc_hir::FnDecl<$tcx>,
|
||||
[] foreign_item: rustc_hir::ForeignItem<$tcx>,
|
||||
[] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
|
||||
[few] inline_asm: rustc_hir::InlineAsm<$tcx>,
|
||||
[few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
|
||||
[] local: rustc_hir::Local<$tcx>,
|
||||
[few] macro_def: rustc_hir::MacroDef<$tcx>,
|
||||
[] param: rustc_hir::Param<$tcx>,
|
||||
[] pat: rustc_hir::Pat<$tcx>,
|
||||
[] path: rustc_hir::Path<$tcx>,
|
||||
[] path_segment: rustc_hir::PathSegment<$tcx>,
|
||||
[] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>,
|
||||
[] qpath: rustc_hir::QPath<$tcx>,
|
||||
[] stmt: rustc_hir::Stmt<$tcx>,
|
||||
[] struct_field: rustc_hir::StructField<$tcx>,
|
||||
[] trait_item_ref: rustc_hir::TraitItemRef,
|
||||
[] ty: rustc_hir::Ty<$tcx>,
|
||||
[] type_binding: rustc_hir::TypeBinding<$tcx>,
|
||||
[] variant: rustc_hir::Variant<$tcx>,
|
||||
[] where_predicate: rustc_hir::WherePredicate<$tcx>,
|
||||
], $tcx);
|
||||
)
|
||||
}
|
469
compiler/rustc_hir/src/def.rs
Normal file
469
compiler/rustc_hir/src/def.rs
Normal file
|
@ -0,0 +1,469 @@
|
|||
use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use crate::hir;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum CtorOf {
|
||||
/// This `DefKind::Ctor` is a synthesized constructor of a tuple or unit struct.
|
||||
Struct,
|
||||
/// This `DefKind::Ctor` is a synthesized constructor of a tuple or unit variant.
|
||||
Variant,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum CtorKind {
|
||||
/// Constructor function automatically created by a tuple struct/variant.
|
||||
Fn,
|
||||
/// Constructor constant automatically created by a unit struct/variant.
|
||||
Const,
|
||||
/// Unusable name in value namespace created by a struct variant.
|
||||
Fictive,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum NonMacroAttrKind {
|
||||
/// Single-segment attribute defined by the language (`#[inline]`)
|
||||
Builtin,
|
||||
/// Multi-segment custom attribute living in a "tool module" (`#[rustfmt::skip]`).
|
||||
Tool,
|
||||
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
|
||||
DeriveHelper,
|
||||
/// Single-segment custom attribute registered with `#[register_attr]`.
|
||||
Registered,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum DefKind {
|
||||
// Type namespace
|
||||
Mod,
|
||||
/// Refers to the struct itself, `DefKind::Ctor` refers to its constructor if it exists.
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
/// Refers to the variant itself, `DefKind::Ctor` refers to its constructor if it exists.
|
||||
Variant,
|
||||
Trait,
|
||||
/// `type Foo = Bar;`
|
||||
TyAlias,
|
||||
ForeignTy,
|
||||
TraitAlias,
|
||||
AssocTy,
|
||||
TyParam,
|
||||
|
||||
// Value namespace
|
||||
Fn,
|
||||
Const,
|
||||
ConstParam,
|
||||
Static,
|
||||
/// Refers to the struct or enum variant's constructor.
|
||||
Ctor(CtorOf, CtorKind),
|
||||
AssocFn,
|
||||
AssocConst,
|
||||
|
||||
// Macro namespace
|
||||
Macro(MacroKind),
|
||||
|
||||
// Not namespaced (or they are, but we don't treat them so)
|
||||
ExternCrate,
|
||||
Use,
|
||||
ForeignMod,
|
||||
AnonConst,
|
||||
OpaqueTy,
|
||||
Field,
|
||||
LifetimeParam,
|
||||
GlobalAsm,
|
||||
Impl,
|
||||
Closure,
|
||||
Generator,
|
||||
}
|
||||
|
||||
impl DefKind {
|
||||
pub fn descr(self, def_id: DefId) -> &'static str {
|
||||
match self {
|
||||
DefKind::Fn => "function",
|
||||
DefKind::Mod if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
|
||||
"crate"
|
||||
}
|
||||
DefKind::Mod => "module",
|
||||
DefKind::Static => "static",
|
||||
DefKind::Enum => "enum",
|
||||
DefKind::Variant => "variant",
|
||||
DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant",
|
||||
DefKind::Ctor(CtorOf::Variant, CtorKind::Const) => "unit variant",
|
||||
DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive) => "struct variant",
|
||||
DefKind::Struct => "struct",
|
||||
DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
|
||||
DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
|
||||
DefKind::Ctor(CtorOf::Struct, CtorKind::Fictive) => {
|
||||
panic!("impossible struct constructor")
|
||||
}
|
||||
DefKind::OpaqueTy => "opaque type",
|
||||
DefKind::TyAlias => "type alias",
|
||||
DefKind::TraitAlias => "trait alias",
|
||||
DefKind::AssocTy => "associated type",
|
||||
DefKind::Union => "union",
|
||||
DefKind::Trait => "trait",
|
||||
DefKind::ForeignTy => "foreign type",
|
||||
DefKind::AssocFn => "associated function",
|
||||
DefKind::Const => "constant",
|
||||
DefKind::AssocConst => "associated constant",
|
||||
DefKind::TyParam => "type parameter",
|
||||
DefKind::ConstParam => "const parameter",
|
||||
DefKind::Macro(macro_kind) => macro_kind.descr(),
|
||||
DefKind::LifetimeParam => "lifetime parameter",
|
||||
DefKind::Use => "import",
|
||||
DefKind::ForeignMod => "foreign module",
|
||||
DefKind::AnonConst => "constant expression",
|
||||
DefKind::Field => "field",
|
||||
DefKind::Impl => "implementation",
|
||||
DefKind::Closure => "closure",
|
||||
DefKind::Generator => "generator",
|
||||
DefKind::ExternCrate => "extern crate",
|
||||
DefKind::GlobalAsm => "global assembly block",
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets an English article for the definition.
|
||||
pub fn article(&self) -> &'static str {
|
||||
match *self {
|
||||
DefKind::AssocTy
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Enum
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl
|
||||
| DefKind::Use
|
||||
| DefKind::ExternCrate => "an",
|
||||
DefKind::Macro(macro_kind) => macro_kind.article(),
|
||||
_ => "a",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ns(&self) -> Option<Namespace> {
|
||||
match self {
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
| DefKind::Enum
|
||||
| DefKind::Variant
|
||||
| DefKind::Trait
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::AssocTy
|
||||
| DefKind::TyParam => Some(Namespace::TypeNS),
|
||||
|
||||
DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst => Some(Namespace::ValueNS),
|
||||
|
||||
DefKind::Macro(..) => Some(Namespace::MacroNS),
|
||||
|
||||
// Not namespaced.
|
||||
DefKind::AnonConst
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolution of a path or export.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum Res<Id = hir::HirId> {
|
||||
Def(DefKind, DefId),
|
||||
|
||||
// Type namespace
|
||||
PrimTy(hir::PrimTy),
|
||||
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
|
||||
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
|
||||
|
||||
// Value namespace
|
||||
SelfCtor(DefId /* impl */), // `DefId` refers to the impl
|
||||
Local(Id),
|
||||
|
||||
// Macro namespace
|
||||
NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]`
|
||||
|
||||
// All namespaces
|
||||
Err,
|
||||
}
|
||||
|
||||
/// The result of resolving a path before lowering to HIR,
|
||||
/// with "module" segments resolved and associated item
|
||||
/// segments deferred to type checking.
|
||||
/// `base_res` is the resolution of the resolved part of the
|
||||
/// path, `unresolved_segments` is the number of unresolved
|
||||
/// segments.
|
||||
///
|
||||
/// ```text
|
||||
/// module::Type::AssocX::AssocY::MethodOrAssocType
|
||||
/// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/// base_res unresolved_segments = 3
|
||||
///
|
||||
/// <T as Trait>::AssocX::AssocY::MethodOrAssocType
|
||||
/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
/// base_res unresolved_segments = 2
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PartialRes {
|
||||
base_res: Res<NodeId>,
|
||||
unresolved_segments: usize,
|
||||
}
|
||||
|
||||
impl PartialRes {
|
||||
#[inline]
|
||||
pub fn new(base_res: Res<NodeId>) -> Self {
|
||||
PartialRes { base_res, unresolved_segments: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_unresolved_segments(base_res: Res<NodeId>, mut unresolved_segments: usize) -> Self {
|
||||
if base_res == Res::Err {
|
||||
unresolved_segments = 0
|
||||
}
|
||||
PartialRes { base_res, unresolved_segments }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn base_res(&self) -> Res<NodeId> {
|
||||
self.base_res
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unresolved_segments(&self) -> usize {
|
||||
self.unresolved_segments
|
||||
}
|
||||
}
|
||||
|
||||
/// Different kinds of symbols don't influence each other.
|
||||
///
|
||||
/// Therefore, they have a separate universe (namespace).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub enum Namespace {
|
||||
TypeNS,
|
||||
ValueNS,
|
||||
MacroNS,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
pub fn descr(self) -> &'static str {
|
||||
match self {
|
||||
Self::TypeNS => "type",
|
||||
Self::ValueNS => "value",
|
||||
Self::MacroNS => "macro",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Just a helper ‒ separate structure for each namespace.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct PerNS<T> {
|
||||
pub value_ns: T,
|
||||
pub type_ns: T,
|
||||
pub macro_ns: T,
|
||||
}
|
||||
|
||||
impl<T> PerNS<T> {
|
||||
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> PerNS<U> {
|
||||
PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, ns: Namespace) -> &T {
|
||||
match ns {
|
||||
Namespace::ValueNS => &self.value_ns,
|
||||
Namespace::TypeNS => &self.type_ns,
|
||||
Namespace::MacroNS => &self.macro_ns,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
|
||||
fn index_mut(&mut self, ns: Namespace) -> &mut T {
|
||||
match ns {
|
||||
Namespace::ValueNS => &mut self.value_ns,
|
||||
Namespace::TypeNS => &mut self.type_ns,
|
||||
Namespace::MacroNS => &mut self.macro_ns,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PerNS<Option<T>> {
|
||||
/// Returns `true` if all the items in this collection are `None`.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the items which are `Some`.
|
||||
pub fn present_items(self) -> impl Iterator<Item = T> {
|
||||
use std::iter::once;
|
||||
|
||||
once(self.type_ns).chain(once(self.value_ns)).chain(once(self.macro_ns)).filter_map(|it| it)
|
||||
}
|
||||
}
|
||||
|
||||
impl CtorKind {
|
||||
pub fn from_ast(vdata: &ast::VariantData) -> CtorKind {
|
||||
match *vdata {
|
||||
ast::VariantData::Tuple(..) => CtorKind::Fn,
|
||||
ast::VariantData::Unit(..) => CtorKind::Const,
|
||||
ast::VariantData::Struct(..) => CtorKind::Fictive,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_hir(vdata: &hir::VariantData<'_>) -> CtorKind {
|
||||
match *vdata {
|
||||
hir::VariantData::Tuple(..) => CtorKind::Fn,
|
||||
hir::VariantData::Unit(..) => CtorKind::Const,
|
||||
hir::VariantData::Struct(..) => CtorKind::Fictive,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NonMacroAttrKind {
|
||||
pub fn descr(self) -> &'static str {
|
||||
match self {
|
||||
NonMacroAttrKind::Builtin => "built-in attribute",
|
||||
NonMacroAttrKind::Tool => "tool attribute",
|
||||
NonMacroAttrKind::DeriveHelper => "derive helper attribute",
|
||||
NonMacroAttrKind::Registered => "explicitly registered attribute",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn article(self) -> &'static str {
|
||||
match self {
|
||||
NonMacroAttrKind::Registered => "an",
|
||||
_ => "a",
|
||||
}
|
||||
}
|
||||
|
||||
/// Users of some attributes cannot mark them as used, so they are considered always used.
|
||||
pub fn is_used(self) -> bool {
|
||||
match self {
|
||||
NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper => true,
|
||||
NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Id> Res<Id> {
|
||||
/// Return the `DefId` of this `Def` if it has an ID, else panic.
|
||||
pub fn def_id(&self) -> DefId
|
||||
where
|
||||
Id: Debug,
|
||||
{
|
||||
self.opt_def_id()
|
||||
.unwrap_or_else(|| panic!("attempted .def_id() on invalid res: {:?}", self))
|
||||
}
|
||||
|
||||
/// Return `Some(..)` with the `DefId` of this `Res` if it has a ID, else `None`.
|
||||
pub fn opt_def_id(&self) -> Option<DefId> {
|
||||
match *self {
|
||||
Res::Def(_, id) => Some(id),
|
||||
|
||||
Res::Local(..)
|
||||
| Res::PrimTy(..)
|
||||
| Res::SelfTy(..)
|
||||
| Res::SelfCtor(..)
|
||||
| Res::ToolMod
|
||||
| Res::NonMacroAttr(..)
|
||||
| Res::Err => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the `DefId` of this `Res` if it represents a module.
|
||||
pub fn mod_def_id(&self) -> Option<DefId> {
|
||||
match *self {
|
||||
Res::Def(DefKind::Mod, id) => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A human readable name for the res kind ("function", "module", etc.).
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match *self {
|
||||
Res::Def(kind, def_id) => kind.descr(def_id),
|
||||
Res::SelfCtor(..) => "self constructor",
|
||||
Res::PrimTy(..) => "builtin type",
|
||||
Res::Local(..) => "local variable",
|
||||
Res::SelfTy(..) => "self type",
|
||||
Res::ToolMod => "tool module",
|
||||
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
|
||||
Res::Err => "unresolved item",
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets an English article for the `Res`.
|
||||
pub fn article(&self) -> &'static str {
|
||||
match *self {
|
||||
Res::Def(kind, _) => kind.article(),
|
||||
Res::NonMacroAttr(kind) => kind.article(),
|
||||
Res::Err => "an",
|
||||
_ => "a",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_id<R>(self, mut map: impl FnMut(Id) -> R) -> Res<R> {
|
||||
match self {
|
||||
Res::Def(kind, id) => Res::Def(kind, id),
|
||||
Res::SelfCtor(id) => Res::SelfCtor(id),
|
||||
Res::PrimTy(id) => Res::PrimTy(id),
|
||||
Res::Local(id) => Res::Local(map(id)),
|
||||
Res::SelfTy(a, b) => Res::SelfTy(a, b),
|
||||
Res::ToolMod => Res::ToolMod,
|
||||
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
|
||||
Res::Err => Res::Err,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn macro_kind(self) -> Option<MacroKind> {
|
||||
match self {
|
||||
Res::Def(DefKind::Macro(kind), _) => Some(kind),
|
||||
Res::NonMacroAttr(..) => Some(MacroKind::Attr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `None` if this is `Res::Err`
|
||||
pub fn ns(&self) -> Option<Namespace> {
|
||||
match self {
|
||||
Res::Def(kind, ..) => kind.ns(),
|
||||
Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS),
|
||||
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
|
||||
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
|
||||
Res::Err => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Always returns `true` if `self` is `Res::Err`
|
||||
pub fn matches_ns(&self, ns: Namespace) -> bool {
|
||||
self.ns().map_or(true, |actual_ns| actual_ns == ns)
|
||||
}
|
||||
}
|
457
compiler/rustc_hir/src/definitions.rs
Normal file
457
compiler/rustc_hir/src/definitions.rs
Normal file
|
@ -0,0 +1,457 @@
|
|||
//! For each definition, we track the following data. A definition
|
||||
//! here is defined somewhat circularly as "something with a `DefId`",
|
||||
//! but it generally corresponds to things like structs, enums, etc.
|
||||
//! There are also some rather random cases (like const initializer
|
||||
//! expressions) that are mostly just leftovers.
|
||||
|
||||
pub use crate::def_id::DefPathHash;
|
||||
use crate::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use crate::hir;
|
||||
|
||||
use rustc_ast::crate_disambiguator::CrateDisambiguator;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::hash::Hash;
|
||||
use tracing::debug;
|
||||
|
||||
/// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
|
||||
/// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
|
||||
/// stores the `DefIndex` of its parent.
|
||||
/// There is one `DefPathTable` for each crate.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DefPathTable {
|
||||
index_to_key: IndexVec<DefIndex, DefKey>,
|
||||
def_path_hashes: IndexVec<DefIndex, DefPathHash>,
|
||||
}
|
||||
|
||||
impl DefPathTable {
|
||||
fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
|
||||
let index = {
|
||||
let index = DefIndex::from(self.index_to_key.len());
|
||||
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
|
||||
self.index_to_key.push(key);
|
||||
index
|
||||
};
|
||||
self.def_path_hashes.push(def_path_hash);
|
||||
debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
|
||||
index
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn def_key(&self, index: DefIndex) -> DefKey {
|
||||
self.index_to_key[index]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
|
||||
let hash = self.def_path_hashes[index];
|
||||
debug!("def_path_hash({:?}) = {:?}", index, hash);
|
||||
hash
|
||||
}
|
||||
|
||||
pub fn num_def_ids(&self) -> usize {
|
||||
self.index_to_key.len()
|
||||
}
|
||||
|
||||
pub fn enumerated_keys_and_path_hashes(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
|
||||
self.index_to_key
|
||||
.iter_enumerated()
|
||||
.map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
|
||||
}
|
||||
|
||||
pub fn all_def_path_hashes_and_def_ids(
|
||||
&self,
|
||||
krate: CrateNum,
|
||||
) -> impl Iterator<Item = (DefPathHash, DefId)> + '_ {
|
||||
self.def_path_hashes
|
||||
.iter_enumerated()
|
||||
.map(move |(index, hash)| (*hash, DefId { krate, index }))
|
||||
}
|
||||
}
|
||||
|
||||
/// The definition table containing node definitions.
|
||||
/// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
|
||||
/// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
|
||||
#[derive(Clone)]
|
||||
pub struct Definitions {
|
||||
table: DefPathTable,
|
||||
|
||||
// FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
|
||||
pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
|
||||
/// The reverse mapping of `def_id_to_hir_id`.
|
||||
pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
|
||||
|
||||
/// If `ExpnId` is an ID of some macro expansion,
|
||||
/// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
|
||||
parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
|
||||
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
|
||||
expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
|
||||
}
|
||||
|
||||
/// A unique identifier that we can use to lookup a definition
|
||||
/// precisely. It combines the index of the definition's parent (if
|
||||
/// any) with a `DisambiguatedDefPathData`.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
|
||||
pub struct DefKey {
|
||||
/// The parent path.
|
||||
pub parent: Option<DefIndex>,
|
||||
|
||||
/// The identifier of this node.
|
||||
pub disambiguated_data: DisambiguatedDefPathData,
|
||||
}
|
||||
|
||||
impl DefKey {
|
||||
fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
|
||||
let mut hasher = StableHasher::new();
|
||||
|
||||
// We hash a `0u8` here to disambiguate between regular `DefPath` hashes,
|
||||
// and the special "root_parent" below.
|
||||
0u8.hash(&mut hasher);
|
||||
parent_hash.hash(&mut hasher);
|
||||
|
||||
let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
|
||||
|
||||
::std::mem::discriminant(data).hash(&mut hasher);
|
||||
if let Some(name) = data.get_opt_name() {
|
||||
// Get a stable hash by considering the symbol chars rather than
|
||||
// the symbol index.
|
||||
name.as_str().hash(&mut hasher);
|
||||
}
|
||||
|
||||
disambiguator.hash(&mut hasher);
|
||||
|
||||
DefPathHash(hasher.finish())
|
||||
}
|
||||
|
||||
fn root_parent_stable_hash(
|
||||
crate_name: &str,
|
||||
crate_disambiguator: CrateDisambiguator,
|
||||
) -> DefPathHash {
|
||||
let mut hasher = StableHasher::new();
|
||||
// Disambiguate this from a regular `DefPath` hash; see `compute_stable_hash()` above.
|
||||
1u8.hash(&mut hasher);
|
||||
crate_name.hash(&mut hasher);
|
||||
crate_disambiguator.hash(&mut hasher);
|
||||
DefPathHash(hasher.finish())
|
||||
}
|
||||
}
|
||||
|
||||
/// A pair of `DefPathData` and an integer disambiguator. The integer is
|
||||
/// normally `0`, but in the event that there are multiple defs with the
|
||||
/// same `parent` and `data`, we use this field to disambiguate
|
||||
/// between them. This introduces some artificial ordering dependency
|
||||
/// but means that if you have, e.g., two impls for the same type in
|
||||
/// the same module, they do get distinct `DefId`s.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable)]
|
||||
pub struct DisambiguatedDefPathData {
|
||||
pub data: DefPathData,
|
||||
pub disambiguator: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub struct DefPath {
|
||||
/// The path leading from the crate root to the item.
|
||||
pub data: Vec<DisambiguatedDefPathData>,
|
||||
|
||||
/// The crate root this path is relative to.
|
||||
pub krate: CrateNum,
|
||||
}
|
||||
|
||||
impl DefPath {
|
||||
pub fn is_local(&self) -> bool {
|
||||
self.krate == LOCAL_CRATE
|
||||
}
|
||||
|
||||
pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
|
||||
where
|
||||
FN: FnMut(DefIndex) -> DefKey,
|
||||
{
|
||||
let mut data = vec![];
|
||||
let mut index = Some(start_index);
|
||||
loop {
|
||||
debug!("DefPath::make: krate={:?} index={:?}", krate, index);
|
||||
let p = index.unwrap();
|
||||
let key = get_key(p);
|
||||
debug!("DefPath::make: key={:?}", key);
|
||||
match key.disambiguated_data.data {
|
||||
DefPathData::CrateRoot => {
|
||||
assert!(key.parent.is_none());
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
data.push(key.disambiguated_data);
|
||||
index = key.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
data.reverse();
|
||||
DefPath { data, krate }
|
||||
}
|
||||
|
||||
/// Returns a string representation of the `DefPath` without
|
||||
/// the crate-prefix. This method is useful if you don't have
|
||||
/// a `TyCtxt` available.
|
||||
pub fn to_string_no_crate(&self) -> String {
|
||||
let mut s = String::with_capacity(self.data.len() * 16);
|
||||
|
||||
for component in &self.data {
|
||||
write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// Returns a filename-friendly string for the `DefPath`, with the
|
||||
/// crate-prefix.
|
||||
pub fn to_string_friendly<F>(&self, crate_imported_name: F) -> String
|
||||
where
|
||||
F: FnOnce(CrateNum) -> Symbol,
|
||||
{
|
||||
let crate_name_str = crate_imported_name(self.krate).as_str();
|
||||
let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16);
|
||||
|
||||
write!(s, "::{}", crate_name_str).unwrap();
|
||||
|
||||
for component in &self.data {
|
||||
if component.disambiguator == 0 {
|
||||
write!(s, "::{}", component.data.as_symbol()).unwrap();
|
||||
} else {
|
||||
write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// Returns a filename-friendly string of the `DefPath`, without
|
||||
/// the crate-prefix. This method is useful if you don't have
|
||||
/// a `TyCtxt` available.
|
||||
pub fn to_filename_friendly_no_crate(&self) -> String {
|
||||
let mut s = String::with_capacity(self.data.len() * 16);
|
||||
|
||||
let mut opt_delimiter = None;
|
||||
for component in &self.data {
|
||||
s.extend(opt_delimiter);
|
||||
opt_delimiter = Some('-');
|
||||
if component.disambiguator == 0 {
|
||||
write!(s, "{}", component.data.as_symbol()).unwrap();
|
||||
} else {
|
||||
write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum DefPathData {
|
||||
// Root: these should only be used for the root nodes, because
|
||||
// they are treated specially by the `def_path` function.
|
||||
/// The crate root (marker).
|
||||
CrateRoot,
|
||||
// Catch-all for random `DefId` things like `DUMMY_NODE_ID`.
|
||||
Misc,
|
||||
|
||||
// Different kinds of items and item-like things:
|
||||
/// An impl.
|
||||
Impl,
|
||||
/// Something in the type namespace.
|
||||
TypeNs(Symbol),
|
||||
/// Something in the value namespace.
|
||||
ValueNs(Symbol),
|
||||
/// Something in the macro namespace.
|
||||
MacroNs(Symbol),
|
||||
/// Something in the lifetime namespace.
|
||||
LifetimeNs(Symbol),
|
||||
/// A closure expression.
|
||||
ClosureExpr,
|
||||
|
||||
// Subportions of items:
|
||||
/// Implicit constructor for a unit or tuple-like struct or enum variant.
|
||||
Ctor,
|
||||
/// A constant expression (see `{ast,hir}::AnonConst`).
|
||||
AnonConst,
|
||||
/// An `impl Trait` type node.
|
||||
ImplTrait,
|
||||
}
|
||||
|
||||
impl Definitions {
|
||||
pub fn def_path_table(&self) -> &DefPathTable {
|
||||
&self.table
|
||||
}
|
||||
|
||||
/// Gets the number of definitions.
|
||||
pub fn def_index_count(&self) -> usize {
|
||||
self.table.index_to_key.len()
|
||||
}
|
||||
|
||||
pub fn def_key(&self, id: LocalDefId) -> DefKey {
|
||||
self.table.def_key(id.local_def_index)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
|
||||
self.table.def_path_hash(id.local_def_index)
|
||||
}
|
||||
|
||||
/// Returns the path from the crate root to `index`. The root
|
||||
/// nodes are not included in the path (i.e., this will be an
|
||||
/// empty vector for the crate root). For an inlined item, this
|
||||
/// will be the path of the item in the external crate (but the
|
||||
/// path will begin with the path to the external crate).
|
||||
pub fn def_path(&self, id: LocalDefId) -> DefPath {
|
||||
DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
|
||||
self.def_key(LocalDefId { local_def_index: index })
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
|
||||
self.def_id_to_hir_id[id].unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option<hir::HirId> {
|
||||
self.def_id_to_hir_id[id]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
|
||||
self.hir_id_to_def_id.get(&hir_id).copied()
|
||||
}
|
||||
|
||||
/// Adds a root definition (no parent) and a few other reserved definitions.
|
||||
pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
|
||||
let key = DefKey {
|
||||
parent: None,
|
||||
disambiguated_data: DisambiguatedDefPathData {
|
||||
data: DefPathData::CrateRoot,
|
||||
disambiguator: 0,
|
||||
},
|
||||
};
|
||||
|
||||
let parent_hash = DefKey::root_parent_stable_hash(crate_name, crate_disambiguator);
|
||||
let def_path_hash = key.compute_stable_hash(parent_hash);
|
||||
|
||||
// Create the root definition.
|
||||
let mut table = DefPathTable::default();
|
||||
let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
|
||||
assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
|
||||
|
||||
Definitions {
|
||||
table,
|
||||
def_id_to_hir_id: Default::default(),
|
||||
hir_id_to_def_id: Default::default(),
|
||||
expansions_that_defined: Default::default(),
|
||||
parent_modules_of_macro_defs: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the root definition.
|
||||
pub fn get_root_def(&self) -> LocalDefId {
|
||||
LocalDefId { local_def_index: CRATE_DEF_INDEX }
|
||||
}
|
||||
|
||||
/// Adds a definition with a parent definition.
|
||||
pub fn create_def(
|
||||
&mut self,
|
||||
parent: LocalDefId,
|
||||
data: DefPathData,
|
||||
expn_id: ExpnId,
|
||||
mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
|
||||
) -> LocalDefId {
|
||||
debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
|
||||
|
||||
// The root node must be created with `create_root_def()`.
|
||||
assert!(data != DefPathData::CrateRoot);
|
||||
|
||||
let disambiguator = next_disambiguator(parent, data);
|
||||
let key = DefKey {
|
||||
parent: Some(parent.local_def_index),
|
||||
disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
|
||||
};
|
||||
|
||||
let parent_hash = self.table.def_path_hash(parent.local_def_index);
|
||||
let def_path_hash = key.compute_stable_hash(parent_hash);
|
||||
|
||||
debug!("create_def: after disambiguation, key = {:?}", key);
|
||||
|
||||
// Create the definition.
|
||||
let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
|
||||
|
||||
if expn_id != ExpnId::root() {
|
||||
self.expansions_that_defined.insert(def_id, expn_id);
|
||||
}
|
||||
|
||||
def_id
|
||||
}
|
||||
|
||||
/// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
|
||||
/// AST to HIR lowering.
|
||||
pub fn init_def_id_to_hir_id_mapping(
|
||||
&mut self,
|
||||
mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
|
||||
) {
|
||||
assert!(
|
||||
self.def_id_to_hir_id.is_empty(),
|
||||
"trying to initialize `LocalDefId` <-> `HirId` mappings twice"
|
||||
);
|
||||
|
||||
// Build the reverse mapping of `def_id_to_hir_id`.
|
||||
self.hir_id_to_def_id = mapping
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
|
||||
.collect();
|
||||
|
||||
self.def_id_to_hir_id = mapping;
|
||||
}
|
||||
|
||||
pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
|
||||
self.expansions_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
|
||||
}
|
||||
|
||||
pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
|
||||
self.parent_modules_of_macro_defs[&expn_id]
|
||||
}
|
||||
|
||||
pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
|
||||
self.parent_modules_of_macro_defs.insert(expn_id, module);
|
||||
}
|
||||
}
|
||||
|
||||
impl DefPathData {
|
||||
pub fn get_opt_name(&self) -> Option<Symbol> {
|
||||
use self::DefPathData::*;
|
||||
match *self {
|
||||
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
|
||||
|
||||
Impl | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_symbol(&self) -> Symbol {
|
||||
use self::DefPathData::*;
|
||||
match *self {
|
||||
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => name,
|
||||
// Note that this does not show up in user print-outs.
|
||||
CrateRoot => sym::double_braced_crate,
|
||||
Impl => sym::double_braced_impl,
|
||||
Misc => sym::double_braced_misc,
|
||||
ClosureExpr => sym::double_braced_closure,
|
||||
Ctor => sym::double_braced_constructor,
|
||||
AnonConst => sym::double_braced_constant,
|
||||
ImplTrait => sym::double_braced_opaque,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
self.as_symbol().to_string()
|
||||
}
|
||||
}
|
2773
compiler/rustc_hir/src/hir.rs
Normal file
2773
compiler/rustc_hir/src/hir.rs
Normal file
File diff suppressed because it is too large
Load diff
49
compiler/rustc_hir/src/hir_id.rs
Normal file
49
compiler/rustc_hir/src/hir_id.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
|
||||
use std::fmt;
|
||||
|
||||
/// Uniquely identifies a node in the HIR of the current crate. It is
|
||||
/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
|
||||
/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
|
||||
/// and the `local_id` which is unique within the given owner.
|
||||
///
|
||||
/// This two-level structure makes for more stable values: One can move an item
|
||||
/// around within the source code, or add or remove stuff before it, without
|
||||
/// the `local_id` part of the `HirId` changing, which is a very useful property in
|
||||
/// incremental compilation where we have to persist things through changes to
|
||||
/// the code base.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub struct HirId {
|
||||
pub owner: LocalDefId,
|
||||
pub local_id: ItemLocalId,
|
||||
}
|
||||
|
||||
impl fmt::Display for HirId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
rustc_data_structures::define_id_collections!(HirIdMap, HirIdSet, HirId);
|
||||
rustc_data_structures::define_id_collections!(ItemLocalMap, ItemLocalSet, ItemLocalId);
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// An `ItemLocalId` uniquely identifies something within a given "item-like";
|
||||
/// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
|
||||
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
|
||||
/// the node's position within the owning item in any way, but there is a
|
||||
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
|
||||
/// integers starting at zero, so a mapping that maps all or most nodes within
|
||||
/// an "item-like" to something else can be implemented by a `Vec` instead of a
|
||||
/// tree or hash map.
|
||||
pub struct ItemLocalId { .. }
|
||||
}
|
||||
rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
|
||||
|
||||
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
|
||||
pub const CRATE_HIR_ID: HirId = HirId {
|
||||
owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
|
||||
local_id: ItemLocalId::from_u32(0),
|
||||
};
|
||||
|
||||
pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX;
|
1222
compiler/rustc_hir/src/intravisit.rs
Normal file
1222
compiler/rustc_hir/src/intravisit.rs
Normal file
File diff suppressed because it is too large
Load diff
57
compiler/rustc_hir/src/itemlikevisit.rs
Normal file
57
compiler/rustc_hir/src/itemlikevisit.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use super::{ImplItem, Item, TraitItem};
|
||||
|
||||
/// The "item-like visitor" defines only the top-level methods
|
||||
/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
|
||||
/// this trait is the right one to implement will depend on the
|
||||
/// overall pattern you need. Here are the three available patterns,
|
||||
/// in roughly the order of desirability:
|
||||
///
|
||||
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
||||
/// - Example: find all items with a `#[foo]` attribute on them.
|
||||
/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().krate().visit_all_item_likes()`.
|
||||
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
|
||||
/// - Con: Don't get information about nesting
|
||||
/// - Con: Don't have methods for specific bits of HIR, like "on
|
||||
/// every expr, do this".
|
||||
/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
|
||||
/// an item, but don't care about how item-like things are nested
|
||||
/// within one another.
|
||||
/// - Example: Examine each expression to look for its type and do some check or other.
|
||||
/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
|
||||
/// to return `NestedVisitorMap::OnlyBodies` and use
|
||||
/// `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within
|
||||
/// your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget
|
||||
/// to invoke `intravisit::walk_expr()` to keep walking the subparts).
|
||||
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
|
||||
/// - Pro: Integrates well into dependency tracking.
|
||||
/// - Con: Don't get information about nesting between items
|
||||
/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
|
||||
/// item-like things.
|
||||
/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the
|
||||
/// impl into scope while visiting the impl-items, and then back out again.
|
||||
/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
|
||||
/// to return `NestedVisitorMap::All`. Walk your crate with `intravisit::walk_crate()`
|
||||
/// invoked on `tcx.hir().krate()`.
|
||||
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
|
||||
/// - Pro: Preserves nesting information
|
||||
/// - Con: Does not integrate well into dependency tracking.
|
||||
///
|
||||
/// Note: the methods of `ItemLikeVisitor` intentionally have no
|
||||
/// defaults, so that as we expand the list of item-like things, we
|
||||
/// revisit the various visitors to see if they need to change. This
|
||||
/// is harder to do with `intravisit::Visitor`, so when you add a new
|
||||
/// `visit_nested_foo()` method, it is recommended that you search for
|
||||
/// existing `fn visit_nested` methods to see where changes are
|
||||
/// needed.
|
||||
pub trait ItemLikeVisitor<'hir> {
|
||||
fn visit_item(&mut self, item: &'hir Item<'hir>);
|
||||
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>);
|
||||
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>);
|
||||
}
|
||||
|
||||
/// A parallel variant of `ItemLikeVisitor`.
|
||||
pub trait ParItemLikeVisitor<'hir> {
|
||||
fn visit_item(&self, item: &'hir Item<'hir>);
|
||||
fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>);
|
||||
fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>);
|
||||
}
|
334
compiler/rustc_hir/src/lang_items.rs
Normal file
334
compiler/rustc_hir/src/lang_items.rs
Normal file
|
@ -0,0 +1,334 @@
|
|||
//! Defines language items.
|
||||
//!
|
||||
//! Language items are items that represent concepts intrinsic to the language
|
||||
//! itself. Examples are:
|
||||
//!
|
||||
//! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
|
||||
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
|
||||
//! * Functions called by the compiler itself.
|
||||
|
||||
use crate::def_id::DefId;
|
||||
use crate::{MethodKind, Target};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub enum LangItemGroup {
|
||||
Op,
|
||||
}
|
||||
|
||||
const NUM_GROUPS: usize = 1;
|
||||
|
||||
macro_rules! expand_group {
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($group:expr) => {
|
||||
Some($group)
|
||||
};
|
||||
}
|
||||
|
||||
// The actual lang items defined come at the end of this file in one handy table.
|
||||
// So you probably just want to nip down to the end.
|
||||
macro_rules! language_item_table {
|
||||
(
|
||||
$( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
|
||||
) => {
|
||||
|
||||
enum_from_u32! {
|
||||
/// A representation of all the valid language items in Rust.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum LangItem {
|
||||
$($variant,)*
|
||||
}
|
||||
}
|
||||
|
||||
impl LangItem {
|
||||
/// Returns the `name` symbol in `#[lang = "$name"]`.
|
||||
/// For example, `LangItem::EqTraitLangItem`,
|
||||
/// that is `#[lang = "eq"]` would result in `sym::eq`.
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
$( LangItem::$variant => $name, )*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn group(self) -> Option<LangItemGroup> {
|
||||
use LangItemGroup::*;
|
||||
match self {
|
||||
$( LangItem::$variant => expand_group!($($group)*), )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct LanguageItems {
|
||||
/// Mappings from lang items to their possibly found `DefId`s.
|
||||
/// The index corresponds to the order in `LangItem`.
|
||||
pub items: Vec<Option<DefId>>,
|
||||
/// Lang items that were not found during collection.
|
||||
pub missing: Vec<LangItem>,
|
||||
/// Mapping from `LangItemGroup` discriminants to all
|
||||
/// `DefId`s of lang items in that group.
|
||||
pub groups: [Vec<DefId>; NUM_GROUPS],
|
||||
}
|
||||
|
||||
impl LanguageItems {
|
||||
/// Construct an empty collection of lang items and no missing ones.
|
||||
pub fn new() -> Self {
|
||||
fn init_none(_: LangItem) -> Option<DefId> { None }
|
||||
|
||||
Self {
|
||||
items: vec![$(init_none(LangItem::$variant)),*],
|
||||
missing: Vec::new(),
|
||||
groups: [vec![]; NUM_GROUPS],
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the mappings to the possibly found `DefId`s for each lang item.
|
||||
pub fn items(&self) -> &[Option<DefId>] {
|
||||
&*self.items
|
||||
}
|
||||
|
||||
/// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
|
||||
/// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
|
||||
/// returns an error message as a string.
|
||||
pub fn require(&self, it: LangItem) -> Result<DefId, String> {
|
||||
self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
|
||||
}
|
||||
|
||||
pub fn group(&self, group: LangItemGroup) -> &[DefId] {
|
||||
self.groups[group as usize].as_ref()
|
||||
}
|
||||
|
||||
$(
|
||||
/// Returns the corresponding `DefId` for the lang item if it
|
||||
/// exists.
|
||||
#[allow(dead_code)]
|
||||
pub fn $method(&self) -> Option<DefId> {
|
||||
self.items[LangItem::$variant as usize]
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// A mapping from the name of the lang item to its order and the form it must be of.
|
||||
pub static ref ITEM_REFS: FxHashMap<Symbol, (usize, Target)> = {
|
||||
let mut item_refs = FxHashMap::default();
|
||||
$( item_refs.insert($name, (LangItem::$variant as usize, $target)); )*
|
||||
item_refs
|
||||
};
|
||||
}
|
||||
|
||||
// End of the macro
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for LangItem {
|
||||
fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
|
||||
::std::hash::Hash::hash(self, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the first `lang = "$name"` out of a list of attributes.
|
||||
/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
|
||||
/// are also extracted out when found.
|
||||
///
|
||||
/// About the `check_name` argument: passing in a `Session` would be simpler,
|
||||
/// because then we could call `Session::check_name` directly. But we want to
|
||||
/// avoid the need for `librustc_hir` to depend on `librustc_session`, so we
|
||||
/// use a closure instead.
|
||||
pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
|
||||
where
|
||||
F: Fn(&'a ast::Attribute, Symbol) -> bool,
|
||||
{
|
||||
attrs.iter().find_map(|attr| {
|
||||
Some(match attr {
|
||||
_ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
|
||||
_ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
|
||||
_ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
|
||||
_ => return None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
language_item_table! {
|
||||
// Variant name, Name, Method name, Target;
|
||||
Bool, sym::bool, bool_impl, Target::Impl;
|
||||
Char, sym::char, char_impl, Target::Impl;
|
||||
Str, sym::str, str_impl, Target::Impl;
|
||||
Array, sym::array, array_impl, Target::Impl;
|
||||
Slice, sym::slice, slice_impl, Target::Impl;
|
||||
SliceU8, sym::slice_u8, slice_u8_impl, Target::Impl;
|
||||
StrAlloc, sym::str_alloc, str_alloc_impl, Target::Impl;
|
||||
SliceAlloc, sym::slice_alloc, slice_alloc_impl, Target::Impl;
|
||||
SliceU8Alloc, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl;
|
||||
ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl;
|
||||
MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl;
|
||||
ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl;
|
||||
MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl;
|
||||
I8, sym::i8, i8_impl, Target::Impl;
|
||||
I16, sym::i16, i16_impl, Target::Impl;
|
||||
I32, sym::i32, i32_impl, Target::Impl;
|
||||
I64, sym::i64, i64_impl, Target::Impl;
|
||||
I128, sym::i128, i128_impl, Target::Impl;
|
||||
Isize, sym::isize, isize_impl, Target::Impl;
|
||||
U8, sym::u8, u8_impl, Target::Impl;
|
||||
U16, sym::u16, u16_impl, Target::Impl;
|
||||
U32, sym::u32, u32_impl, Target::Impl;
|
||||
U64, sym::u64, u64_impl, Target::Impl;
|
||||
U128, sym::u128, u128_impl, Target::Impl;
|
||||
Usize, sym::usize, usize_impl, Target::Impl;
|
||||
F32, sym::f32, f32_impl, Target::Impl;
|
||||
F64, sym::f64, f64_impl, Target::Impl;
|
||||
F32Runtime, sym::f32_runtime, f32_runtime_impl, Target::Impl;
|
||||
F64Runtime, sym::f64_runtime, f64_runtime_impl, Target::Impl;
|
||||
|
||||
Sized, sym::sized, sized_trait, Target::Trait;
|
||||
Unsize, sym::unsize, unsize_trait, Target::Trait;
|
||||
// Trait injected by #[derive(PartialEq)], (i.e. "Partial EQ").
|
||||
StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait;
|
||||
// Trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize).
|
||||
StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait;
|
||||
Copy, sym::copy, copy_trait, Target::Trait;
|
||||
Clone, sym::clone, clone_trait, Target::Trait;
|
||||
Sync, sym::sync, sync_trait, Target::Trait;
|
||||
DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait;
|
||||
// The associated item of `trait DiscriminantKind`.
|
||||
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
|
||||
|
||||
Freeze, sym::freeze, freeze_trait, Target::Trait;
|
||||
|
||||
Drop, sym::drop, drop_trait, Target::Trait;
|
||||
|
||||
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait;
|
||||
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait;
|
||||
|
||||
Add(Op), sym::add, add_trait, Target::Trait;
|
||||
Sub(Op), sym::sub, sub_trait, Target::Trait;
|
||||
Mul(Op), sym::mul, mul_trait, Target::Trait;
|
||||
Div(Op), sym::div, div_trait, Target::Trait;
|
||||
Rem(Op), sym::rem, rem_trait, Target::Trait;
|
||||
Neg(Op), sym::neg, neg_trait, Target::Trait;
|
||||
Not(Op), sym::not, not_trait, Target::Trait;
|
||||
BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait;
|
||||
BitAnd(Op), sym::bitand, bitand_trait, Target::Trait;
|
||||
BitOr(Op), sym::bitor, bitor_trait, Target::Trait;
|
||||
Shl(Op), sym::shl, shl_trait, Target::Trait;
|
||||
Shr(Op), sym::shr, shr_trait, Target::Trait;
|
||||
AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait;
|
||||
SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait;
|
||||
MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait;
|
||||
DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait;
|
||||
RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait;
|
||||
BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait;
|
||||
BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait;
|
||||
BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait;
|
||||
ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait;
|
||||
ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait;
|
||||
Index(Op), sym::index, index_trait, Target::Trait;
|
||||
IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait;
|
||||
|
||||
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct;
|
||||
VaList, sym::va_list, va_list, Target::Struct;
|
||||
|
||||
Deref, sym::deref, deref_trait, Target::Trait;
|
||||
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
|
||||
Receiver, sym::receiver, receiver_trait, Target::Trait;
|
||||
|
||||
Fn, kw::Fn, fn_trait, Target::Trait;
|
||||
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait;
|
||||
FnOnce, sym::fn_once, fn_once_trait, Target::Trait;
|
||||
|
||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy;
|
||||
|
||||
Future, sym::future_trait, future_trait, Target::Trait;
|
||||
GeneratorState, sym::generator_state, gen_state, Target::Enum;
|
||||
Generator, sym::generator, gen_trait, Target::Trait;
|
||||
Unpin, sym::unpin, unpin_trait, Target::Trait;
|
||||
Pin, sym::pin, pin_type, Target::Struct;
|
||||
|
||||
PartialEq, sym::eq, eq_trait, Target::Trait;
|
||||
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait;
|
||||
|
||||
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
|
||||
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
|
||||
//
|
||||
// The `begin_unwind` lang item has a predefined symbol name and is sort of a "weak lang item"
|
||||
// in the sense that a crate is not required to have it defined to use it, but a final product
|
||||
// is required to define it somewhere. Additionally, there are restrictions on crates that use
|
||||
// a weak lang item, but do not have it defined.
|
||||
Panic, sym::panic, panic_fn, Target::Fn;
|
||||
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn;
|
||||
PanicInfo, sym::panic_info, panic_info, Target::Struct;
|
||||
PanicLocation, sym::panic_location, panic_location, Target::Struct;
|
||||
PanicImpl, sym::panic_impl, panic_impl, Target::Fn;
|
||||
// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn;
|
||||
|
||||
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn;
|
||||
BoxFree, sym::box_free, box_free_fn, Target::Fn;
|
||||
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn;
|
||||
Oom, sym::oom, oom, Target::Fn;
|
||||
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct;
|
||||
|
||||
Start, sym::start, start_fn, Target::Fn;
|
||||
|
||||
EhPersonality, sym::eh_personality, eh_personality, Target::Fn;
|
||||
EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static;
|
||||
|
||||
OwnedBox, sym::owned_box, owned_box, Target::Struct;
|
||||
|
||||
PhantomData, sym::phantom_data, phantom_data, Target::Struct;
|
||||
|
||||
ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct;
|
||||
|
||||
MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union;
|
||||
|
||||
// Align offset for stride != 1; must not panic.
|
||||
AlignOffset, sym::align_offset, align_offset_fn, Target::Fn;
|
||||
|
||||
Termination, sym::termination, termination, Target::Trait;
|
||||
|
||||
Try, kw::Try, try_trait, Target::Trait;
|
||||
|
||||
// Language items from AST lowering
|
||||
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
|
||||
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
|
||||
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
|
||||
|
||||
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
|
||||
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
|
||||
|
||||
FromGenerator, sym::from_generator, from_generator_fn, Target::Fn;
|
||||
GetContext, sym::get_context, get_context_fn, Target::Fn;
|
||||
|
||||
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false });
|
||||
|
||||
FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false });
|
||||
|
||||
OptionSome, sym::Some, option_some_variant, Target::Variant;
|
||||
OptionNone, sym::None, option_none_variant, Target::Variant;
|
||||
|
||||
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
|
||||
ResultErr, sym::Err, result_err_variant, Target::Variant;
|
||||
|
||||
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
|
||||
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
|
||||
|
||||
PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent);
|
||||
|
||||
RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct;
|
||||
RangeFull, sym::RangeFull, range_full_struct, Target::Struct;
|
||||
RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct;
|
||||
RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent);
|
||||
Range, sym::Range, range_struct, Target::Struct;
|
||||
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct;
|
||||
RangeTo, sym::RangeTo, range_to_struct, Target::Struct;
|
||||
}
|
36
compiler/rustc_hir/src/lib.rs
Normal file
36
compiler/rustc_hir/src/lib.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
//! HIR datatypes. See the [rustc dev guide] for more info.
|
||||
//!
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
|
||||
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(const_fn)] // For the unsizing cast on `&[]`
|
||||
#![feature(const_panic)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(or_patterns)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_data_structures;
|
||||
|
||||
mod arena;
|
||||
pub mod def;
|
||||
pub mod definitions;
|
||||
pub use rustc_span::def_id;
|
||||
mod hir;
|
||||
pub mod hir_id;
|
||||
pub mod intravisit;
|
||||
pub mod itemlikevisit;
|
||||
pub mod lang_items;
|
||||
pub mod pat_util;
|
||||
mod stable_hash_impls;
|
||||
mod target;
|
||||
pub mod weak_lang_items;
|
||||
|
||||
pub use hir::*;
|
||||
pub use hir_id::*;
|
||||
pub use lang_items::{LangItem, LanguageItems};
|
||||
pub use stable_hash_impls::HashStableContext;
|
||||
pub use target::{MethodKind, Target};
|
194
compiler/rustc_hir/src/pat_util.rs
Normal file
194
compiler/rustc_hir/src/pat_util.rs
Normal file
|
@ -0,0 +1,194 @@
|
|||
use crate::def::{CtorOf, DefKind, Res};
|
||||
use crate::def_id::DefId;
|
||||
use crate::hir::{self, HirId, PatKind};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::iter::{Enumerate, ExactSizeIterator};
|
||||
|
||||
pub struct EnumerateAndAdjust<I> {
|
||||
enumerate: Enumerate<I>,
|
||||
gap_pos: usize,
|
||||
gap_len: usize,
|
||||
}
|
||||
|
||||
impl<I> Iterator for EnumerateAndAdjust<I>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
type Item = (usize, <I as Iterator>::Item);
|
||||
|
||||
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
|
||||
self.enumerate
|
||||
.next()
|
||||
.map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.enumerate.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EnumerateAndAdjustIterator {
|
||||
fn enumerate_and_adjust(
|
||||
self,
|
||||
expected_len: usize,
|
||||
gap_pos: Option<usize>,
|
||||
) -> EnumerateAndAdjust<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
|
||||
fn enumerate_and_adjust(
|
||||
self,
|
||||
expected_len: usize,
|
||||
gap_pos: Option<usize>,
|
||||
) -> EnumerateAndAdjust<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let actual_len = self.len();
|
||||
EnumerateAndAdjust {
|
||||
enumerate: self.enumerate(),
|
||||
gap_pos: gap_pos.unwrap_or(expected_len),
|
||||
gap_len: expected_len - actual_len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl hir::Pat<'_> {
|
||||
pub fn is_refutable(&self) -> bool {
|
||||
match self.kind {
|
||||
PatKind::Lit(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => {
|
||||
true
|
||||
}
|
||||
|
||||
PatKind::Path(hir::QPath::Resolved(_, ref path))
|
||||
| PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..)
|
||||
| PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res {
|
||||
Res::Def(DefKind::Variant, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PatKind::Slice(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`
|
||||
pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) {
|
||||
self.walk_always(|p| {
|
||||
if let PatKind::Binding(binding_mode, _, ident, _) = p.kind {
|
||||
f(binding_mode, p.hir_id, p.span, ident);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`.
|
||||
///
|
||||
/// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
|
||||
pub fn each_binding_or_first(
|
||||
&self,
|
||||
f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident),
|
||||
) {
|
||||
self.walk(|p| match &p.kind {
|
||||
PatKind::Or(ps) => {
|
||||
ps[0].each_binding_or_first(f);
|
||||
false
|
||||
}
|
||||
PatKind::Binding(bm, _, ident, _) => {
|
||||
f(*bm, p.hir_id, p.span, *ident);
|
||||
true
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any patterns that bind something to
|
||||
/// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
|
||||
pub fn contains_bindings(&self) -> bool {
|
||||
self.satisfies(|p| match p.kind {
|
||||
PatKind::Binding(..) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any patterns that bind something to
|
||||
/// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
|
||||
pub fn contains_bindings_or_wild(&self) -> bool {
|
||||
self.satisfies(|p| match p.kind {
|
||||
PatKind::Binding(..) | PatKind::Wild => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the pattern satisfies the given predicate on some sub-pattern.
|
||||
fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool {
|
||||
let mut satisfies = false;
|
||||
self.walk_short(|p| {
|
||||
if pred(p) {
|
||||
satisfies = true;
|
||||
false // Found one, can short circuit now.
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
satisfies
|
||||
}
|
||||
|
||||
pub fn simple_ident(&self) -> Option<Ident> {
|
||||
match self.kind {
|
||||
PatKind::Binding(
|
||||
hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
|
||||
_,
|
||||
ident,
|
||||
None,
|
||||
) => Some(ident),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns variants that are necessary to exist for the pattern to match.
|
||||
pub fn necessary_variants(&self) -> Vec<DefId> {
|
||||
let mut variants = vec![];
|
||||
self.walk(|p| match &p.kind {
|
||||
PatKind::Or(_) => false,
|
||||
PatKind::Path(hir::QPath::Resolved(_, path))
|
||||
| PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
|
||||
| PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
|
||||
if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
|
||||
path.res
|
||||
{
|
||||
variants.push(id);
|
||||
}
|
||||
true
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
variants.sort();
|
||||
variants.dedup();
|
||||
variants
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
|
||||
/// yes whether it contains mutable or just immutables ones.
|
||||
//
|
||||
// FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
|
||||
// ref bindings are be implicit after #42640 (default match binding modes). See issue #44848.
|
||||
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
let mut result = None;
|
||||
self.each_binding(|annotation, _, _, _| match annotation {
|
||||
hir::BindingAnnotation::Ref => match result {
|
||||
None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
|
||||
_ => {}
|
||||
},
|
||||
hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut),
|
||||
_ => {}
|
||||
});
|
||||
result
|
||||
}
|
||||
}
|
167
compiler/rustc_hir/src/stable_hash_impls.rs
Normal file
167
compiler/rustc_hir/src/stable_hash_impls.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||
|
||||
use crate::hir::{
|
||||
BodyId, Expr, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId, Ty,
|
||||
VisibilityKind,
|
||||
};
|
||||
use crate::hir_id::{HirId, ItemLocalId};
|
||||
use rustc_span::def_id::{DefPathHash, LocalDefId};
|
||||
|
||||
/// 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 librustc_middle.
|
||||
pub trait HashStableContext:
|
||||
rustc_ast::HashStableContext + rustc_target::HashStableContext
|
||||
{
|
||||
fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher);
|
||||
fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher);
|
||||
fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher);
|
||||
fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher);
|
||||
fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher);
|
||||
fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
|
||||
fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
|
||||
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
|
||||
fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash;
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
|
||||
type KeyType = (DefPathHash, ItemLocalId);
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
|
||||
let def_path_hash = hcx.local_def_path_hash(self.owner);
|
||||
(def_path_hash, self.local_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
|
||||
type KeyType = (DefPathHash, ItemLocalId);
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
|
||||
self.hir_id.to_stable_hash_key(hcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
|
||||
type KeyType = (DefPathHash, ItemLocalId);
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
|
||||
self.hir_id.to_stable_hash_key(hcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HirId {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_hir_id(*self, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for BodyId {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_body_id(*self, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
// The following implementations of HashStable for `ItemId`, `TraitItemId`, and
|
||||
// `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within
|
||||
// the HIR, since they just signify a HIR nodes own path. But `ItemId` et al
|
||||
// are used when another item in the HIR is *referenced* and we certainly
|
||||
// want to pick up on a reference changing its target, so we hash the NodeIds
|
||||
// in "DefPath Mode".
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ItemId {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_reference_to_item(self.id, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItemId {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_reference_to_item(self.hir_id, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_reference_to_item(self.hir_id, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Mod<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_hir_mod(self, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_hir_expr(self, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Ty<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_hir_ty(self, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for VisibilityKind<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
hcx.hash_hir_visibility_kind(self, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItem<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
let TraitItem { hir_id: _, ident, ref attrs, ref generics, ref kind, span } = *self;
|
||||
|
||||
hcx.hash_hir_item_like(|hcx| {
|
||||
ident.name.hash_stable(hcx, hasher);
|
||||
attrs.hash_stable(hcx, hasher);
|
||||
generics.hash_stable(hcx, hasher);
|
||||
kind.hash_stable(hcx, hasher);
|
||||
span.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
let ImplItem {
|
||||
hir_id: _,
|
||||
ident,
|
||||
ref vis,
|
||||
defaultness,
|
||||
ref attrs,
|
||||
ref generics,
|
||||
ref kind,
|
||||
span,
|
||||
} = *self;
|
||||
|
||||
hcx.hash_hir_item_like(|hcx| {
|
||||
ident.name.hash_stable(hcx, hasher);
|
||||
vis.hash_stable(hcx, hasher);
|
||||
defaultness.hash_stable(hcx, hasher);
|
||||
attrs.hash_stable(hcx, hasher);
|
||||
generics.hash_stable(hcx, hasher);
|
||||
kind.hash_stable(hcx, hasher);
|
||||
span.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
let Item { ident, ref attrs, hir_id: _, ref kind, ref vis, span } = *self;
|
||||
|
||||
hcx.hash_hir_item_like(|hcx| {
|
||||
ident.name.hash_stable(hcx, hasher);
|
||||
attrs.hash_stable(hcx, hasher);
|
||||
kind.hash_stable(hcx, hasher);
|
||||
vis.hash_stable(hcx, hasher);
|
||||
span.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
127
compiler/rustc_hir/src/target.rs
Normal file
127
compiler/rustc_hir/src/target.rs
Normal file
|
@ -0,0 +1,127 @@
|
|||
//! This module implements some validity checks for attributes.
|
||||
//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
|
||||
//! attached to items that actually support them and if there are
|
||||
//! conflicts between multiple such attributes attached to the same
|
||||
//! item.
|
||||
|
||||
use crate::hir;
|
||||
use crate::{Item, ItemKind, TraitItem, TraitItemKind};
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum MethodKind {
|
||||
Trait { body: bool },
|
||||
Inherent,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Target {
|
||||
ExternCrate,
|
||||
Use,
|
||||
Static,
|
||||
Const,
|
||||
Fn,
|
||||
Closure,
|
||||
Mod,
|
||||
ForeignMod,
|
||||
GlobalAsm,
|
||||
TyAlias,
|
||||
OpaqueTy,
|
||||
Enum,
|
||||
Variant,
|
||||
Struct,
|
||||
Union,
|
||||
Trait,
|
||||
TraitAlias,
|
||||
Impl,
|
||||
Expression,
|
||||
Statement,
|
||||
AssocConst,
|
||||
Method(MethodKind),
|
||||
AssocTy,
|
||||
ForeignFn,
|
||||
ForeignStatic,
|
||||
ForeignTy,
|
||||
}
|
||||
|
||||
impl Display for Target {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match *self {
|
||||
Target::ExternCrate => "extern crate",
|
||||
Target::Use => "use",
|
||||
Target::Static => "static item",
|
||||
Target::Const => "constant item",
|
||||
Target::Fn => "function",
|
||||
Target::Closure => "closure",
|
||||
Target::Mod => "module",
|
||||
Target::ForeignMod => "foreign module",
|
||||
Target::GlobalAsm => "global asm",
|
||||
Target::TyAlias => "type alias",
|
||||
Target::OpaqueTy => "opaque type",
|
||||
Target::Enum => "enum",
|
||||
Target::Variant => "enum variant",
|
||||
Target::Struct => "struct",
|
||||
Target::Union => "union",
|
||||
Target::Trait => "trait",
|
||||
Target::TraitAlias => "trait alias",
|
||||
Target::Impl => "item",
|
||||
Target::Expression => "expression",
|
||||
Target::Statement => "statement",
|
||||
Target::AssocConst => "associated const",
|
||||
Target::Method(_) => "method",
|
||||
Target::AssocTy => "associated type",
|
||||
Target::ForeignFn => "foreign function",
|
||||
Target::ForeignStatic => "foreign static item",
|
||||
Target::ForeignTy => "foreign type",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Target {
|
||||
pub fn from_item(item: &Item<'_>) -> Target {
|
||||
match item.kind {
|
||||
ItemKind::ExternCrate(..) => Target::ExternCrate,
|
||||
ItemKind::Use(..) => Target::Use,
|
||||
ItemKind::Static(..) => Target::Static,
|
||||
ItemKind::Const(..) => Target::Const,
|
||||
ItemKind::Fn(..) => Target::Fn,
|
||||
ItemKind::Mod(..) => Target::Mod,
|
||||
ItemKind::ForeignMod(..) => Target::ForeignMod,
|
||||
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
|
||||
ItemKind::TyAlias(..) => Target::TyAlias,
|
||||
ItemKind::OpaqueTy(..) => Target::OpaqueTy,
|
||||
ItemKind::Enum(..) => Target::Enum,
|
||||
ItemKind::Struct(..) => Target::Struct,
|
||||
ItemKind::Union(..) => Target::Union,
|
||||
ItemKind::Trait(..) => Target::Trait,
|
||||
ItemKind::TraitAlias(..) => Target::TraitAlias,
|
||||
ItemKind::Impl { .. } => Target::Impl,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_trait_item(trait_item: &TraitItem<'_>) -> Target {
|
||||
match trait_item.kind {
|
||||
TraitItemKind::Const(..) => Target::AssocConst,
|
||||
TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => {
|
||||
Target::Method(MethodKind::Trait { body: false })
|
||||
}
|
||||
TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => {
|
||||
Target::Method(MethodKind::Trait { body: true })
|
||||
}
|
||||
TraitItemKind::Type(..) => Target::AssocTy,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_foreign_item(foreign_item: &hir::ForeignItem<'_>) -> Target {
|
||||
match foreign_item.kind {
|
||||
hir::ForeignItemKind::Fn(..) => Target::ForeignFn,
|
||||
hir::ForeignItemKind::Static(..) => Target::ForeignStatic,
|
||||
hir::ForeignItemKind::Type => Target::ForeignTy,
|
||||
}
|
||||
}
|
||||
}
|
53
compiler/rustc_hir/src/weak_lang_items.rs
Normal file
53
compiler/rustc_hir/src/weak_lang_items.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
//! Validity checking for weak lang items
|
||||
|
||||
use crate::def_id::DefId;
|
||||
use crate::{lang_items, LangItem, LanguageItems};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
macro_rules! weak_lang_items {
|
||||
($($name:ident, $item:ident, $sym:ident;)*) => (
|
||||
|
||||
lazy_static! {
|
||||
pub static ref WEAK_ITEMS_REFS: FxHashMap<Symbol, LangItem> = {
|
||||
let mut map = FxHashMap::default();
|
||||
$(map.insert(sym::$name, LangItem::$item);)*
|
||||
map
|
||||
};
|
||||
}
|
||||
|
||||
/// The `check_name` argument avoids the need for `librustc_hir` to depend on
|
||||
/// `librustc_session`.
|
||||
pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
|
||||
where
|
||||
F: Fn(&'a ast::Attribute, Symbol) -> bool
|
||||
{
|
||||
lang_items::extract(check_name, attrs).and_then(|(name, _)| {
|
||||
$(if name == sym::$name {
|
||||
Some(sym::$sym)
|
||||
} else)* {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl LanguageItems {
|
||||
pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
|
||||
let did = Some(item_def_id);
|
||||
|
||||
$(self.$name() == did)||*
|
||||
}
|
||||
}
|
||||
|
||||
) }
|
||||
|
||||
weak_lang_items! {
|
||||
panic_impl, PanicImpl, rust_begin_unwind;
|
||||
eh_personality, EhPersonality, rust_eh_personality;
|
||||
eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo;
|
||||
oom, Oom, rust_oom;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue