Remove polymorphization
This commit is contained in:
parent
8dc83770f7
commit
711c8cc690
92 changed files with 59 additions and 2643 deletions
|
@ -92,10 +92,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
|
||||
TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
|
||||
TestCase::custom("aot.polymorphize_coroutine", &|runner| {
|
||||
runner.run_rustc(&["example/polymorphize_coroutine.rs", "-Zpolymorphize"]);
|
||||
runner.run_out_command("polymorphize_coroutine", &[]);
|
||||
}),
|
||||
TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]),
|
||||
TestCase::custom("aot.gen_block_iterate", &|runner| {
|
||||
runner.run_rustc([
|
||||
|
|
|
@ -42,7 +42,6 @@ aot.float-minmax-pass
|
|||
aot.mod_bench
|
||||
aot.issue-72793
|
||||
aot.issue-59326
|
||||
aot.polymorphize_coroutine
|
||||
aot.neon
|
||||
aot.gen_block_iterate
|
||||
aot.raw-dylib
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::Coroutine;
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
run_coroutine::<i32>();
|
||||
}
|
||||
|
||||
fn run_coroutine<T>() {
|
||||
let mut coroutine = #[coroutine]
|
||||
|| {
|
||||
yield;
|
||||
return;
|
||||
};
|
||||
Pin::new(&mut coroutine).resume(());
|
||||
}
|
|
@ -394,8 +394,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
def_id,
|
||||
fn_args,
|
||||
source_info.span,
|
||||
)
|
||||
.polymorphize(fx.tcx);
|
||||
);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
if target.is_some() {
|
||||
|
@ -698,7 +697,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
target: BasicBlock,
|
||||
) {
|
||||
let ty = drop_place.layout().ty;
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty);
|
||||
|
||||
if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) =
|
||||
drop_instance.def
|
||||
|
|
|
@ -673,8 +673,7 @@ fn codegen_stmt<'tcx>(
|
|||
def_id,
|
||||
args,
|
||||
)
|
||||
.unwrap()
|
||||
.polymorphize(fx.tcx),
|
||||
.unwrap(),
|
||||
);
|
||||
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
|
||||
lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
|
||||
|
@ -760,8 +759,7 @@ fn codegen_stmt<'tcx>(
|
|||
def_id,
|
||||
args,
|
||||
ty::ClosureKind::FnOnce,
|
||||
)
|
||||
.polymorphize(fx.tcx);
|
||||
);
|
||||
let func_ref = fx.get_function_ref(instance);
|
||||
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
|
||||
lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
|
||||
|
@ -1087,7 +1085,7 @@ fn codegen_panic_inner<'tcx>(
|
|||
|
||||
let def_id = fx.tcx.require_lang_item(lang_item, span);
|
||||
|
||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||
let instance = Instance::mono(fx.tcx, def_id);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
fx.bcx.ins().trap(TrapCode::user(2).unwrap());
|
||||
|
|
|
@ -452,8 +452,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
let data_id = match reloc_target_alloc {
|
||||
GlobalAlloc::Function { instance, .. } => {
|
||||
assert_eq!(addend, 0);
|
||||
let func_id =
|
||||
crate::abi::import_function(tcx, module, instance.polymorphize(tcx));
|
||||
let func_id = crate::abi::import_function(tcx, module, instance);
|
||||
let local_func_id = module.declare_func_in_data(func_id, &mut data);
|
||||
data.write_function_addr(offset.bytes() as u32, local_func_id);
|
||||
continue;
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
};
|
||||
|
||||
if main_def_id.is_local() {
|
||||
let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
|
||||
let instance = Instance::mono(tcx, main_def_id);
|
||||
if module.get_name(tcx.symbol_name(instance).name).is_none() {
|
||||
return;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
}
|
||||
};
|
||||
|
||||
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
||||
let instance = Instance::mono(tcx, rust_main_def_id);
|
||||
|
||||
let main_name = tcx.symbol_name(instance).name;
|
||||
let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
|
||||
|
@ -117,8 +117,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
report.def_id,
|
||||
tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
|
||||
DUMMY_SP,
|
||||
)
|
||||
.polymorphize(tcx);
|
||||
);
|
||||
|
||||
let report_name = tcx.symbol_name(report).name;
|
||||
let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
|
||||
|
@ -143,8 +142,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
start_def_id,
|
||||
tcx.mk_args(&[main_ret_ty.into()]),
|
||||
DUMMY_SP,
|
||||
)
|
||||
.polymorphize(tcx);
|
||||
);
|
||||
let start_func_id = import_function(tcx, m, start_instance);
|
||||
|
||||
let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
|
||||
|
|
|
@ -1005,9 +1005,6 @@ pub(crate) fn assert_assignable<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
(ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => {
|
||||
// No way to check if it is correct or not with polymorphization enabled
|
||||
}
|
||||
_ => {
|
||||
assert_eq!(
|
||||
from_ty,
|
||||
|
|
|
@ -6,7 +6,6 @@ tests/ui/functions-closures/parallel-codegen-closures.rs
|
|||
tests/ui/linkage-attr/linkage1.rs
|
||||
tests/ui/lto/dylib-works.rs
|
||||
tests/ui/numbers-arithmetic/saturating-float-casts.rs
|
||||
tests/ui/polymorphization/promoted-function.rs
|
||||
tests/ui/sepcomp/sepcomp-cci.rs
|
||||
tests/ui/sepcomp/sepcomp-extern.rs
|
||||
tests/ui/sepcomp/sepcomp-fns-backwards.rs
|
||||
|
|
|
@ -302,10 +302,9 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
(value, AddressSpace::DATA)
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Function { instance, .. } => (
|
||||
self.get_fn_addr(instance.polymorphize(self.tcx)),
|
||||
self.data_layout().instruction_address_space,
|
||||
),
|
||||
GlobalAlloc::Function { instance, .. } => {
|
||||
(self.get_fn_addr(instance), self.data_layout().instruction_address_space)
|
||||
}
|
||||
GlobalAlloc::VTable(ty, dyn_ty) => {
|
||||
let alloc = self
|
||||
.tcx
|
||||
|
|
|
@ -471,8 +471,6 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
|
|||
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
|
||||
},
|
||||
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
|
||||
// Type parameters from polymorphized functions.
|
||||
ty::Param(_) => build_param_type_di_node(cx, t),
|
||||
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
|
||||
};
|
||||
|
||||
|
@ -871,26 +869,6 @@ fn build_foreign_type_di_node<'ll, 'tcx>(
|
|||
)
|
||||
}
|
||||
|
||||
fn build_param_type_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
debug!("build_param_type_di_node: {:?}", t);
|
||||
let name = format!("{t:?}");
|
||||
DINodeCreationResult {
|
||||
di_node: unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
Size::ZERO.bits(),
|
||||
DW_ATE_unsigned,
|
||||
)
|
||||
},
|
||||
already_stored_in_typemap: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
codegen_unit_name: &str,
|
||||
|
|
|
@ -432,11 +432,8 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
|
||||
}
|
||||
}
|
||||
// Type parameters from polymorphized functions.
|
||||
ty::Param(_) => {
|
||||
write!(output, "{t:?}").unwrap();
|
||||
}
|
||||
ty::Error(_)
|
||||
ty::Param(_)
|
||||
| ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Alias(..)
|
||||
|
|
|
@ -847,10 +847,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
let (instance, mut llfn) = match *callee.layout.ty.kind() {
|
||||
ty::FnDef(def_id, args) => (
|
||||
Some(
|
||||
ty::Instance::expect_resolve(bx.tcx(), bx.typing_env(), def_id, args, fn_span)
|
||||
.polymorphize(bx.tcx()),
|
||||
),
|
||||
Some(ty::Instance::expect_resolve(
|
||||
bx.tcx(),
|
||||
bx.typing_env(),
|
||||
def_id,
|
||||
args,
|
||||
fn_span,
|
||||
)),
|
||||
None,
|
||||
),
|
||||
ty::FnPtr(..) => (None, Some(callee.immediate())),
|
||||
|
|
|
@ -478,8 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
def_id,
|
||||
args,
|
||||
)
|
||||
.unwrap()
|
||||
.polymorphize(bx.cx().tcx());
|
||||
.unwrap();
|
||||
OperandValue::Immediate(bx.get_fn_addr(instance))
|
||||
}
|
||||
_ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
|
||||
|
@ -493,8 +492,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
def_id,
|
||||
args,
|
||||
ty::ClosureKind::FnOnce,
|
||||
)
|
||||
.polymorphize(bx.cx().tcx());
|
||||
);
|
||||
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
|
||||
}
|
||||
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
|
||||
|
|
|
@ -14,10 +14,8 @@ use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationR
|
|||
|
||||
/// Checks whether a type contains generic parameters which must be instantiated.
|
||||
///
|
||||
/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
|
||||
/// types may be "concrete enough" even though they still contain generic parameters in
|
||||
/// case these parameters are unused.
|
||||
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
|
||||
/// In case it does, returns a `TooGeneric` const eval error.
|
||||
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(_tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
|
||||
where
|
||||
T: TypeVisitable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
@ -27,11 +25,9 @@ where
|
|||
}
|
||||
|
||||
struct FoundParam;
|
||||
struct UsedParamsNeedInstantiationVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
struct UsedParamsNeedInstantiationVisitor {}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor {
|
||||
type Result = ControlFlow<FoundParam>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
|
@ -41,25 +37,7 @@ where
|
|||
|
||||
match *ty.kind() {
|
||||
ty::Param(_) => ControlFlow::Break(FoundParam),
|
||||
ty::Closure(def_id, args)
|
||||
| ty::CoroutineClosure(def_id, args, ..)
|
||||
| ty::Coroutine(def_id, args, ..)
|
||||
| ty::FnDef(def_id, args) => {
|
||||
let instance = ty::InstanceKind::Item(def_id);
|
||||
let unused_params = self.tcx.unused_generic_params(instance);
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
let index = index
|
||||
.try_into()
|
||||
.expect("more generic parameters than can fit into a `u32`");
|
||||
// Only recurse when generic parameters in fns, closures and coroutines
|
||||
// are used and have to be instantiated.
|
||||
//
|
||||
// Just in case there are closures or coroutines within this arg,
|
||||
// recurse.
|
||||
if unused_params.is_used(index) && arg.has_param() {
|
||||
return arg.visit_with(self);
|
||||
}
|
||||
}
|
||||
ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::FnDef(..) => {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
|
@ -74,7 +52,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let mut vis = UsedParamsNeedInstantiationVisitor { tcx };
|
||||
let mut vis = UsedParamsNeedInstantiationVisitor {};
|
||||
if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
|
||||
throw_inval!(TooGeneric);
|
||||
} else {
|
||||
|
|
|
@ -1103,10 +1103,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
TEST, rustc_symbol_name, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_polymorphize_error, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_def_path, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
|
|
|
@ -876,7 +876,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
|| tcx.hir().body_const_context(def_id).is_some()
|
||||
{
|
||||
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
|
||||
tcx.ensure().unused_generic_params(ty::InstanceKind::Item(def_id.to_def_id()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -895,8 +894,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
|
||||
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
|
||||
// in MIR optimizations that may only be reachable through codegen, or other codepaths
|
||||
// that requires the optimized/ctfe MIR, such as polymorphization, coroutine bodies,
|
||||
// or evaluating consts.
|
||||
// that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
|
||||
if tcx.sess.opts.unstable_opts.validate_mir {
|
||||
sess.time("ensuring_final_MIR_is_computable", || {
|
||||
tcx.hir().par_body_owners(|def_id| {
|
||||
|
|
|
@ -269,7 +269,6 @@ provide! { tcx, def_id, other, cdata,
|
|||
lookup_default_body_stability => { table }
|
||||
lookup_deprecation_entry => { table }
|
||||
params_in_repr => { table }
|
||||
unused_generic_params => { table_direct }
|
||||
def_kind => { cdata.def_kind(def_id.index) }
|
||||
impl_parent => { table }
|
||||
defaultness => { table_direct }
|
||||
|
|
|
@ -1767,10 +1767,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
{
|
||||
record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses);
|
||||
}
|
||||
|
||||
let instance = ty::InstanceKind::Item(def_id.to_def_id());
|
||||
let unused = tcx.unused_generic_params(instance);
|
||||
self.tables.unused_generic_params.set(def_id.local_def_index, unused);
|
||||
}
|
||||
|
||||
// Encode all the deduced parameter attributes for everything that has MIR, even for items
|
||||
|
|
|
@ -395,7 +395,6 @@ define_tables! {
|
|||
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
|
||||
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
|
||||
unused_generic_params: Table<DefIndex, UnusedGenericParams>,
|
||||
// Reexported names are not associated with individual `DefId`s,
|
||||
// e.g. a glob import can introduce a lot of names, all with the same `DefId`.
|
||||
// That's why the encoded list needs to contain `ModChild` structures describing all the names
|
||||
|
|
|
@ -82,7 +82,7 @@ use crate::ty::print::{PrintTraitRefExt, describe_as_module};
|
|||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::{
|
||||
self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
|
||||
TyCtxtFeed, UnusedGenericParams,
|
||||
TyCtxtFeed,
|
||||
};
|
||||
use crate::{dep_graph, mir, thir};
|
||||
|
||||
|
@ -2048,15 +2048,6 @@ rustc_queries! {
|
|||
desc { "getting codegen unit `{sym}`" }
|
||||
}
|
||||
|
||||
query unused_generic_params(key: ty::InstanceKind<'tcx>) -> UnusedGenericParams {
|
||||
cache_on_disk_if { key.def_id().is_local() }
|
||||
desc {
|
||||
|tcx| "determining which generic parameters are unused by `{}`",
|
||||
tcx.def_path_str(key.def_id())
|
||||
}
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query backend_optimization_level(_: ()) -> OptLevel {
|
||||
desc { "optimization level used by backend" }
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ use crate::error;
|
|||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::ty::print::{FmtPrinter, Printer, shrunk_instance_name};
|
||||
use crate::ty::{
|
||||
self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
|
||||
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
|
||||
/// An `InstanceKind` along with the args that are needed to substitute the instance.
|
||||
|
@ -917,116 +917,6 @@ impl<'tcx> Instance<'tcx> {
|
|||
tcx.try_normalize_erasing_regions(typing_env, v.instantiate_identity())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new `Instance` where generic parameters in `instance.args` are replaced by
|
||||
/// identity parameters if they are determined to be unused in `instance.def`.
|
||||
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
debug!("polymorphize: running polymorphization analysis");
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize {
|
||||
return self;
|
||||
}
|
||||
|
||||
let polymorphized_args = polymorphize(tcx, self.def, self.args);
|
||||
debug!("polymorphize: self={:?} polymorphized_args={:?}", self, polymorphized_args);
|
||||
Self { def: self.def, args: polymorphized_args }
|
||||
}
|
||||
}
|
||||
|
||||
fn polymorphize<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: ty::InstanceKind<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
debug!("polymorphize({:?}, {:?})", instance, args);
|
||||
let unused = tcx.unused_generic_params(instance);
|
||||
debug!("polymorphize: unused={:?}", unused);
|
||||
|
||||
// If this is a closure or coroutine then we need to handle the case where another closure
|
||||
// from the function is captured as an upvar and hasn't been polymorphized. In this case,
|
||||
// the unpolymorphized upvar closure would result in a polymorphized closure producing
|
||||
// multiple mono items (and eventually symbol clashes).
|
||||
let def_id = instance.def_id();
|
||||
let upvars_ty = match tcx.type_of(def_id).skip_binder().kind() {
|
||||
ty::Closure(..) => Some(args.as_closure().tupled_upvars_ty()),
|
||||
ty::Coroutine(..) => {
|
||||
assert_eq!(
|
||||
args.as_coroutine().kind_ty(),
|
||||
tcx.types.unit,
|
||||
"polymorphization does not support coroutines from async closures"
|
||||
);
|
||||
Some(args.as_coroutine().tupled_upvars_ty())
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let has_upvars = upvars_ty.is_some_and(|ty| !ty.tuple_fields().is_empty());
|
||||
debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
|
||||
|
||||
struct PolymorphizationFolder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for PolymorphizationFolder<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
debug!("fold_ty: ty={:?}", ty);
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, args) => {
|
||||
let polymorphized_args =
|
||||
polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args);
|
||||
if args == polymorphized_args {
|
||||
ty
|
||||
} else {
|
||||
Ty::new_closure(self.tcx, def_id, polymorphized_args)
|
||||
}
|
||||
}
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let polymorphized_args =
|
||||
polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args);
|
||||
if args == polymorphized_args {
|
||||
ty
|
||||
} else {
|
||||
Ty::new_coroutine(self.tcx, def_id, polymorphized_args)
|
||||
}
|
||||
}
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenericArgs::for_item(tcx, def_id, |param, _| {
|
||||
let is_unused = unused.is_unused(param.index);
|
||||
debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
|
||||
match param.kind {
|
||||
// Upvar case: If parameter is a type parameter..
|
||||
ty::GenericParamDefKind::Type { .. } if
|
||||
// ..and has upvars..
|
||||
has_upvars &&
|
||||
// ..and this param has the same type as the tupled upvars..
|
||||
upvars_ty == Some(args[param.index as usize].expect_ty()) => {
|
||||
// ..then double-check that polymorphization marked it used..
|
||||
debug_assert!(!is_unused);
|
||||
// ..and polymorphize any closures/coroutines captured as upvars.
|
||||
let upvars_ty = upvars_ty.unwrap();
|
||||
let polymorphized_upvars_ty = upvars_ty.fold_with(
|
||||
&mut PolymorphizationFolder { tcx });
|
||||
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
|
||||
ty::GenericArg::from(polymorphized_upvars_ty)
|
||||
},
|
||||
|
||||
// Simple case: If parameter is a const or type parameter..
|
||||
ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if
|
||||
// ..and is within range and unused..
|
||||
unused.is_unused(param.index) =>
|
||||
// ..then use the identity for this parameter.
|
||||
tcx.mk_param_from_def(param),
|
||||
|
||||
// Otherwise, use the parameter as before.
|
||||
_ => args[param.index as usize],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn needs_fn_once_adapter_shim(
|
||||
|
|
|
@ -131,8 +131,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
|
|||
VtblEntry::Vacant => continue,
|
||||
VtblEntry::Method(instance) => {
|
||||
// Prepare the fn ptr we write into the vtable.
|
||||
let instance = instance.polymorphize(tcx);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
|
||||
let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT);
|
||||
let fn_ptr = Pointer::from(fn_alloc_id);
|
||||
Scalar::from_pointer(fn_ptr, &tcx)
|
||||
}
|
||||
|
|
|
@ -41,6 +41,4 @@ monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
|
|||
monomorphize_unknown_cgu_collection_mode =
|
||||
unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
|
||||
|
||||
monomorphize_unused_generic_params = item has unused generic parameters
|
||||
|
||||
monomorphize_written_to_path = the full type name has been written to '{$path}'
|
||||
|
|
|
@ -965,9 +965,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
|
|||
return true;
|
||||
}
|
||||
|
||||
if tcx.is_reachable_non_generic(def_id)
|
||||
|| instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some()
|
||||
{
|
||||
if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(*tcx).is_some() {
|
||||
// We can link to the item in question, no instance needed in this crate.
|
||||
return false;
|
||||
}
|
||||
|
@ -1114,7 +1112,7 @@ fn create_fn_mono_item<'tcx>(
|
|||
crate::util::dump_closure_profile(tcx, instance);
|
||||
}
|
||||
|
||||
respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
|
||||
respan(source, MonoItem::Fn(instance))
|
||||
}
|
||||
|
||||
/// Creates a `MonoItem` for each method that is referenced by the vtable for
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(monomorphize_recursion_limit)]
|
||||
pub(crate) struct RecursionLimit {
|
||||
|
@ -28,28 +25,6 @@ pub(crate) struct NoOptimizedMir {
|
|||
pub crate_name: Symbol,
|
||||
}
|
||||
|
||||
pub(crate) struct UnusedGenericParamsHint {
|
||||
pub span: Span,
|
||||
pub param_spans: Vec<Span>,
|
||||
pub param_names: Vec<String>,
|
||||
}
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for UnusedGenericParamsHint {
|
||||
#[track_caller]
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::monomorphize_unused_generic_params);
|
||||
diag.span(self.span);
|
||||
for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
|
||||
// FIXME: I can figure out how to do a label with a fluent string with a fixed message,
|
||||
// or a label with a dynamic value in a hard-coded string, but I haven't figured out
|
||||
// how to combine the two. 😢
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(span, format!("generic parameter `{name}` is unused"));
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(monomorphize_large_assignments)]
|
||||
#[note]
|
||||
|
|
|
@ -19,7 +19,6 @@ mod collector;
|
|||
mod errors;
|
||||
mod mono_checks;
|
||||
mod partitioning;
|
||||
mod polymorphize;
|
||||
mod util;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
@ -50,6 +49,5 @@ fn custom_coerce_unsize_info<'tcx>(
|
|||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
partitioning::provide(providers);
|
||||
polymorphize::provide(providers);
|
||||
mono_checks::provide(providers);
|
||||
}
|
||||
|
|
|
@ -113,7 +113,6 @@ use rustc_middle::mir::mono::{
|
|||
Visibility,
|
||||
};
|
||||
use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, InstanceKind, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::CodegenUnits;
|
||||
|
@ -661,18 +660,14 @@ fn characteristic_def_id_of_mono_item<'tcx>(
|
|||
return None;
|
||||
}
|
||||
|
||||
// When polymorphization is enabled, methods which do not depend on their generic
|
||||
// parameters, but the self-type of their impl block do will fail to normalize.
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() {
|
||||
// This is a method within an impl, find out what the self-type is:
|
||||
let impl_self_ty = tcx.instantiate_and_normalize_erasing_regions(
|
||||
instance.args,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
tcx.type_of(impl_def_id),
|
||||
);
|
||||
if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
|
||||
return Some(def_id);
|
||||
}
|
||||
// This is a method within an impl, find out what the self-type is:
|
||||
let impl_self_ty = tcx.instantiate_and_normalize_erasing_regions(
|
||||
instance.args,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
tcx.type_of(impl_def_id),
|
||||
);
|
||||
if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
|
||||
return Some(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,334 +0,0 @@
|
|||
//! Polymorphization Analysis
|
||||
//! =========================
|
||||
//!
|
||||
//! This module implements an analysis of functions, methods and closures to determine which
|
||||
//! generic parameters are unused (and eventually, in what ways generic parameters are used - only
|
||||
//! for their size, offset of a field, etc.).
|
||||
|
||||
use rustc_hir::ConstContext;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::visit::{TyContext, Visitor};
|
||||
use rustc_middle::mir::{self, Local, LocalDecl, Location};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams};
|
||||
use rustc_span::symbol::sym;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::errors::UnusedGenericParamsHint;
|
||||
|
||||
/// Provide implementations of queries relating to polymorphization analysis.
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.unused_generic_params = unused_generic_params;
|
||||
}
|
||||
|
||||
/// Determine which generic parameters are used by the instance.
|
||||
///
|
||||
/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
|
||||
/// parameters are used).
|
||||
fn unused_generic_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: ty::InstanceKind<'tcx>,
|
||||
) -> UnusedGenericParams {
|
||||
assert!(instance.def_id().is_local());
|
||||
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize {
|
||||
// If polymorphization disabled, then all parameters are used.
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
let def_id = instance.def_id();
|
||||
// Exit early if this instance should not be polymorphized.
|
||||
if !should_polymorphize(tcx, def_id, instance) {
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
debug!(?generics);
|
||||
|
||||
// Exit early when there are no parameters to be unused.
|
||||
if generics.is_empty() {
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
// Create a bitset with N rightmost ones for each parameter.
|
||||
let generics_count: u32 =
|
||||
generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
|
||||
let mut unused_parameters = UnusedGenericParams::new_all_unused(generics_count);
|
||||
debug!(?unused_parameters, "(start)");
|
||||
|
||||
mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
|
||||
debug!(?unused_parameters, "(after default)");
|
||||
|
||||
// Visit MIR and accumulate used generic parameters.
|
||||
let body = match tcx.hir().body_const_context(def_id.expect_local()) {
|
||||
// Const functions are actually called and should thus be considered for polymorphization
|
||||
// via their runtime MIR.
|
||||
Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
|
||||
Some(_) => tcx.mir_for_ctfe(def_id),
|
||||
};
|
||||
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
|
||||
vis.visit_body(body);
|
||||
debug!(?unused_parameters, "(end)");
|
||||
|
||||
// Emit errors for debugging and testing if enabled.
|
||||
if !unused_parameters.all_used() {
|
||||
emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters);
|
||||
}
|
||||
|
||||
unused_parameters
|
||||
}
|
||||
|
||||
/// Returns `true` if the instance should be polymorphized.
|
||||
fn should_polymorphize<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
instance: ty::InstanceKind<'tcx>,
|
||||
) -> bool {
|
||||
// If an instance's MIR body is not polymorphic then the modified generic parameters that are
|
||||
// derived from polymorphization's result won't make any difference.
|
||||
if !instance.has_polymorphic_mir_body() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
|
||||
if matches!(instance, ty::InstanceKind::Intrinsic(..) | ty::InstanceKind::Virtual(..)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Foreign items have no bodies to analyze.
|
||||
if tcx.is_foreign_item(def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure there is MIR available.
|
||||
match tcx.hir().body_const_context(def_id.expect_local()) {
|
||||
Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
|
||||
debug!("no mir available");
|
||||
return false;
|
||||
}
|
||||
Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
|
||||
debug!("no ctfe mir available");
|
||||
return false;
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
|
||||
/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
|
||||
/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
|
||||
#[instrument(level = "debug", skip(tcx, def_id, generics, unused_parameters))]
|
||||
fn mark_used_by_default_parameters<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &mut UnusedGenericParams,
|
||||
) {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Closure | DefKind::SyntheticCoroutineBody => {
|
||||
for param in &generics.own_params {
|
||||
debug!(?param, "(closure/gen)");
|
||||
unused_parameters.mark_used(param.index);
|
||||
}
|
||||
}
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
| DefKind::Enum
|
||||
| DefKind::Variant
|
||||
| DefKind::Trait
|
||||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::AssocTy
|
||||
| DefKind::TyParam
|
||||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Ctor(_, _)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Macro(_)
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl { .. } => {
|
||||
for param in &generics.own_params {
|
||||
debug!(?param, "(other)");
|
||||
if let ty::GenericParamDefKind::Lifetime = param.kind {
|
||||
unused_parameters.mark_used(param.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(parent) = generics.parent {
|
||||
mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
|
||||
/// parameter which was unused.
|
||||
#[instrument(level = "debug", skip(tcx, generics))]
|
||||
fn emit_unused_generic_params_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &UnusedGenericParams,
|
||||
) {
|
||||
let base_def_id = tcx.typeck_root_def_id(def_id);
|
||||
if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fn_span = match tcx.opt_item_ident(def_id) {
|
||||
Some(ident) => ident.span,
|
||||
_ => tcx.def_span(def_id),
|
||||
};
|
||||
|
||||
let mut param_spans = Vec::new();
|
||||
let mut param_names = Vec::new();
|
||||
let mut next_generics = Some(generics);
|
||||
while let Some(generics) = next_generics {
|
||||
for param in &generics.own_params {
|
||||
if unused_parameters.is_unused(param.index) {
|
||||
debug!(?param);
|
||||
let def_span = tcx.def_span(param.def_id);
|
||||
param_spans.push(def_span);
|
||||
param_names.push(param.name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
next_generics = generics.parent.map(|did| tcx.generics_of(did));
|
||||
}
|
||||
|
||||
tcx.dcx().emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names });
|
||||
}
|
||||
|
||||
/// Visitor used to aggregate generic parameter uses.
|
||||
struct MarkUsedGenericParams<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
unused_parameters: &'a mut UnusedGenericParams,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
|
||||
/// Invoke `unused_generic_params` on a body contained within the current item (e.g.
|
||||
/// a closure, coroutine or constant).
|
||||
#[instrument(level = "debug", skip(self, def_id, args))]
|
||||
fn visit_child_body(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) {
|
||||
let instance = ty::InstanceKind::Item(def_id);
|
||||
let unused = self.tcx.unused_generic_params(instance);
|
||||
debug!(?self.unused_parameters, ?unused);
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let i = i.try_into().unwrap();
|
||||
if unused.is_used(i) {
|
||||
arg.visit_with(self);
|
||||
}
|
||||
}
|
||||
debug!(?self.unused_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self, local))]
|
||||
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
if local == Local::from_usize(1) {
|
||||
let def_kind = self.tcx.def_kind(self.def_id);
|
||||
if matches!(def_kind, DefKind::Closure) {
|
||||
// Skip visiting the closure/coroutine that is currently being processed. This only
|
||||
// happens because the first argument to the closure is a reference to itself and
|
||||
// that will call `visit_args`, resulting in each generic parameter captured being
|
||||
// considered used by default.
|
||||
debug!("skipping closure args");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.super_local_decl(local, local_decl);
|
||||
}
|
||||
|
||||
fn visit_const_operand(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) {
|
||||
match ct.const_ {
|
||||
mir::Const::Ty(_, c) => {
|
||||
c.visit_with(self);
|
||||
}
|
||||
mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => {
|
||||
// Avoid considering `T` unused when constants are of the form:
|
||||
// `<Self as Foo<T>>::foo::promoted[p]`
|
||||
if let Some(p) = promoted {
|
||||
if self.def_id == def && !self.tcx.generics_of(def).has_self {
|
||||
// If there is a promoted, don't look at the args - since it will always contain
|
||||
// the generic parameters, instead, traverse the promoted MIR.
|
||||
let promoted = self.tcx.promoted_mir(def);
|
||||
self.visit_body(&promoted[p]);
|
||||
}
|
||||
}
|
||||
|
||||
Visitor::visit_ty(self, ty, TyContext::Location(location));
|
||||
}
|
||||
mir::Const::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) {
|
||||
ty.visit_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) {
|
||||
if !c.has_non_region_param() {
|
||||
return;
|
||||
}
|
||||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
}
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args })
|
||||
if matches!(self.tcx.def_kind(def), DefKind::AnonConst) =>
|
||||
{
|
||||
self.visit_child_body(def, args);
|
||||
}
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) {
|
||||
if !ty.has_non_region_param() {
|
||||
return;
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, args) | ty::Coroutine(def_id, args, ..) => {
|
||||
debug!(?def_id);
|
||||
// Avoid cycle errors with coroutines.
|
||||
if def_id == self.def_id {
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider any generic parameters used by any closures/coroutines as used in the
|
||||
// parent.
|
||||
self.visit_child_body(def_id, args);
|
||||
}
|
||||
ty::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1950,8 +1950,6 @@ options! {
|
|||
(default: PLT is disabled if full relro is enabled on x86_64)"),
|
||||
polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
|
||||
"enable polonius-based borrow-checker (default: no)"),
|
||||
polymorphize: bool = (false, parse_bool, [TRACKED],
|
||||
"perform polymorphization analysis"),
|
||||
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
|
||||
"a single extra argument to prepend the linker invocation (can be used several times)"),
|
||||
pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
|
||||
|
|
|
@ -1746,7 +1746,6 @@ symbols! {
|
|||
rustc_peek_liveness,
|
||||
rustc_peek_maybe_init,
|
||||
rustc_peek_maybe_uninit,
|
||||
rustc_polymorphize_error,
|
||||
rustc_preserve_ub_checks,
|
||||
rustc_private,
|
||||
rustc_proc_macro_decls,
|
||||
|
|
|
@ -256,7 +256,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
});
|
||||
|
||||
// Encode impl generic params if the generic parameters contain non-region parameters
|
||||
// (implying polymorphization is enabled) and this isn't an inherent impl.
|
||||
// and this isn't an inherent impl.
|
||||
if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) {
|
||||
self.path_generic_args(
|
||||
|this| {
|
||||
|
@ -330,9 +330,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
ty::Float(FloatTy::F128) => "C4f128",
|
||||
ty::Never => "z",
|
||||
|
||||
// Should only be encountered with polymorphization,
|
||||
// or within the identity-substituted impl header of an
|
||||
// item nested within an impl item.
|
||||
// Should only be encountered within the identity-substituted
|
||||
// impl header of an item nested within an impl item.
|
||||
ty::Param(_) => "p",
|
||||
|
||||
ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => bug!(),
|
||||
|
@ -558,9 +557,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
let (ct_ty, valtree) = match ct.kind() {
|
||||
ty::ConstKind::Value(ty, val) => (ty, val),
|
||||
|
||||
// Should only be encountered with polymorphization,
|
||||
// or within the identity-substituted impl header of an
|
||||
// item nested within an impl item.
|
||||
// Should only be encountered within the identity-substituted
|
||||
// impl header of an item nested within an impl item.
|
||||
ty::ConstKind::Param(_) => {
|
||||
// Never cached (single-character).
|
||||
self.push("p");
|
||||
|
|
|
@ -45,23 +45,8 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||
let ty = instance.ty(tcx, typing_env);
|
||||
match *ty.kind() {
|
||||
ty::FnDef(def_id, args) => {
|
||||
// HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
|
||||
// parameters unused if they show up in the signature, but not in the `mir::Body`
|
||||
// (i.e. due to being inside a projection that got normalized, see
|
||||
// `tests/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
|
||||
// track of a polymorphization `ParamEnv` to allow normalizing later.
|
||||
//
|
||||
// We normalize the `fn_sig` again after instantiating at a later point.
|
||||
let mut sig = tcx.instantiate_bound_regions_with_erased(
|
||||
tcx.fn_sig(def_id)
|
||||
.map_bound(|fn_sig| {
|
||||
tcx.normalize_erasing_regions(
|
||||
ty::TypingEnv::non_body_analysis(tcx, def_id),
|
||||
fn_sig,
|
||||
)
|
||||
})
|
||||
.instantiate(tcx, args),
|
||||
);
|
||||
let mut sig = tcx
|
||||
.instantiate_bound_regions_with_erased(tcx.fn_sig(def_id).instantiate(tcx, args));
|
||||
|
||||
if let ty::InstanceKind::VTableShim(..) = instance.def {
|
||||
let mut inputs_and_output = sig.inputs_and_output.to_vec();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue