From 785459d630a129c4007e865b3c907cd5c469d604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 7 Feb 2023 08:32:30 +0100 Subject: [PATCH 1/5] Erase query cache values --- compiler/rustc_middle/src/query/erase.rs | 225 ++++++++++++++++++ compiler/rustc_middle/src/query/mod.rs | 1 + compiler/rustc_middle/src/ty/query.rs | 34 ++- compiler/rustc_query_impl/src/lib.rs | 14 +- .../rustc_query_impl/src/on_disk_cache.rs | 9 +- compiler/rustc_query_impl/src/plumbing.rs | 50 +++- .../rustc_query_system/src/query/config.rs | 8 +- .../rustc_query_system/src/query/plumbing.rs | 37 +-- 8 files changed, 329 insertions(+), 49 deletions(-) create mode 100644 compiler/rustc_middle/src/query/erase.rs diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs new file mode 100644 index 0000000000000..83046e14f116b --- /dev/null +++ b/compiler/rustc_middle/src/query/erase.rs @@ -0,0 +1,225 @@ +use crate::ty; +use std::intrinsics::type_name; +use std::{ + fmt, + mem::{size_of, transmute_copy, MaybeUninit}, +}; + +#[derive(Copy, Clone)] +pub struct Erased { + data: MaybeUninit, +} + +impl fmt::Debug for Erased { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Erased") + } +} + +pub trait EraseType: Copy { + type Result: Copy; +} + +// Allow `type_alias_bounds` since compilation will fail without `EraseType`. +#[allow(type_alias_bounds)] +pub type Erase = Erased; + +#[inline(always)] +pub fn erase(src: T) -> Erase { + assert_eq!( + size_of::(), + size_of::(), + "size of {} must match erased type {}", + type_name::(), + type_name::() + ); + Erased::<::Result> { + // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes. + data: unsafe { transmute_copy(&src) }, + } +} + +/// Restores an erased value. +#[inline(always)] +pub fn restore(value: Erase) -> T { + let value: Erased<::Result> = value; + // SAFETY: Due to the use of impl Trait in `Erase` the only way to safetly create an instance + // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of + // the right size. + unsafe { transmute_copy(&value.data) } +} + +impl EraseType for &'_ T { + type Result = [u8; size_of::<*const ()>()]; +} + +impl EraseType for &'_ [T] { + type Result = [u8; size_of::<*const [()]>()]; +} + +impl EraseType for &'_ ty::List { + type Result = [u8; size_of::<*const ()>()]; +} + +impl EraseType for Result { + type Result = Self; +} + +impl EraseType for Option { + type Result = Self; +} + +impl EraseType for rustc_hir::MaybeOwner { + type Result = Self; +} + +impl EraseType for ty::Visibility { + type Result = Self; +} + +impl EraseType for ty::Binder<'_, T> { + type Result = Self; +} + +impl EraseType for ty::EarlyBinder { + type Result = Self; +} + +impl EraseType for (T0, T1) { + type Result = Self; +} + +macro_rules! trivial { + ($($ty:ty),+ $(,)?) => { + $( + impl EraseType for $ty { + type Result = [u8; size_of::<$ty>()]; + } + )* + } +} + +trivial! { + (), + bool, + rustc_ast::expand::allocator::AllocatorKind, + rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, + rustc_attr::Deprecation, + rustc_attr::Stability, + rustc_data_structures::svh::Svh, + rustc_errors::ErrorGuaranteed, + rustc_hir::Constness, + rustc_hir::def_id::DefId, + rustc_hir::def_id::DefIndex, + rustc_hir::def_id::LocalDefId, + rustc_hir::def::DefKind, + rustc_hir::Defaultness, + rustc_hir::definitions::DefKey, + rustc_hir::GeneratorKind, + rustc_hir::HirId, + rustc_hir::IsAsync, + rustc_hir::ItemLocalId, + rustc_hir::LangItem, + rustc_hir::OwnerId, + rustc_hir::Upvar, + rustc_index::bit_set::FiniteBitSet, + rustc_middle::metadata::ModChild, + rustc_middle::middle::dependency_format::Linkage, + rustc_middle::middle::exported_symbols::SymbolExportInfo, + rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, + rustc_middle::middle::resolve_bound_vars::ResolvedArg, + rustc_middle::middle::stability::DeprecationEntry, + rustc_middle::mir::ConstQualifs, + rustc_middle::mir::interpret::AllocId, + rustc_middle::mir::interpret::ErrorHandled, + rustc_middle::mir::interpret::LitToConstError, + rustc_middle::thir::ExprId, + rustc_middle::traits::CodegenObligationError, + rustc_middle::traits::EvaluationResult, + rustc_middle::traits::OverflowError, + rustc_middle::traits::query::NoSolution, + rustc_middle::traits::WellFormedLoc, + rustc_middle::ty::adjustment::CoerceUnsizedInfo, + rustc_middle::ty::AssocItem, + rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::BoundVariableKind, + rustc_middle::ty::DeducedParamAttrs, + rustc_middle::ty::Destructor, + rustc_middle::ty::fast_reject::SimplifiedType, + rustc_middle::ty::ImplPolarity, + rustc_middle::ty::Representability, + rustc_middle::ty::ReprOptions, + rustc_middle::ty::UnusedGenericParams, + rustc_middle::ty::util::AlwaysRequiresDrop, + rustc_session::config::CrateType, + rustc_session::config::EntryFnType, + rustc_session::config::OptLevel, + rustc_session::config::SymbolManglingVersion, + rustc_session::cstore::CrateDepKind, + rustc_session::cstore::ExternCrate, + rustc_session::cstore::LinkagePreference, + rustc_session::Limits, + rustc_session::lint::LintExpectationId, + rustc_span::def_id::CrateNum, + rustc_span::def_id::DefPathHash, + rustc_span::ExpnHash, + rustc_span::ExpnId, + rustc_span::Span, + rustc_span::Symbol, + rustc_span::symbol::Ident, + rustc_target::spec::PanicStrategy, + rustc_type_ir::Variance, + u32, + usize, +} + +macro_rules! tcx_lifetime { + ($($($fake_path:ident)::+),+ $(,)?) => { + $( + impl<'tcx> EraseType for $($fake_path)::+<'tcx> { + type Result = [u8; size_of::<$($fake_path)::+<'static>>()]; + } + )* + } +} + +tcx_lifetime! { + rustc_middle::hir::Owner, + rustc_middle::middle::exported_symbols::ExportedSymbol, + rustc_middle::mir::ConstantKind, + rustc_middle::mir::DestructuredConstant, + rustc_middle::mir::interpret::ConstAlloc, + rustc_middle::mir::interpret::ConstValue, + rustc_middle::mir::interpret::GlobalId, + rustc_middle::mir::interpret::LitToConstInput, + rustc_middle::traits::ChalkEnvironmentAndGoal, + rustc_middle::traits::query::MethodAutoderefStepsResult, + rustc_middle::traits::query::type_op::AscribeUserType, + rustc_middle::traits::query::type_op::Eq, + rustc_middle::traits::query::type_op::ProvePredicate, + rustc_middle::traits::query::type_op::Subtype, + rustc_middle::ty::AdtDef, + rustc_middle::ty::AliasTy, + rustc_middle::ty::Clause, + rustc_middle::ty::ClosureTypeInfo, + rustc_middle::ty::Const, + rustc_middle::ty::DestructuredConst, + rustc_middle::ty::ExistentialTraitRef, + rustc_middle::ty::FnSig, + rustc_middle::ty::GenericArg, + rustc_middle::ty::GenericPredicates, + rustc_middle::ty::inhabitedness::InhabitedPredicate, + rustc_middle::ty::Instance, + rustc_middle::ty::InstanceDef, + rustc_middle::ty::layout::FnAbiError, + rustc_middle::ty::layout::LayoutError, + rustc_middle::ty::ParamEnv, + rustc_middle::ty::Predicate, + rustc_middle::ty::SymbolName, + rustc_middle::ty::TraitRef, + rustc_middle::ty::Ty, + rustc_middle::ty::UnevaluatedConst, + rustc_middle::ty::ValTree, + rustc_middle::ty::VtblEntry, +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9203dd59a7e63..846df6d5188f6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,6 +7,7 @@ use crate::ty::{self, print::describe_as_module, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; +pub mod erase; mod keys; pub use keys::{AsLocalKey, Key, LocalCrate}; diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 30246fe4dbebc..734512b4048c7 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -17,6 +17,7 @@ use crate::mir::interpret::{ }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; +use crate::query::erase::{erase, restore, Erase}; use crate::query::{AsLocalKey, Key}; use crate::thir; use crate::traits::query::{ @@ -57,6 +58,8 @@ use rustc_hir::hir_id::OwnerId; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::vec::IndexVec; +pub(crate) use rustc_query_system::query::QueryJobId; +use rustc_query_system::query::*; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; @@ -66,18 +69,19 @@ use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi; use rustc_target::spec::PanicStrategy; + +use std::marker::PhantomData; use std::mem; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; -pub(crate) use rustc_query_system::query::QueryJobId; -use rustc_query_system::query::*; - #[derive(Default)] pub struct QuerySystem<'tcx> { pub arenas: QueryArenas<'tcx>, pub caches: QueryCaches<'tcx>, + // Since we erase query value types we tell the typesystem about them with `PhantomData`. + _phantom_values: QueryPhantomValues<'tcx>, } #[derive(Copy, Clone)] @@ -263,8 +267,8 @@ macro_rules! define_callbacks { pub fn $name<'tcx>( _tcx: TyCtxt<'tcx>, value: query_provided::$name<'tcx>, - ) -> query_values::$name<'tcx> { - query_if_arena!([$($modifiers)*] + ) -> Erase> { + erase(query_if_arena!([$($modifiers)*] { if mem::needs_drop::>() { &*_tcx.query_system.arenas.$name.alloc(value) @@ -273,7 +277,7 @@ macro_rules! define_callbacks { } } (value) - ) + )) } )* } @@ -282,7 +286,7 @@ macro_rules! define_callbacks { use super::*; $( - pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache; + pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>>::Cache; )* } @@ -334,6 +338,11 @@ macro_rules! define_callbacks { } } + #[derive(Default)] + pub struct QueryPhantomValues<'tcx> { + $($(#[$attr])* pub $name: PhantomData>,)* + } + #[derive(Default)] pub struct QueryCaches<'tcx> { $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* @@ -395,10 +404,10 @@ macro_rules! define_callbacks { let key = key.into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); - match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { + restore::<$V>(match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(value) => value, None => self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap(), - } + }) })* } @@ -459,7 +468,7 @@ macro_rules! define_callbacks { span: Span, key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option<$V>;)* + ) -> Option>;)* } }; } @@ -486,7 +495,8 @@ macro_rules! define_feedable { opt_remap_env_constness!([$($modifiers)*][key]); let tcx = self.tcx; - let value = query_provided_to_value::$name(tcx, value); + let erased = query_provided_to_value::$name(tcx, value); + let value = restore::<$V>(erased); let cache = &tcx.query_system.caches.$name; match try_get_cached(tcx, cache, &key) { @@ -505,7 +515,7 @@ macro_rules! define_feedable { &value, hash_result!([$($modifiers)*]), ); - cache.complete(key, value, dep_node_index); + cache.complete(key, erased, dep_node_index); value } } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 021a67c9513cd..7e053735aa9cf 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -18,19 +18,21 @@ extern crate rustc_middle; use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; -use rustc_middle::dep_graph::{self, DepKindStruct}; +use rustc_middle::dep_graph::{self, DepKind, DepKindStruct}; +use rustc_middle::query::erase::{erase, restore, Erase}; use rustc_middle::query::AsLocalKey; use rustc_middle::ty::query::{ query_keys, query_provided, query_provided_to_value, query_storage, query_values, }; use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine}; use rustc_middle::ty::TyCtxt; +use rustc_query_system::dep_graph::SerializedDepNodeIndex; +use rustc_query_system::Value; use rustc_span::Span; #[macro_use] mod plumbing; pub use plumbing::QueryCtxt; -use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::query::*; #[cfg(parallel_compiler)] pub use rustc_query_system::query::{deadlock, QueryContext}; @@ -43,6 +45,14 @@ pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; +trait QueryToConfig<'tcx>: 'tcx { + type Value; + type Config: QueryConfig>; + + fn config(qcx: QueryCtxt<'tcx>) -> Self::Config; + fn restore(value: >>::Value) -> Self::Value; +} + rustc_query_append! { define_queries! } impl<'tcx> Queries<'tcx> { diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 35b7e5919e42a..4d64517d4a313 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -13,6 +13,7 @@ use rustc_middle::mir::{self, interpret}; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; +use rustc_query_system::query::QueryConfig; use rustc_query_system::query::{QueryCache, QuerySideEffects}; use rustc_serialize::{ opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}, @@ -1064,13 +1065,13 @@ impl<'a, 'tcx> Encodable> for [u8] { } } -pub fn encode_query_results<'a, 'tcx, Q>( - query: Q, +pub(crate) fn encode_query_results<'a, 'tcx, Q>( + query: Q::Config, qcx: QueryCtxt<'tcx>, encoder: &mut CacheEncoder<'a, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, ) where - Q: super::QueryConfig>, + Q: super::QueryToConfig<'tcx>, Q::Value: Encodable>, { let _timer = qcx @@ -1089,7 +1090,7 @@ pub fn encode_query_results<'a, 'tcx, Q>( // Encode the type check tables with the `SerializedDepNodeIndex` // as tag. - encoder.encode_tagged(dep_node, value); + encoder.encode_tagged(dep_node, &Q::restore(*value)); } }); } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9bba26cc8e846..ddc86b5173fbe 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -263,14 +263,14 @@ macro_rules! feedable { } macro_rules! hash_result { - ([]) => {{ - Some(dep_graph::hash_result) + ([][$V:ty]) => {{ + Some(|hcx, result| dep_graph::hash_result(hcx, &restore::<$V>(*result))) }}; - ([(no_hash) $($rest:tt)*]) => {{ + ([(no_hash) $($rest:tt)*][$V:ty]) => {{ None }}; - ([$other:tt $($modifiers:tt)*]) => { - hash_result!([$($modifiers)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + hash_result!([$($modifiers)*][$($args)*]) }; } @@ -479,7 +479,7 @@ macro_rules! define_queries { $(impl<'tcx> QueryConfig> for queries::$name<'tcx> { type Key = query_keys::$name<'tcx>; - type Value = query_values::$name<'tcx>; + type Value = Erase>; #[inline(always)] fn name(self) -> &'static str { @@ -508,7 +508,7 @@ macro_rules! define_queries { } fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { - tcx.$name(key) + erase(tcx.$name(key)) } #[inline] @@ -558,6 +558,16 @@ macro_rules! define_queries { }) } + #[inline] + fn from_cycle_error( + self, + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo], + ) -> Self::Value { + let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle); + erase(result) + } + #[inline(always)] fn anon(self) -> bool { is_anon!([$($modifiers)*]) @@ -590,7 +600,22 @@ macro_rules! define_queries { #[inline(always)] fn hash_result(self) -> rustc_query_system::query::HashResult { - hash_result!([$($modifiers)*]) + hash_result!([$($modifiers)*][query_values::$name<'tcx>]) + } + })* + + $(impl<'tcx> QueryToConfig<'tcx> for queries::$name<'tcx> { + type Value = query_values::$name<'tcx>; + type Config = Self; + + #[inline(always)] + fn config(_qcx: QueryCtxt<'tcx>) -> Self::Config { + Self::default() + } + + #[inline(always)] + fn restore(value: >>::Value) -> Self::Value { + restore::>(value) } })* @@ -665,6 +690,7 @@ macro_rules! define_queries { use $crate::profiling_support::QueryKeyStringCache; use rustc_query_system::query::QueryMap; use rustc_middle::dep_graph::DepKind; + use crate::QueryToConfig; pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> { fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap) -> Option<()> { @@ -708,8 +734,8 @@ macro_rules! define_queries { ) }, encode_query_results: expand_if_cached!([$($modifiers)*], |qcx, encoder, query_result_index| - $crate::on_disk_cache::encode_query_results( - super::queries::$name::default(), + $crate::on_disk_cache::encode_query_results::>( + super::queries::$name::config(qcx), qcx, encoder, query_result_index, @@ -798,9 +824,9 @@ macro_rules! define_queries_struct { &'tcx self, tcx: TyCtxt<'tcx>, span: Span, - key: as QueryConfig>>::Key, + key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option> { + ) -> Option>> { let qcx = QueryCtxt { tcx, queries: self }; get_query( queries::$name::default(), diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index a0aeb812af968..ae3b67915cbd0 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -4,7 +4,7 @@ use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; -use crate::query::{QueryContext, QueryState}; +use crate::query::{QueryContext, QueryInfo, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; use std::fmt::Debug; @@ -45,6 +45,12 @@ pub trait QueryConfig: Copy { fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; + fn from_cycle_error( + self, + tcx: Qcx::DepContext, + cycle: &[QueryInfo], + ) -> Self::Value; + fn anon(self) -> bool; fn eval_always(self) -> bool; fn depth_limit(self) -> bool; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 519ea5ffed18f..5314d26b9401a 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -11,7 +11,6 @@ use crate::query::job::QueryLatch; use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo}; use crate::query::SerializedDepNodeIndex; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; -use crate::values::Value; use crate::HandleCycleError; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -120,43 +119,45 @@ where #[cold] #[inline(never)] -fn mk_cycle( +fn mk_cycle( + query: Q, qcx: Qcx, - cycle_error: CycleError, + cycle_error: CycleError, handler: HandleCycleError, -) -> R +) -> Q::Value where - Qcx: QueryContext + HasDepContext, - R: std::fmt::Debug + Value, + Q: QueryConfig, + Qcx: QueryContext, { let error = report_cycle(qcx.dep_context().sess(), &cycle_error); - handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler) + handle_cycle_error(query, qcx, &cycle_error, error, handler) } -fn handle_cycle_error( - tcx: Tcx, - cycle_error: &CycleError, +fn handle_cycle_error( + query: Q, + qcx: Qcx, + cycle_error: &CycleError, mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, handler: HandleCycleError, -) -> V +) -> Q::Value where - Tcx: DepContext, - V: Value, + Q: QueryConfig, + Qcx: QueryContext, { use HandleCycleError::*; match handler { Error => { error.emit(); - Value::from_cycle_error(tcx, &cycle_error.cycle) + query.from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) } Fatal => { error.emit(); - tcx.sess().abort_if_errors(); + qcx.dep_context().sess().abort_if_errors(); unreachable!() } DelayBug => { error.delay_as_bug(); - Value::from_cycle_error(tcx, &cycle_error.cycle) + query.from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) } } } @@ -269,7 +270,7 @@ where &qcx.current_query_job(), span, ); - (mk_cycle(qcx, error, query.handle_cycle_error()), None) + (mk_cycle(query, qcx, error, query.handle_cycle_error()), None) } #[inline(always)] @@ -306,7 +307,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(qcx, cycle, query.handle_cycle_error()), None), + Err(cycle) => (mk_cycle(query, qcx, cycle, query.handle_cycle_error()), None), } } From 36b4199a8e4197420760438df464cffcaa674e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 26 Mar 2023 11:00:26 +0200 Subject: [PATCH 2/5] Don't rely on `Debug` impl for `Erased` --- compiler/rustc_middle/src/query/erase.rs | 11 +---------- compiler/rustc_middle/src/ty/query.rs | 1 + compiler/rustc_query_impl/src/plumbing.rs | 7 ++++++- .../rustc_query_system/src/dep_graph/graph.rs | 9 ++++++++- compiler/rustc_query_system/src/query/caches.rs | 8 ++++---- compiler/rustc_query_system/src/query/config.rs | 4 +++- .../rustc_query_system/src/query/plumbing.rs | 16 ++++++++++------ 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 83046e14f116b..705300b9b7a78 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,21 +1,12 @@ use crate::ty; use std::intrinsics::type_name; -use std::{ - fmt, - mem::{size_of, transmute_copy, MaybeUninit}, -}; +use std::mem::{size_of, transmute_copy, MaybeUninit}; #[derive(Copy, Clone)] pub struct Erased { data: MaybeUninit, } -impl fmt::Debug for Erased { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Erased") - } -} - pub trait EraseType: Copy { type Result: Copy; } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 734512b4048c7..fa9fea7234486 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -501,6 +501,7 @@ macro_rules! define_feedable { match try_get_cached(tcx, cache, &key) { Some(old) => { + let old = restore::<$V>(old); bug!( "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", stringify!($name), diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ddc86b5173fbe..a1dfb27c5d73a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -486,6 +486,11 @@ macro_rules! define_queries { stringify!($name) } + #[inline] + fn format_value(self) -> fn(&Self::Value) -> String { + |value| format!("{:?}", restore::>(*value)) + } + #[inline] fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { ::rustc_middle::query::cached::$name(tcx, key) @@ -819,7 +824,7 @@ macro_rules! define_queries_struct { $($(#[$attr])* #[inline(always)] - #[tracing::instrument(level = "trace", skip(self, tcx), ret)] + #[tracing::instrument(level = "trace", skip(self, tcx))] fn $name( &'tcx self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 2ff7de8cb9efc..534d13b1ae0f4 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -538,7 +538,14 @@ impl DepGraph { if let Some(prev_index) = data.previous.node_to_index_opt(&node) { let dep_node_index = data.current.prev_index_to_index.lock()[prev_index]; if let Some(dep_node_index) = dep_node_index { - crate::query::incremental_verify_ich(cx, data, result, prev_index, hash_result); + crate::query::incremental_verify_ich( + cx, + data, + result, + prev_index, + hash_result, + |value| format!("{:?}", value), + ); #[cfg(debug_assertions)] if hash_result.is_some() { diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index d3efc22a19451..3ac8a852a4e77 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -18,7 +18,7 @@ pub trait CacheSelector<'tcx, V> { pub trait QueryCache: Sized { type Key: Hash + Eq + Copy + Debug; - type Value: Copy + Debug; + type Value: Copy; /// Checks if the query is already computed and in the cache. fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>; @@ -52,7 +52,7 @@ impl Default for DefaultCache { impl QueryCache for DefaultCache where K: Eq + Hash + Copy + Debug, - V: Copy + Debug, + V: Copy, { type Key = K; type Value = V; @@ -120,7 +120,7 @@ impl Default for SingleCache { impl QueryCache for SingleCache where - V: Copy + Debug, + V: Copy, { type Key = (); type Value = V; @@ -164,7 +164,7 @@ impl Default for VecCache { impl QueryCache for VecCache where K: Eq + Idx + Copy + Debug, - V: Copy + Debug, + V: Copy, { type Key = K; type Value = V; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index ae3b67915cbd0..dc981a802f366 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -20,10 +20,12 @@ pub trait QueryConfig: Copy { // `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap, // but it isn't necessary. type Key: DepNodeParams + Eq + Hash + Copy + Debug; - type Value: Debug + Copy; + type Value: Copy; type Cache: QueryCache; + fn format_value(self) -> fn(&Self::Value) -> String; + // Don't use this method to access query results, instead use the methods on TyCtxt fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState where diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 5314d26b9401a..95366e1ad0b8f 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -411,7 +411,8 @@ where // get evaluated first, and re-feed the query. if let Some((cached_result, _)) = cache.lookup(&key) { panic!( - "fed query later has its value computed. The already cached value: {cached_result:?}" + "fed query later has its value computed. The already cached value: {}", + (query.format_value())(&cached_result) ); } } @@ -582,6 +583,7 @@ where &result, prev_dep_node_index, query.hash_result(), + query.format_value(), ); } @@ -627,19 +629,21 @@ where &result, prev_dep_node_index, query.hash_result(), + query.format_value(), ); Some((result, dep_node_index)) } #[inline] -#[instrument(skip(tcx, dep_graph_data, result, hash_result), level = "debug")] -pub(crate) fn incremental_verify_ich( +#[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")] +pub(crate) fn incremental_verify_ich( tcx: Tcx, dep_graph_data: &DepGraphData, result: &V, prev_index: SerializedDepNodeIndex, hash_result: Option, &V) -> Fingerprint>, + format_value: fn(&V) -> String, ) where Tcx: DepContext, { @@ -654,7 +658,7 @@ pub(crate) fn incremental_verify_ich( let old_hash = dep_graph_data.prev_fingerprint_of(prev_index); if new_hash != old_hash { - incremental_verify_ich_failed(tcx, prev_index, result); + incremental_verify_ich_failed(tcx, prev_index, &|| format_value(&result)); } } @@ -678,7 +682,7 @@ where fn incremental_verify_ich_failed( tcx: Tcx, prev_index: SerializedDepNodeIndex, - result: &dyn Debug, + result: &dyn Fn() -> String, ) where Tcx: DepContext, { @@ -708,7 +712,7 @@ fn incremental_verify_ich_failed( run_cmd, dep_node: format!("{dep_node:?}"), }); - panic!("Found unstable fingerprints for {dep_node:?}: {result:?}"); + panic!("Found unstable fingerprints for {dep_node:?}: {}", result()); } INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic)); From 453e919c3748c2e057d4e2c3fc3b881ac84668c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 26 Mar 2023 11:22:21 +0200 Subject: [PATCH 3/5] Avoid the assertion in `erase` --- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/query/erase.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 0e883424fd47c..b4edb02f6c48d 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -33,6 +33,7 @@ #![feature(generators)] #![feature(get_mut_unchecked)] #![feature(if_let_guard)] +#![feature(inline_const)] #![feature(iter_from_generator)] #![feature(local_key_cell_methods)] #![feature(negative_impls)] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 705300b9b7a78..131f91c288707 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,5 +1,4 @@ use crate::ty; -use std::intrinsics::type_name; use std::mem::{size_of, transmute_copy, MaybeUninit}; #[derive(Copy, Clone)] @@ -17,13 +16,13 @@ pub type Erase = Erased; #[inline(always)] pub fn erase(src: T) -> Erase { - assert_eq!( - size_of::(), - size_of::(), - "size of {} must match erased type {}", - type_name::(), - type_name::() - ); + // Ensure the sizes match + const { + if std::mem::size_of::() != std::mem::size_of::() { + panic!("size of T must match erased type T::Result") + } + }; + Erased::<::Result> { // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes. data: unsafe { transmute_copy(&src) }, From 6d99dd91895f9dafbaa08d1ada7782d884089503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 26 Mar 2023 12:24:44 +0200 Subject: [PATCH 4/5] Address comments --- compiler/rustc_middle/src/query/erase.rs | 4 +++- compiler/rustc_query_impl/src/lib.rs | 9 ++++----- compiler/rustc_query_impl/src/on_disk_cache.rs | 7 +++---- compiler/rustc_query_impl/src/plumbing.rs | 17 +++++------------ compiler/rustc_query_system/src/query/config.rs | 3 ++- .../rustc_query_system/src/query/plumbing.rs | 4 ++-- 6 files changed, 19 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 131f91c288707..86532f4f264f9 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -3,6 +3,8 @@ use std::mem::{size_of, transmute_copy, MaybeUninit}; #[derive(Copy, Clone)] pub struct Erased { + // We use `MaybeUninit` here so we can store any value + // in `data` since we aren't actually storing a `T`. data: MaybeUninit, } @@ -12,7 +14,7 @@ pub trait EraseType: Copy { // Allow `type_alias_bounds` since compilation will fail without `EraseType`. #[allow(type_alias_bounds)] -pub type Erase = Erased; +pub type Erase = Erased; #[inline(always)] pub fn erase(src: T) -> Erase { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 7e053735aa9cf..7001a1eed57e7 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -45,12 +45,11 @@ pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; -trait QueryToConfig<'tcx>: 'tcx { - type Value; - type Config: QueryConfig>; +/// This is implemented per query and restoring query values from their erased state. +trait QueryConfigRestored<'tcx>: QueryConfig> + Default { + type RestoredValue; - fn config(qcx: QueryCtxt<'tcx>) -> Self::Config; - fn restore(value: >>::Value) -> Self::Value; + fn restore(value: >>::Value) -> Self::RestoredValue; } rustc_query_append! { define_queries! } diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 4d64517d4a313..eec9dac7b9b0c 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -13,7 +13,6 @@ use rustc_middle::mir::{self, interpret}; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; -use rustc_query_system::query::QueryConfig; use rustc_query_system::query::{QueryCache, QuerySideEffects}; use rustc_serialize::{ opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}, @@ -1066,13 +1065,13 @@ impl<'a, 'tcx> Encodable> for [u8] { } pub(crate) fn encode_query_results<'a, 'tcx, Q>( - query: Q::Config, + query: Q, qcx: QueryCtxt<'tcx>, encoder: &mut CacheEncoder<'a, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, ) where - Q: super::QueryToConfig<'tcx>, - Q::Value: Encodable>, + Q: super::QueryConfigRestored<'tcx>, + Q::RestoredValue: Encodable>, { let _timer = qcx .tcx diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index a1dfb27c5d73a..afbead7d1ae97 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -564,7 +564,7 @@ macro_rules! define_queries { } #[inline] - fn from_cycle_error( + fn value_from_cycle_error( self, tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], @@ -609,17 +609,11 @@ macro_rules! define_queries { } })* - $(impl<'tcx> QueryToConfig<'tcx> for queries::$name<'tcx> { - type Value = query_values::$name<'tcx>; - type Config = Self; + $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> { + type RestoredValue = query_values::$name<'tcx>; #[inline(always)] - fn config(_qcx: QueryCtxt<'tcx>) -> Self::Config { - Self::default() - } - - #[inline(always)] - fn restore(value: >>::Value) -> Self::Value { + fn restore(value: >>::Value) -> Self::RestoredValue { restore::>(value) } })* @@ -695,7 +689,6 @@ macro_rules! define_queries { use $crate::profiling_support::QueryKeyStringCache; use rustc_query_system::query::QueryMap; use rustc_middle::dep_graph::DepKind; - use crate::QueryToConfig; pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> { fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap) -> Option<()> { @@ -740,7 +733,7 @@ macro_rules! define_queries { }, encode_query_results: expand_if_cached!([$($modifiers)*], |qcx, encoder, query_result_index| $crate::on_disk_cache::encode_query_results::>( - super::queries::$name::config(qcx), + super::queries::$name::default(), qcx, encoder, query_result_index, diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index dc981a802f366..c8d779385108f 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -47,7 +47,8 @@ pub trait QueryConfig: Copy { fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; - fn from_cycle_error( + /// Synthesize an error value to let compilation continue after a cycle. + fn value_from_cycle_error( self, tcx: Qcx::DepContext, cycle: &[QueryInfo], diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 95366e1ad0b8f..20310483d7e86 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -148,7 +148,7 @@ where match handler { Error => { error.emit(); - query.from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) } Fatal => { error.emit(); @@ -157,7 +157,7 @@ where } DelayBug => { error.delay_as_bug(); - query.from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) } } } From 0110073d035530139835585a78c3a62db838a49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 26 Mar 2023 12:51:16 +0200 Subject: [PATCH 5/5] Fully erase query values --- compiler/rustc_middle/src/query/erase.rs | 150 ++++++++++++++++++++--- 1 file changed, 135 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 86532f4f264f9..5462ced16d6b2 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,4 +1,6 @@ -use crate::ty; +use crate::mir; +use crate::traits; +use crate::ty::{self, Ty}; use std::mem::{size_of, transmute_copy, MaybeUninit}; #[derive(Copy, Clone)] @@ -53,32 +55,128 @@ impl EraseType for &'_ ty::List { type Result = [u8; size_of::<*const ()>()]; } -impl EraseType for Result { - type Result = Self; +impl EraseType for Result<&'_ T, traits::query::NoSolution> { + type Result = [u8; size_of::>()]; } -impl EraseType for Option { - type Result = Self; +impl EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::>()]; } -impl EraseType for rustc_hir::MaybeOwner { - type Result = Self; +impl EraseType for Result<&'_ T, traits::CodegenObligationError> { + type Result = [u8; size_of::>()]; } -impl EraseType for ty::Visibility { - type Result = Self; +impl EraseType for Result<&'_ T, ty::layout::FnAbiError<'_>> { + type Result = [u8; size_of::>>()]; } -impl EraseType for ty::Binder<'_, T> { - type Result = Self; +impl EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::< + Result<(&'static (), rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed>, + >()]; } -impl EraseType for ty::EarlyBinder { - type Result = Self; +impl EraseType for Result>, rustc_errors::ErrorGuaranteed> { + type Result = + [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; } -impl EraseType for (T0, T1) { - type Result = Self; +impl EraseType for Result>, rustc_errors::ErrorGuaranteed> { + type Result = + [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; +} + +impl EraseType for Result, traits::query::NoSolution> { + type Result = [u8; size_of::, traits::query::NoSolution>>()]; +} + +impl EraseType for Result> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Result>, ty::layout::LayoutError<'_>> { + type Result = [u8; size_of::< + Result< + rustc_target::abi::TyAndLayout<'static, Ty<'static>>, + ty::layout::LayoutError<'static>, + >, + >()]; +} + +impl EraseType for Result, mir::interpret::LitToConstError> { + type Result = [u8; size_of::, mir::interpret::LitToConstError>>()]; +} + +impl EraseType for Result, mir::interpret::LitToConstError> { + type Result = + [u8; size_of::, mir::interpret::LitToConstError>>()]; +} + +impl EraseType for Result, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result, mir::interpret::ErrorHandled>, + >()]; +} + +impl EraseType for Result, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result, mir::interpret::ErrorHandled>, + >()]; +} + +impl EraseType for Result>, mir::interpret::ErrorHandled> { + type Result = + [u8; size_of::>, mir::interpret::ErrorHandled>>()]; +} + +impl EraseType for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { + type Result = + [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; +} + +impl EraseType for Option<&'_ T> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Option<&'_ [T]> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Option> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Option> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Option>> { + type Result = [u8; size_of::>>>()]; +} + +impl EraseType for Option>> { + type Result = [u8; size_of::>>>()]; +} + +impl EraseType for rustc_hir::MaybeOwner<&'_ T> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for ty::EarlyBinder { + type Result = T::Result; +} + +impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for (&'_ T0, &'_ T1) { + type Result = [u8; size_of::<(&'static (), &'static ())>()]; +} + +impl EraseType for (&'_ T0, &'_ [T1]) { + type Result = [u8; size_of::<(&'static (), &'static [()])>()]; } macro_rules! trivial { @@ -94,6 +192,27 @@ macro_rules! trivial { trivial! { (), bool, + Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Result<(), rustc_errors::ErrorGuaranteed>, + Result<(), rustc_middle::traits::query::NoSolution>, + Result, rustc_ast::expand::allocator::AllocatorKind, rustc_attr::ConstStability, rustc_attr::DefaultBodyStability, @@ -144,6 +263,7 @@ trivial! { rustc_middle::ty::ReprOptions, rustc_middle::ty::UnusedGenericParams, rustc_middle::ty::util::AlwaysRequiresDrop, + rustc_middle::ty::Visibility, rustc_session::config::CrateType, rustc_session::config::EntryFnType, rustc_session::config::OptLevel,