Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeId: use a (v0) mangled type to remain sound in the face of hash collisions. #95845

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,11 +783,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}

fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
fn llvm_cfi_type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
// Unsupported.
}

fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
fn llvm_cfi_typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
// Unsupported.
self.context.new_rvalue_from_int(self.int_type, 0)
}
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
let typeid_metadata = self.typeid_metadata(typeid);
// FIXME(eddyb) this does not belong in `Builder`, it's global.
fn llvm_cfi_type_metadata(&mut self, function: &'ll Value, typeid: String) {
let typeid_metadata = self.llvm_cfi_typeid_metadata(typeid);
let v = [self.const_usize(0), typeid_metadata];
unsafe {
llvm::LLVMGlobalSetMetadata(
Expand All @@ -637,7 +638,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
// FIXME(eddyb) this does not belong in `Builder`, it's global.
fn llvm_cfi_typeid_metadata(&mut self, typeid: String) -> Self::Value {
unsafe {
llvm::LLVMMDStringInContext(
self.cx.llcx,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_symbol_mangling::llvm_cfi_typeid_for_fn_abi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
Expand Down Expand Up @@ -908,8 +908,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Emit type metadata and checks.
// FIXME(rcvalle): Add support for generalized identifiers.
// FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
let typeid_metadata = bx.typeid_metadata(typeid);
let typeid = llvm_cfi_typeid_for_fn_abi(bx.tcx(), fn_abi);
let typeid_metadata = bx.llvm_cfi_typeid_metadata(typeid);

// Test whether the function pointer is associated with the type identifier.
let cond = bx.type_test(fn_ptr, typeid_metadata);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_symbol_mangling::llvm_cfi_typeid_for_fn_abi;
use rustc_target::abi::call::{FnAbi, PassMode};

use std::iter;
Expand Down Expand Up @@ -252,8 +252,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// For backends that support CFI using type membership (i.e., testing whether a given pointer
// is associated with a type identifier).
if cx.tcx().sess.is_sanitizer_cfi_enabled() {
let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
bx.type_metadata(llfn, typeid);
let typeid = llvm_cfi_typeid_for_fn_abi(cx.tcx(), fn_abi);
bx.llvm_cfi_type_metadata(llfn, typeid);
}
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ pub trait BuilderMethods<'a, 'tcx>:

fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
fn nonnull_metadata(&mut self, load: Self::Value);
fn type_metadata(&mut self, function: Self::Function, typeid: String);
fn typeid_metadata(&mut self, typeid: String) -> Self::Value;

// FIXME(eddyb) these do not belong in `Builder`, they're global.
fn llvm_cfi_type_metadata(&mut self, function: Self::Function, typeid: String);
fn llvm_cfi_typeid_metadata(&mut self, typeid: String) -> Self::Value;

fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
fn store_with_flags(
Expand Down
93 changes: 87 additions & 6 deletions compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

use std::convert::TryFrom;

use rustc_hir::lang_items::LangItem;
use rustc_hir::Mutability;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::{
mir::{self, interpret::ConstAlloc},
ty::ScalarInt,
};
use rustc_middle::mir::{self, interpret::ConstAlloc};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use rustc_target::abi::Size;

use crate::interpret::{
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
self, intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
MemPlaceMeta, Scalar,
};

Expand Down Expand Up @@ -39,6 +39,87 @@ pub(crate) fn const_caller_location(
ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
}

pub(crate) fn const_type_id<'tcx>(
Copy link
Member

@RalfJung RalfJung Apr 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd prefer this helper to be in the interpret module, not const_eval -- it is needed for all interpreter instances after all, const_eval is meant for specifically the CTFE instance of the general interpreter infrastruture.

EDIT: It is needed also for regular codegen, but I think my point remains -- const_eval should be for things that are specific for CTFE. interpret should not usually import anything from const_eval.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're also creating your own ecx here, and returning this as a ConstValue -- why all that?

I guess an alternative might be to treat this like vtable_allocation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type_name::alloc_type_name also seems similar in spirit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh I see, I was modelling it after const_caller_location but that's only here because it's a query instead of an intrinsic. Should it have its own module under interpret::intrinsics like caller_location does?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, note in particular that the caller_location implementation in interpret does not call the const_eval code. It is not a nullary intrinsic so it takes slightly different paths. Though probably the const_caller_location query should be made more like the vtable query, which is not inside const_eval either.

Should it have its own module under interpret::intrinsics like caller_location does?

Yeah I guess that would make sense.
It would almost make sense to move these queries for intrinsics that are implemented via interpreter stuff but also used for codegen in a separate module rustc_const_eval::intrinsics, i.e., outside interpret. @oli-obk any thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it, caller_location actually has a impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> block so having that inside interpret makes sense. type_name, OTOH, doesn't really do anything with the interpreter, it is very much like the vtable code (but the two are in totally different locations, which we should probably fix). "give me the vtable for type T" is not technically an intrinsic but not very different, either, is it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think cleaning this up is orthogonal.

Except for mplace_field we don't even need an InterpCx and can just create and intern the Allocations directly. If we added more convenience operations for writing data of a specific struct to an Allocation we can probably stop using InterpCx for caller_location, too.

Imo we should just merge this PR and then work on cleaning these up now that we have multiple intrinsics to clean up in a similar way.

Copy link
Member

@RalfJung RalfJung Apr 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree cleaning up the existing stuff is a separate task.

But we shouldn't have anything load-bearing inside the const_eval module, so I do think that this code should be moved somewhere else before landing. I don't care strongly which of the existing precedent it follows, but none of it has load-bearing code in const_eval, so let's not add yet another different style of implementing such an intrinsic. :)

(Even caller_location, which was mentioned as a template, has its load-bearing code in interpret::intrinsics::caller_location.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still relevant, should move this function.

tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> ConstValue<'tcx> {
trace!("const_type_id: {}", ty);

// Compute (logical) `TypeId` field values, before trying to encode them.
let hash = tcx.type_id_hash(ty);
let mangling = tcx.type_id_mangling(param_env.and(ty)).name;

let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);

let type_id_ty = tcx.type_of(tcx.require_lang_item(LangItem::TypeId, None));
let type_id_layout = ecx.layout_of(type_id_ty).unwrap();

// Encode `TypeId` field values, before putting together the allocation.
let hash_val = Scalar::from_u64(hash);
let mangling_val = {
let mangling_len = u64::try_from(mangling.len()).unwrap();
let mangling_len_val = Scalar::from_machine_usize(mangling_len, &ecx);

// The field is `mangling: &TypeManglingStr`, get `TypeManglingStr` from it.
let mangling_field_ty = type_id_layout.field(&ecx, 1).ty;
let type_mangling_str_ty = mangling_field_ty.builtin_deref(true).unwrap().ty;

// Allocate memory for `TypeManglingStr` struct.
let type_mangling_str_layout = ecx.layout_of(type_mangling_str_ty).unwrap();
let type_mangling_str_place = {
// NOTE(eddyb) this similar to the `ecx.allocate(...)` used below
// for `type_id_place`, except with an additional size for the
// string bytes (`mangling`) being added to the `TypeManglingStr`
// (which is unsized, using an `extern { type }` tail).
let layout = type_mangling_str_layout;
let size = layout.size + Size::from_bytes(mangling_len);
let ptr = ecx
.allocate_ptr(size, layout.align.abi, interpret::MemoryKind::IntrinsicGlobal)
.unwrap();
MPlaceTy::from_aligned_ptr(ptr.into(), layout)
};

// Initialize `TypeManglingStr` fields.
ecx.write_scalar(
mangling_len_val,
&ecx.mplace_field(&type_mangling_str_place, 0).unwrap().into(),
)
.unwrap();
ecx.write_bytes_ptr(
ecx.mplace_field(&type_mangling_str_place, 1).unwrap().ptr,
mangling.bytes(),
)
.unwrap();

// `&TypeManglingStr` has no metadata, thanks to the length being stored
// behind the reference (in the first field of `TypeManglingStr`).
type_mangling_str_place.to_ref(&ecx).to_scalar().unwrap()
};

// FIXME(eddyb) everything below would be unnecessary if `ConstValue` could
// hold a pair of `Scalar`s, or if we moved to valtrees.

// Allocate memory for `TypeId` struct.
let type_id_place =
ecx.allocate(type_id_layout, interpret::MemoryKind::IntrinsicGlobal).unwrap();

// Initialize `TypeId` fields.
ecx.write_scalar(hash_val, &ecx.mplace_field(&type_id_place, 0).unwrap().into()).unwrap();
ecx.write_scalar(mangling_val, &ecx.mplace_field(&type_id_place, 1).unwrap().into()).unwrap();

// Convert the `TypeId` allocation from being in `ecx`, to a global `ConstValue`.
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &type_id_place).is_err() {
bug!("intern_const_alloc_recursive should not error in this case")
}
let (type_id_alloc_id, type_id_offset) =
type_id_place.ptr.into_pointer_or_addr().unwrap().into_parts();
ConstValue::ByRef {
alloc: tcx.global_alloc(type_id_alloc_id).unwrap_memory(),
offset: type_id_offset,
}
}

/// Convert an evaluated constant to a type level constant
pub(crate) fn const_to_valtree<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
match kind {
MemoryKind::Stack
| MemoryKind::Machine(const_eval::MemoryKind::Heap)
| MemoryKind::CallerLocation => {}
| MemoryKind::IntrinsicGlobal => {}
}
// Set allocation mutability as appropriate. This is used by LLVM to put things into
// read-only memory, and also by Miri when evaluating other globals that
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use std::convert::TryFrom;

use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::{
self,
interpret::{ConstValue, GlobalId, InterpResult, Scalar},
Expand Down Expand Up @@ -69,7 +70,7 @@ crate fn eval_nullary_intrinsic<'tcx>(
}
sym::type_id => {
ensure_monomorphic_enough(tcx, tp_ty)?;
ConstValue::from_u64(tcx.type_id_hash(tp_ty))
crate::const_eval::const_type_id(tcx, param_env, tp_ty)
}
sym::variant_count => match tp_ty.kind() {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
Expand Down Expand Up @@ -166,7 +167,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let ty = match intrinsic_name {
sym::pref_align_of | sym::variant_count => self.tcx.types.usize,
sym::needs_drop => self.tcx.types.bool,
sym::type_id => self.tcx.types.u64,
sym::type_id => self
.tcx
.type_of(self.tcx.require_lang_item(LangItem::TypeId, Some(self.tcx.span))),
sym::type_name => self.tcx.mk_static_str(),
_ => bug!("already checked for nullary intrinsics"),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> MPlaceTy<'tcx, M::PointerTag> {
let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail;
let file = if loc_details.file {
self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
self.allocate_str(filename.as_str(), MemoryKind::IntrinsicGlobal, Mutability::Not)
} else {
// FIXME: This creates a new allocation each time. It might be preferable to
// perform this allocation only once, and re-use the `MPlaceTy`.
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
self.allocate_str("<redacted>", MemoryKind::IntrinsicGlobal, Mutability::Not)
};
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };

// Allocate memory for `CallerLocation` struct.
// Allocate memory for `panic::Location` struct.
let loc_ty = self
.tcx
.type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
let loc_layout = self.layout_of(loc_ty).unwrap();
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
// pointless, since that would require allocating more memory than a Location.
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
let location = self.allocate(loc_layout, MemoryKind::IntrinsicGlobal).unwrap();

// Initialize fields.
self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into())
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use super::{
pub enum MemoryKind<T> {
/// Stack memory. Error if deallocated except during a stack pop.
Stack,
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
CallerLocation,
/// Global memory allocated by an intrinsic. Error if ever deallocated.
IntrinsicGlobal,
/// Additional memory kinds a machine wishes to distinguish from the builtin ones.
Machine(T),
}
Expand All @@ -40,7 +40,7 @@ impl<T: MayLeak> MayLeak for MemoryKind<T> {
fn may_leak(self) -> bool {
match self {
MemoryKind::Stack => false,
MemoryKind::CallerLocation => true,
MemoryKind::IntrinsicGlobal => true,
MemoryKind::Machine(k) => k.may_leak(),
}
}
Expand All @@ -50,7 +50,7 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MemoryKind::Stack => write!(f, "stack variable"),
MemoryKind::CallerLocation => write!(f, "caller location"),
MemoryKind::IntrinsicGlobal => write!(f, "global memory (from intrinsic)"),
MemoryKind::Machine(m) => write!(f, "{}", m),
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ language_item_table! {
IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);

UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
VaList, sym::va_list, va_list_type, Target::Struct, GenericRequirement::None;

Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
Expand Down Expand Up @@ -326,6 +326,8 @@ language_item_table! {
Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None;
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None;
RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;

TypeId, sym::TypeId, type_id_struct, Target::Struct, GenericRequirement::Exact(0);
}

pub enum GenericRequirement {
Expand Down
50 changes: 47 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,14 +995,58 @@ rustc_queries! {
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
}

/// The `symbol_name` query provides the symbol name for calling a
/// given instance from the local crate. In particular, it will also
/// look up the correct symbol name of instances from upstream crates.
/// The `symbol_name` query provides the symbol name for the given instance.
///
/// Both `static` and `fn` instances have symbol names, whether definitions
/// (on the Rust side, either from the local crate or an upstream one), or
/// imports in a "foreign block" (`extern {...}`).
///
/// This symbol name is the canonical one for that instance, and must be
/// used for both linker-level exports (definitions) and imports (uses),
/// of that instance (i.e. it's the sole connection the linker sees).
///
/// By default, Rust definitions have mangled symbols, to avoid conflicts,
/// and to allow for many instances ("monomorphizations") of generic `fn`s.
/// The exact choice of mangling can vary, and not all type information from
/// the instance may always be present in a form that allows demangling back
/// to a human-readable form. See also the `symbol_mangling_version` query
/// and the `rustc_symbol_mangling` crate.
///
/// Note however that `fn` lifetime parameters are erased (and so they never
/// participate in monomorphization), meaning mangled Rust symbol names will
/// never contain information about such lifetimes (mangled lifetimes only
/// occur for higher-ranked types, e.g. `foo::<for<'a> fn(&'a X)>`).
query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName<'tcx> {
desc { "computing the symbol for `{}`", key }
cache_on_disk_if { true }
}

/// The `type_id_mangling` query provides the Rust mangling of the given type,
/// for use in `TypeId`, as a guard against `type_id_hash` collisions.
///
/// Unlike the `symbol_name` query, the mangling used for types doesn't vary
/// between crates, and encodes all the type information "structurally"
/// (i.e. lossy encodings such as hashing aren't allowed, as that would
/// effectively defeat the purpose of guarding against hash collisions).
///
/// If this is used outside of `TypeId`, some additional caveats apply:
/// * it's not a full symbol, so it could collide with unrelated exports,
/// if used directly as a linker symbol without a prefix and/or suffix
/// * mangling features such as compression (e.g. `v0` backrefs) mean that
/// it cannot be trivially embedded in a larger mangled Rust symbol - for
/// that usecase, prefer using `symbol_name` with an instance of a either
/// a custom `InstanceDef`, or at least a generic lang item (`fn`, though
/// associated `const` may work better for a type-dependent `static`)
/// * every Rust mangling erases most lifetimes, with the only exception
/// being those found in higher-ranked types (e.g. `for<'a> fn(&'a X)`)
//
// FIXME(eddyb) this shouldn't be using `ty::SymbolName`, but `&'tcx str`,
// or `ty::SymbolName` should be renamed to "tcx-interned string".
query type_id_mangling(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> ty::SymbolName<'tcx> {
desc { "computing the type mangling of `{}`", key.value }
cache_on_disk_if { true }
}

query opt_def_kind(def_id: DefId) -> Option<DefKind> {
desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ symbols! {
Ty,
TyCtxt,
TyKind,
TypeId,
Unknown,
UnsafeArg,
Vec,
Expand Down
Loading