Remove polymorphization

This commit is contained in:
Ben Kimock 2024-12-04 21:03:12 -05:00
parent 8dc83770f7
commit 711c8cc690
92 changed files with 59 additions and 2643 deletions

View File

@ -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([

View File

@ -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

View File

@ -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(());
}

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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(..)

View File

@ -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())),

View File

@ -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),

View File

@ -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 {

View File

@ -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

View File

@ -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| {

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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" }
}

View File

@ -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(

View File

@ -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)
}

View File

@ -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}'

View File

@ -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

View File

@ -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]

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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),
}
}
}

View File

@ -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],

View File

@ -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,

View File

@ -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");

View File

@ -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();

View File

@ -695,7 +695,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
),
rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
gated!(

View File

@ -510,7 +510,6 @@ ui/confuse-field-and-method/issue-2392.rs
ui/confuse-field-and-method/issue-32128.rs
ui/confuse-field-and-method/issue-33784.rs
ui/const-generics/generic_arg_infer/issue-91614.rs
ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs
ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs
ui/const-generics/generic_const_exprs/issue-100217.rs
ui/const-generics/generic_const_exprs/issue-100360.rs
@ -540,7 +539,6 @@ ui/const-generics/generic_const_exprs/issue-85848.rs
ui/const-generics/generic_const_exprs/issue-86710.rs
ui/const-generics/generic_const_exprs/issue-89851.rs
ui/const-generics/generic_const_exprs/issue-90847.rs
ui/const-generics/generic_const_exprs/issue-94287.rs
ui/const-generics/generic_const_exprs/issue-94293.rs
ui/const-generics/generic_const_exprs/issue-96699.rs
ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs
@ -3481,8 +3479,6 @@ ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs
ui/pattern/usefulness/issue-82772-match-box-as-struct.rs
ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs
ui/pattern/usefulness/issue-88747.rs
ui/polymorphization/issue-74614.rs
ui/polymorphization/issue-74636.rs
ui/privacy/auxiliary/issue-117997.rs
ui/privacy/auxiliary/issue-119463-extern.rs
ui/privacy/auxiliary/issue-17718-const-privacy.rs

View File

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
//@ compile-flags:-Zprint-mono-items=eager
#![feature(start)]
@ -6,7 +6,7 @@ pub static FN: fn() = foo::<i32>;
pub fn foo<T>() {}
//~ MONO_ITEM fn foo::<T>
//~ MONO_ITEM fn foo::<i32>
//~ MONO_ITEM static FN
//~ MONO_ITEM fn start

View File

@ -1,4 +1,4 @@
//@ compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on -Zinline-mir=no
//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
#![deny(dead_code)]
#![feature(start)]
@ -29,7 +29,7 @@ impl SomeGenericTrait<u64> for i32 {
// For the non-generic foo(), we should generate a codegen-item even if it
// is not called anywhere
//~ MONO_ITEM fn <i32 as SomeGenericTrait<T1>>::foo
//~ MONO_ITEM fn <i32 as SomeGenericTrait<u64>>::foo
}
// Non-generic impl of generic trait

View File

@ -1,4 +0,0 @@
//@ compile-flags: -Zpolymorphize=on
#[inline(never)]
pub fn foo<T>() {}

View File

@ -1,11 +0,0 @@
//@ aux-build:poly-dep.rs
//@ compile-flags: --crate-type=lib -Zprint-mono-items=eager -Zpolymorphize=on
extern crate poly_dep;
pub static FN1: fn() = poly_dep::foo::<i32>;
pub static FN2: fn() = poly_dep::foo::<u32>;
//~ MONO_ITEM static FN1
//~ MONO_ITEM static FN2
//~ MONO_ITEM fn poly_dep::foo::<T>

View File

@ -1,315 +0,0 @@
//@ compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
#![crate_type = "rlib"]
// This test checks that the polymorphization analysis correctly reduces the
// generated mono items.
mod functions {
// Function doesn't have any type parameters to be unused.
pub fn no_parameters() {}
//~ MONO_ITEM fn functions::no_parameters
// Function has an unused type parameter.
pub fn unused<T>() {}
//~ MONO_ITEM fn functions::unused::<T>
// Function uses type parameter in value of a binding.
pub fn used_binding_value<T: Default>() {
let _: T = Default::default();
}
//~ MONO_ITEM fn functions::used_binding_value::<u32>
//~ MONO_ITEM fn functions::used_binding_value::<u64>
// Function uses type parameter in type of a binding.
pub fn used_binding_type<T>() {
let _: Option<T> = None;
}
//~ MONO_ITEM fn functions::used_binding_type::<u32>
//~ MONO_ITEM fn functions::used_binding_type::<u64>
// Function uses type parameter in argument.
pub fn used_argument<T>(_: T) {}
//~ MONO_ITEM fn functions::used_argument::<u32>
//~ MONO_ITEM fn functions::used_argument::<u64>
//
// Function uses type parameter in substitutions to another function.
pub fn used_substs<T>() {
unused::<T>()
}
//~ MONO_ITEM fn functions::used_substs::<u32>
//~ MONO_ITEM fn functions::used_substs::<u64>
}
mod closures {
// Function doesn't have any type parameters to be unused.
pub fn no_parameters() {
let _ = || {};
}
//~ MONO_ITEM fn closures::no_parameters
// Function has an unused type parameter in parent and closure.
pub fn unused<T>() -> u32 {
let add_one = |x: u32| x + 1;
add_one(3)
}
//~ MONO_ITEM fn closures::unused::<T>::{closure#0}
//~ MONO_ITEM fn closures::unused::<T>
// Function has an unused type parameter in closure, but not in parent.
pub fn used_parent<T: Default>() -> u32 {
let _: T = Default::default();
let add_one = |x: u32| x + 1;
add_one(3)
}
//~ MONO_ITEM fn closures::used_parent::<T>::{closure#0}
//~ MONO_ITEM fn closures::used_parent::<u32>
//~ MONO_ITEM fn closures::used_parent::<u64>
// Function uses type parameter in value of a binding in closure.
pub fn used_binding_value<T: Default>() -> T {
let x = || {
let y: T = Default::default();
y
};
x()
}
//~ MONO_ITEM fn closures::used_binding_value::<u32>::{closure#0}
//~ MONO_ITEM fn closures::used_binding_value::<u64>::{closure#0}
//~ MONO_ITEM fn closures::used_binding_value::<u32>
//~ MONO_ITEM fn closures::used_binding_value::<u64>
// Function uses type parameter in type of a binding in closure.
pub fn used_binding_type<T>() -> Option<T> {
let x = || {
let y: Option<T> = None;
y
};
x()
}
//~ MONO_ITEM fn closures::used_binding_type::<u32>::{closure#0}
//~ MONO_ITEM fn closures::used_binding_type::<u64>::{closure#0}
//~ MONO_ITEM fn closures::used_binding_type::<u32>
//~ MONO_ITEM fn closures::used_binding_type::<u64>
// Function and closure uses type parameter in argument.
pub fn used_argument<T>(t: T) -> u32 {
let x = |_: T| 3;
x(t)
}
//~ MONO_ITEM fn closures::used_argument::<u32>::{closure#0}
//~ MONO_ITEM fn closures::used_argument::<u64>::{closure#0}
//~ MONO_ITEM fn closures::used_argument::<u32>
//~ MONO_ITEM fn closures::used_argument::<u64>
// Closure uses type parameter in argument.
pub fn used_argument_closure<T: Default>() -> u32 {
let t: T = Default::default();
let x = |_: T| 3;
x(t)
}
//~ MONO_ITEM fn closures::used_argument_closure::<u32>::{closure#0}
//~ MONO_ITEM fn closures::used_argument_closure::<u64>::{closure#0}
//~ MONO_ITEM fn closures::used_argument_closure::<u32>
//~ MONO_ITEM fn closures::used_argument_closure::<u64>
// Closure uses type parameter as upvar.
pub fn used_upvar<T: Default>() -> T {
let x: T = Default::default();
let y = || x;
y()
}
//~ MONO_ITEM fn closures::used_upvar::<u32>::{closure#0}
//~ MONO_ITEM fn closures::used_upvar::<u64>::{closure#0}
//~ MONO_ITEM fn closures::used_upvar::<u32>
//~ MONO_ITEM fn closures::used_upvar::<u64>
// Closure uses type parameter in substitutions to another function.
pub fn used_substs<T>() {
let x = || super::functions::unused::<T>();
x()
}
//~ MONO_ITEM fn closures::used_substs::<u32>::{closure#0}
//~ MONO_ITEM fn closures::used_substs::<u64>::{closure#0}
//~ MONO_ITEM fn closures::used_substs::<u32>
//~ MONO_ITEM fn closures::used_substs::<u64>
}
mod methods {
pub struct Foo<F>(F);
impl<F: Default> Foo<F> {
// Function has an unused type parameter from impl.
pub fn unused_impl() {}
//~ MONO_ITEM fn methods::Foo::<F>::unused_impl
// Function has an unused type parameter from impl and fn.
pub fn unused_both<G: Default>() {}
//~ MONO_ITEM fn methods::Foo::<F>::unused_both::<G>
// Function uses type parameter from impl.
pub fn used_impl() {
let _: F = Default::default();
}
//~ MONO_ITEM fn methods::Foo::<u32>::used_impl
//~ MONO_ITEM fn methods::Foo::<u64>::used_impl
// Function uses type parameter from impl.
pub fn used_fn<G: Default>() {
let _: G = Default::default();
}
//~ MONO_ITEM fn methods::Foo::<F>::used_fn::<u32>
//~ MONO_ITEM fn methods::Foo::<F>::used_fn::<u64>
// Function uses type parameter from impl.
pub fn used_both<G: Default>() {
let _: F = Default::default();
let _: G = Default::default();
}
//~ MONO_ITEM fn methods::Foo::<u32>::used_both::<u32>
//~ MONO_ITEM fn methods::Foo::<u64>::used_both::<u64>
// Function uses type parameter in substitutions to another function.
pub fn used_substs() {
super::functions::unused::<F>()
}
//~ MONO_ITEM fn methods::Foo::<u32>::used_substs
//~ MONO_ITEM fn methods::Foo::<u64>::used_substs
// Function has an unused type parameter from impl and fn.
pub fn closure_unused_all<G: Default>() -> u32 {
let add_one = |x: u32| x + 1;
add_one(3)
}
//~ MONO_ITEM fn methods::Foo::<F>::closure_unused_all::<G>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<F>::closure_unused_all::<G>
// Function uses type parameter from impl and fn in closure.
pub fn closure_used_both<G: Default>() -> u32 {
let add_one = |x: u32| {
let _: F = Default::default();
let _: G = Default::default();
x + 1
};
add_one(3)
}
//~ MONO_ITEM fn methods::Foo::<u32>::closure_used_both::<u32>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<u64>::closure_used_both::<u64>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<u32>::closure_used_both::<u32>
//~ MONO_ITEM fn methods::Foo::<u64>::closure_used_both::<u64>
// Function uses type parameter from fn in closure.
pub fn closure_used_fn<G: Default>() -> u32 {
let add_one = |x: u32| {
let _: G = Default::default();
x + 1
};
add_one(3)
}
//~ MONO_ITEM fn methods::Foo::<F>::closure_used_fn::<u32>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<F>::closure_used_fn::<u64>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<F>::closure_used_fn::<u32>
//~ MONO_ITEM fn methods::Foo::<F>::closure_used_fn::<u64>
// Function uses type parameter from impl in closure.
pub fn closure_used_impl<G: Default>() -> u32 {
let add_one = |x: u32| {
let _: F = Default::default();
x + 1
};
add_one(3)
}
//~ MONO_ITEM fn methods::Foo::<u32>::closure_used_impl::<G>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<u64>::closure_used_impl::<G>::{closure#0}
//~ MONO_ITEM fn methods::Foo::<u32>::closure_used_impl::<G>
//~ MONO_ITEM fn methods::Foo::<u64>::closure_used_impl::<G>
// Closure uses type parameter in substitutions to another function.
pub fn closure_used_substs() {
let x = || super::functions::unused::<F>();
x()
}
//~ MONO_ITEM fn methods::Foo::<u32>::closure_used_substs::{closure#0}
//~ MONO_ITEM fn methods::Foo::<u64>::closure_used_substs::{closure#0}
//~ MONO_ITEM fn methods::Foo::<u32>::closure_used_substs
//~ MONO_ITEM fn methods::Foo::<u64>::closure_used_substs
}
}
fn dispatch<T: Default>() {
functions::no_parameters();
functions::unused::<T>();
functions::used_binding_value::<T>();
functions::used_binding_type::<T>();
functions::used_argument::<T>(Default::default());
functions::used_substs::<T>();
closures::no_parameters();
let _ = closures::unused::<T>();
let _ = closures::used_parent::<T>();
let _ = closures::used_binding_value::<T>();
let _ = closures::used_binding_type::<T>();
let _ = closures::used_argument::<T>(Default::default());
let _ = closures::used_argument_closure::<T>();
let _ = closures::used_upvar::<T>();
let _ = closures::used_substs::<T>();
methods::Foo::<T>::unused_impl();
methods::Foo::<T>::unused_both::<T>();
methods::Foo::<T>::used_impl();
methods::Foo::<T>::used_fn::<T>();
methods::Foo::<T>::used_both::<T>();
methods::Foo::<T>::used_substs();
let _ = methods::Foo::<T>::closure_unused_all::<T>();
let _ = methods::Foo::<T>::closure_used_both::<T>();
let _ = methods::Foo::<T>::closure_used_impl::<T>();
let _ = methods::Foo::<T>::closure_used_fn::<T>();
let _ = methods::Foo::<T>::closure_used_substs();
}
//~ MONO_ITEM fn dispatch::<u32>
//~ MONO_ITEM fn dispatch::<u64>
pub fn foo() {
// Generate two copies of each function to check that where the type parameter is unused,
// there is only a single copy.
dispatch::<u32>();
dispatch::<u64>();
}
//~ MONO_ITEM fn foo @@ unused_type_parameters-cgu.0[External]
// These are all the items that aren't relevant to the test.
//~ MONO_ITEM fn <u32 as std::default::Default>::default
//~ MONO_ITEM fn <u64 as std::default::Default>::default

View File

@ -1,16 +0,0 @@
//@ known-bug: #105249
//@ compile-flags: -Zpolymorphize=on
trait Foo<T> {
fn print<'a>(&'a self) where T: 'a { println!("foo"); }
}
impl<'a> Foo<&'a ()> for () { }
trait Bar: for<'a> Foo<&'a ()> { }
impl Bar for () {}
fn main() {
(&() as &dyn Bar).print(); // Segfault
}

View File

@ -1,24 +0,0 @@
//@ known-bug: #123893
//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes -Zinline-mir-threshold=20
pub fn main() {
generic_impl::<bool>();
}
fn generic_impl<T>() {
trait MagicTrait {
const IS_BIG: bool;
}
impl<T> MagicTrait for T {
const IS_BIG: bool = true;
}
more_cost();
if T::IS_BIG {
big_impl::<i32>();
}
}
#[inline(never)]
fn big_impl<T>() {}
#[inline(never)]
fn more_cost() {}

View File

@ -1,33 +0,0 @@
//@ known-bug: #124020
//@ compile-flags: -Zpolymorphize=on --edition=2018 --crate-type=lib
#![feature(async_closure, async_trait_bounds)]
use std::future::Future;
use std::pin::pin;
use std::task::*;
pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
let mut fut = pin!(fut);
let ctx = &mut Context::from_waker(Waker::noop());
loop {
match fut.as_mut().poll(ctx) {
Poll::Pending => {}
Poll::Ready(t) => break t,
}
}
}
async fn call_once(f: impl AsyncFnOnce(DropMe)) {
f(DropMe("world")).await;
}
struct DropMe(&'static str);
pub fn future() {
block_on(async {
let async_closure = async move |a: DropMe| {};
call_once(async_closure).await;
});
}

View File

@ -1,7 +0,0 @@
//@ known-bug: rust-lang/rust#124436
//@ compile-flags: -Zdump-mir=all -Zpolymorphize=on
pub trait TraitCat {}
pub trait TraitDog {}
pub fn gamma<T: TraitCat + TraitDog>(t: [TraitDog; 32]) {}

View File

@ -1,13 +0,0 @@
//@ known-bug: #130425
//@ compile-flags: -Zmir-opt-level=5 -Zpolymorphize=on
struct S<T>(T)
where
[T; (
|_: u8| {
static FOO: Sync = AtomicUsize::new(0);
unsafe { &*(&FOO as *const _ as *const usize) }
},
1,
)
.1]: Copy;

View File

@ -1,21 +0,0 @@
#![feature(generic_const_exprs)]
use std::str::FromStr;
pub struct If<const CONDITION: bool>;
pub trait True {}
impl True for If<true> {}
pub struct FixedI32<const FRAC: u32>;
impl<const FRAC: u32> FromStr for FixedI32<FRAC>
where
If<{ FRAC <= 32 }>: True,
{
type Err = ();
fn from_str(_s: &str) -> Result<Self, Self::Err> {
unimplemented!()
}
}

View File

@ -1,10 +0,0 @@
//@ aux-build:issue-94287-aux.rs
//@ build-fail
extern crate issue_94287_aux;
use std::str::FromStr;
fn main() {
let _ = <issue_94287_aux::FixedI32<16>>::from_str("");
}

View File

@ -1,15 +0,0 @@
error: failed to evaluate generic const expression
--> $DIR/auxiliary/issue-94287-aux.rs:15:8
|
LL | If<{ FRAC <= 32 }>: True,
| ^^^^^^^^^^^^^^
|
= note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
help: consider enabling this feature
--> $DIR/issue-94287.rs:1:1
|
LL + #![feature(generic_const_exprs)]
|
error: aborting due to 1 previous error

View File

@ -1,18 +0,0 @@
//@ compile-flags: -Zpolymorphize=on
//@ build-pass
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine;
use std::pin::Pin;
use std::thread;
fn main() {
let mut foo = #[coroutine]
|| yield;
thread::spawn(move || match Pin::new(&mut foo).resume(()) {
s => panic!("bad state: {:?}", s),
})
.join()
.unwrap();
}

View File

@ -1,4 +1,4 @@
//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes -Zmir-opt-level=0
//@ compile-flags: -Zinline-mir=yes -Zmir-opt-level=0 -Zvalidate-mir
#![feature(fn_traits, unboxed_closures)]
struct Foo<T>(T);

View File

@ -1,20 +0,0 @@
//! This test used to ICE: #123917
//! The reason was that while the AST knows about two fields
//! named `ptr`, only one exists at the layout level, so accessing
//! `_extra_field` would use an oob index
//@ compile-flags: -Zmir-opt-level=5 -Zpolymorphize=on
struct NonNull<T>(*mut T);
struct Token<T> {
ptr: *mut T,
ptr: NonNull<T>,
//~^ ERROR: `ptr` is already declared
_extra_field: (),
}
fn tokenize<T>(item: *mut T) -> Token<T> {
Token { ptr: NonNull(item), _extra_field: () }
}
fn main() {}

View File

@ -1,11 +0,0 @@
error[E0124]: field `ptr` is already declared
--> $DIR/abi_mismatch.rs:11:5
|
LL | ptr: *mut T,
| ----------- `ptr` first declared here
LL | ptr: NonNull<T>,
| ^^^^^^^^^^^^^^^ field already declared
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0124`.

View File

@ -1,29 +0,0 @@
//@ build-pass
//@ compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
fn foo(f: impl Fn()) {
let x = |_: ()| ();
// Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
// `x` that will differ for each instantiation despite polymorphisation of the varying
// argument.
let y = || x(());
// Consider `f` used in `foo`.
f();
// Use `y` so that it is visited in monomorphisation collection.
y();
}
fn entry_a() {
foo(|| ());
}
fn entry_b() {
foo(|| ());
}
fn main() {
entry_a();
entry_b();
}

View File

@ -1,34 +0,0 @@
//@ build-pass
//@ compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
fn foo(f: impl Fn()) {
// Mutate an upvar from `x` so that it implements `FnMut`.
let mut outer = 3;
let mut x = |_: ()| {
outer = 4;
()
};
// Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
// `x` that will differ for each instantiation despite polymorphisation of the varying
// argument.
let mut y = || x(());
// Consider `f` used in `foo`.
f();
// Use `y` so that it is visited in monomorphisation collection.
y();
}
fn entry_a() {
foo(|| ());
}
fn entry_b() {
foo(|| ());
}
fn main() {
entry_a();
entry_b();
}

View File

@ -1,34 +0,0 @@
//@ build-pass
//@ compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
fn foo(f: impl Fn()) {
// Move a non-copy type into `x` so that it implements `FnOnce`.
let outer = Vec::<u32>::new();
let x = move |_: ()| {
let inner = outer;
()
};
// Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
// `x` that will differ for each instantiation despite polymorphisation of the varying
// argument.
let y = || x(());
// Consider `f` used in `foo`.
f();
// Use `y` so that it is visited in monomorphisation collection.
y();
}
fn entry_a() {
foo(|| ());
}
fn entry_b() {
foo(|| ());
}
fn main() {
entry_a();
entry_b();
}

View File

@ -1,38 +0,0 @@
//@ build-pass
//@ compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
fn y_uses_f(f: impl Fn()) {
let x = |_: ()| ();
let y = || {
f();
x(());
};
f();
y();
}
fn x_uses_f(f: impl Fn()) {
let x = |_: ()| { f(); };
let y = || x(());
f();
y();
}
fn entry_a() {
x_uses_f(|| ());
y_uses_f(|| ());
}
fn entry_b() {
x_uses_f(|| ());
y_uses_f(|| ());
}
fn main() {
entry_a();
entry_b();
}

View File

@ -1,67 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![feature(generic_const_exprs, rustc_attrs)]
//~^ WARN the feature `generic_const_exprs` is incomplete
// This test checks that the polymorphization analysis correctly detects unused const
// parameters in closures.
// Function doesn't have any generic parameters to be unused.
#[rustc_polymorphize_error]
pub fn no_parameters() {
let _ = || {};
}
// Function has an unused generic parameter in parent and closure.
#[rustc_polymorphize_error]
pub fn unused<const T: usize>() -> usize {
//~^ ERROR item has unused generic parameters
let add_one = |x: usize| x + 1;
//~^ ERROR item has unused generic parameters
add_one(3)
}
// Function has an unused generic parameter in closure, but not in parent.
#[rustc_polymorphize_error]
pub fn used_parent<const T: usize>() -> usize {
let x: usize = T;
let add_one = |x: usize| x + 1;
//~^ ERROR item has unused generic parameters
x + add_one(3)
}
// Function uses generic parameter in value of a binding in closure.
#[rustc_polymorphize_error]
pub fn used_binding<const T: usize>() -> usize {
let x = || {
let y: usize = T;
y
};
x()
}
// Closure uses a value as an upvar, which used the generic parameter.
#[rustc_polymorphize_error]
pub fn unused_upvar<const T: usize>() -> usize {
let x: usize = T;
let y = || x;
//~^ ERROR item has unused generic parameters
y()
}
// Closure uses generic parameter in substitutions to another function.
#[rustc_polymorphize_error]
pub fn used_substs<const T: usize>() -> usize {
let x = || unused::<T>();
x()
}
fn main() {
no_parameters();
let _ = unused::<1>();
let _ = used_parent::<1>();
let _ = used_binding::<1>();
let _ = unused_upvar::<1>();
let _ = used_substs::<1>();
}

View File

@ -1,44 +0,0 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/closures.rs:3:12
|
LL | #![feature(generic_const_exprs, rustc_attrs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default
error: item has unused generic parameters
--> $DIR/closures.rs:19:19
|
LL | pub fn unused<const T: usize>() -> usize {
| -------------- generic parameter `T` is unused
LL |
LL | let add_one = |x: usize| x + 1;
| ^^^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:17:8
|
LL | pub fn unused<const T: usize>() -> usize {
| ^^^^^^ -------------- generic parameter `T` is unused
error: item has unused generic parameters
--> $DIR/closures.rs:28:19
|
LL | pub fn used_parent<const T: usize>() -> usize {
| -------------- generic parameter `T` is unused
LL | let x: usize = T;
LL | let add_one = |x: usize| x + 1;
| ^^^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:48:13
|
LL | pub fn unused_upvar<const T: usize>() -> usize {
| -------------- generic parameter `T` is unused
LL | let x: usize = T;
LL | let y = || x;
| ^^
error: aborting due to 4 previous errors; 1 warning emitted

View File

@ -1,37 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![feature(generic_const_exprs, rustc_attrs)]
//~^ WARN the feature `generic_const_exprs` is incomplete
// This test checks that the polymorphization analysis correctly detects unused const
// parameters in functions.
// Function doesn't have any generic parameters to be unused.
#[rustc_polymorphize_error]
pub fn no_parameters() {}
// Function has an unused generic parameter.
#[rustc_polymorphize_error]
pub fn unused<const T: usize>() {
//~^ ERROR item has unused generic parameters
}
// Function uses generic parameter in value of a binding.
#[rustc_polymorphize_error]
pub fn used_binding<const T: usize>() -> usize {
let x: usize = T;
x
}
// Function uses generic parameter in substitutions to another function.
#[rustc_polymorphize_error]
pub fn used_substs<const T: usize>() {
unused::<T>()
}
fn main() {
no_parameters();
unused::<1>();
used_binding::<1>();
used_substs::<1>();
}

View File

@ -1,17 +0,0 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/functions.rs:3:12
|
LL | #![feature(generic_const_exprs, rustc_attrs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default
error: item has unused generic parameters
--> $DIR/functions.rs:15:8
|
LL | pub fn unused<const T: usize>() {
| ^^^^^^ -------------- generic parameter `T` is unused
error: aborting due to 1 previous error; 1 warning emitted

View File

@ -1,98 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on -Zinline-mir=off
#![feature(generic_const_exprs, coroutines, coroutine_trait, rustc_attrs)]
//~^ WARN the feature `generic_const_exprs` is incomplete
use std::marker::Unpin;
use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;
enum YieldOrReturn<Y, R> {
Yield(Y),
Return(R),
}
fn finish<T, Y, R>(mut t: T) -> Vec<YieldOrReturn<Y, R>>
where
T: Coroutine<(), Yield = Y, Return = R> + Unpin,
{
let mut results = Vec::new();
loop {
match Pin::new(&mut t).resume(()) {
CoroutineState::Yielded(yielded) => results.push(YieldOrReturn::Yield(yielded)),
CoroutineState::Complete(returned) => {
results.push(YieldOrReturn::Return(returned));
return results;
}
}
}
}
// This test checks that the polymorphization analysis functions on coroutines.
#[rustc_polymorphize_error]
pub fn unused_type<T>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin {
#[coroutine]
|| {
//~^ ERROR item has unused generic parameters
yield 1;
2
}
}
#[rustc_polymorphize_error]
pub fn used_type_in_yield<Y: Default>() -> impl Coroutine<(), Yield = Y, Return = u32> + Unpin {
#[coroutine]
|| {
yield Y::default();
2
}
}
#[rustc_polymorphize_error]
pub fn used_type_in_return<R: Default>() -> impl Coroutine<(), Yield = u32, Return = R> + Unpin {
#[coroutine]
|| {
yield 3;
R::default()
}
}
#[rustc_polymorphize_error]
pub fn unused_const<const T: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin {
#[coroutine]
|| {
//~^ ERROR item has unused generic parameters
yield 1;
2
}
}
#[rustc_polymorphize_error]
pub fn used_const_in_yield<const Y: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin
{
#[coroutine]
|| {
yield Y;
2
}
}
#[rustc_polymorphize_error]
pub fn used_const_in_return<const R: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin
{
#[coroutine]
|| {
yield 4;
R
}
}
fn main() {
finish(unused_type::<u32>());
finish(used_type_in_yield::<u32>());
finish(used_type_in_return::<u32>());
finish(unused_const::<1u32>());
finish(used_const_in_yield::<1u32>());
finish(used_const_in_return::<1u32>());
}

View File

@ -1,29 +0,0 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/coroutine.rs:3:12
|
LL | #![feature(generic_const_exprs, coroutines, coroutine_trait, rustc_attrs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default
error: item has unused generic parameters
--> $DIR/coroutine.rs:36:5
|
LL | pub fn unused_type<T>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin {
| - generic parameter `T` is unused
LL | #[coroutine]
LL | || {
| ^^
error: item has unused generic parameters
--> $DIR/coroutine.rs:64:5
|
LL | pub fn unused_const<const T: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin {
| ------------ generic parameter `T` is unused
LL | #[coroutine]
LL | || {
| ^^
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -1,22 +0,0 @@
//@ check-pass
//@ compile-flags:-Zpolymorphize=on
pub struct OnDrop<F: Fn()>(pub F);
impl<F: Fn()> Drop for OnDrop<F> {
fn drop(&mut self) { }
}
fn foo<R, S: FnOnce()>(
_: R,
_: S,
) {
let bar = || {
let _ = OnDrop(|| ());
};
bar();
}
fn main() {
foo(3u32, || {});
}

View File

@ -1,27 +0,0 @@
//@ check-pass
//@ compile-flags:-Zpolymorphize=on
pub struct OnDrop<F: Fn()>(pub F);
impl<F: Fn()> Drop for OnDrop<F> {
fn drop(&mut self) { }
}
fn bar<F: FnOnce()>(f: F) {
let _ = OnDrop(|| ());
f()
}
fn foo<R, S: FnOnce()>(
_: R,
_: S,
) {
let bar = || {
bar(|| {})
};
bar();
}
fn main() {
foo(3u32, || {});
}

View File

@ -1,20 +0,0 @@
// issue: rust-lang/rust#90192
// ICE assertion failed: matches!(ty.kind(), ty :: Param(_))
//@ compile-flags:-Zpolymorphize=on -Zmir-opt-level=3
//@ build-pass
fn test<T>() {
std::mem::size_of::<T>();
}
pub fn foo<T>(_: T) -> &'static fn() {
&(test::<T> as fn())
}
fn outer<T>() {
foo(|| ());
}
fn main() {
outer::<u8>();
}

View File

@ -1,27 +0,0 @@
// This test demonstrates an ICE that may occur when we try to resolve the instance
// of a impl that has different generics than the trait it's implementing. This ensures
// we first check that the args are compatible before resolving the body, just like
// we do in projection before substituting a GAT.
//
// When polymorphization is enabled, we check the optimized MIR for unused parameters.
// This will invoke the inliner, leading to this ICE.
//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes
trait Trait {
fn foo<'a, K: 'a>(self, _: K);
}
impl Trait for () {
#[inline]
fn foo<K>(self, _: K) {
//~^ ERROR lifetime parameters or bounds on method `foo` do not match the trait declaration
todo!();
}
}
pub fn qux<T>() {
().foo(());
}
fn main() {}

View File

@ -1,15 +0,0 @@
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
--> $DIR/inline-incorrect-early-bound.rs:17:11
|
LL | fn foo<'a, K: 'a>(self, _: K);
| -----------
| | |
| | this bound might be missing in the impl
| lifetimes in impl do not match this method in trait
...
LL | fn foo<K>(self, _: K) {
| ^^^ lifetimes do not match method in trait
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0195`.

View File

@ -1,21 +0,0 @@
//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
#![feature(unboxed_closures)]
use std::sync::Arc;
pub struct WeakOnce<T>();
//~^ ERROR type parameter `T` is never used
impl<T> WeakOnce<T> {
extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
//~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
//~| ERROR mismatched types
pub fn get(&self) -> Arc<T> {
self.try_get()
.unwrap_or_else(|| panic!("Singleton {} not available", std::any::type_name::<T>()))
}
}
fn main() {}

View File

@ -1,30 +0,0 @@
error[E0392]: type parameter `T` is never used
--> $DIR/inline-tainted-body.rs:7:21
|
LL | pub struct WeakOnce<T>();
| ^ unused type parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
error: functions with the "rust-call" ABI must take a single non-self tuple argument
--> $DIR/inline-tainted-body.rs:11:35
|
LL | extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
| ^^^^^
error[E0308]: mismatched types
--> $DIR/inline-tainted-body.rs:11:45
|
LL | extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
| ------- ^^^^^^^^^^^^^^ expected `Option<Arc<T>>`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
|
= note: expected enum `Option<Arc<T>>`
found unit type `()`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0392.
For more information about an error, try `rustc --explain E0308`.

View File

@ -1,18 +0,0 @@
//@ compile-flags:-Zpolymorphize=on
//@ build-pass
fn test<T>() {
std::mem::size_of::<T>();
}
pub fn foo<T>(_: T) -> &'static fn() {
&(test::<T> as fn())
}
fn outer<T>() {
foo(|| ());
}
fn main() {
outer::<u8>();
}

View File

@ -1,16 +0,0 @@
//@ compile-flags:-Zpolymorphize=on
//@ build-pass
use std::any::TypeId;
pub fn foo<T: 'static>(_: T) -> TypeId {
TypeId::of::<T>()
}
fn outer<T: 'static>() {
foo(|| ());
}
fn main() {
outer::<u8>();
}

View File

@ -1,25 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![feature(rustc_attrs)]
// This test checks that the polymorphization analysis doesn't break when the
// function/closure doesn't just have generic parameters.
// Function has an unused generic parameter.
#[rustc_polymorphize_error]
pub fn unused<'a, T>(_: &'a u32) {
//~^ ERROR item has unused generic parameters
}
#[rustc_polymorphize_error]
pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
let _: T = Default::default();
let add_one = |x: u32| x + 1;
//~^ ERROR item has unused generic parameters
add_one(3)
}
fn main() {
unused::<u32>(&3);
used::<u32>(&3);
}

View File

@ -1,17 +0,0 @@
error: item has unused generic parameters
--> $DIR/lifetimes.rs:10:8
|
LL | pub fn unused<'a, T>(_: &'a u32) {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
--> $DIR/lifetimes.rs:17:19
|
LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
| - generic parameter `T` is unused
LL | let _: T = Default::default();
LL | let add_one = |x: u32| x + 1;
| ^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -1,26 +0,0 @@
//@ build-pass
//@ compile-flags:-Zpolymorphize=on
pub trait ParallelIterator: Sized {
fn drive<C: Consumer<()>>(_: C) {
C::into_folder();
}
}
pub trait Consumer<T>: Sized {
type Result;
fn into_folder() -> Self::Result;
}
impl ParallelIterator for () {}
impl<F: Fn(), T> Consumer<T> for F {
type Result = ();
fn into_folder() -> Self::Result {
unimplemented!()
}
}
fn main() {
<()>::drive(|| ());
}

View File

@ -1,95 +0,0 @@
//@ build-fail
//@ compile-flags: -Copt-level=0 -Zpolymorphize=on
#![feature(rustc_attrs)]
// This test checks that `T` is considered used in `foo`, because it is used in a predicate for
// `I`, which is used.
#[rustc_polymorphize_error]
fn bar<I>() {
//~^ ERROR item has unused generic parameters
}
#[rustc_polymorphize_error]
fn foo<I, T>(_: I)
//~^ ERROR item has unused generic parameters
where
I: Iterator<Item = T>,
{
bar::<I>()
}
#[rustc_polymorphize_error]
fn baz<I, T>(_: I)
//~^ ERROR item has unused generic parameters
where
std::iter::Repeat<I>: Iterator<Item = T>,
{
bar::<I>()
}
// In addition, check that `I` is considered used in `next::{{closure}}`, because `T` is used and
// `T` is really just `I::Item`. `E` is used due to the fixed-point marking of predicates.
pub(crate) struct Foo<'a, I, E>(I, &'a E);
impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
where
I: Iterator<Item = &'a (T, E)>,
{
type Item = T;
#[rustc_polymorphize_error]
fn next(&mut self) -> Option<Self::Item> {
self.find(|_| true)
//~^ ERROR item has unused generic parameters
}
}
// Furthermore, check that `B` is considered used because `C` is used, and that `A` is considered
// used because `B` is now used.
trait Baz<Z> {}
impl Baz<u16> for u8 {}
impl Baz<u32> for u16 {}
#[rustc_polymorphize_error]
fn quux<A, B, C: Default>() -> usize
//~^ ERROR item has unused generic parameters
where
A: Baz<B>,
B: Baz<C>,
{
std::mem::size_of::<C>()
}
// Finally, check that `F` is considered used because `G` is used when neither are in the self-ty
// of the predicate.
trait Foobar<F, G> {}
impl Foobar<u32, u32> for () {}
#[rustc_polymorphize_error]
fn foobar<F, G>() -> usize
//~^ ERROR item has unused generic parameters
where
(): Foobar<F, G>,
{
std::mem::size_of::<G>()
}
fn main() {
let x = &[2u32];
foo(x.iter());
baz(x.iter());
let mut a = Foo([(1u32, 1u16)].iter(), &1u16);
let _ = a.next();
let _ = quux::<u8, u16, u32>();
let _ = foobar::<u32, u32>();
}

View File

@ -1,45 +0,0 @@
error: item has unused generic parameters
--> $DIR/predicates.rs:10:4
|
LL | fn bar<I>() {
| ^^^ - generic parameter `I` is unused
error: item has unused generic parameters
--> $DIR/predicates.rs:15:4
|
LL | fn foo<I, T>(_: I)
| ^^^ - generic parameter `T` is unused
error: item has unused generic parameters
--> $DIR/predicates.rs:24:4
|
LL | fn baz<I, T>(_: I)
| ^^^ - generic parameter `T` is unused
error: item has unused generic parameters
--> $DIR/predicates.rs:45:19
|
LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
| - - generic parameter `E` is unused
| |
| generic parameter `I` is unused
...
LL | self.find(|_| true)
| ^^^
error: item has unused generic parameters
--> $DIR/predicates.rs:59:4
|
LL | fn quux<A, B, C: Default>() -> usize
| ^^^^ - - generic parameter `B` is unused
| |
| generic parameter `A` is unused
error: item has unused generic parameters
--> $DIR/predicates.rs:76:4
|
LL | fn foobar<F, G>() -> usize
| ^^^^^^ - generic parameter `F` is unused
error: aborting due to 6 previous errors

View File

@ -1,12 +0,0 @@
//@ build-fail
//@ compile-flags: -Zpolymorphize=on
#![crate_type = "lib"]
#![feature(rustc_attrs)]
fn foo<'a>(_: &'a ()) {}
#[rustc_polymorphize_error]
pub fn test<T>() {
//~^ ERROR item has unused generic parameters
foo(&());
}

View File

@ -1,8 +0,0 @@
error: item has unused generic parameters
--> $DIR/promoted-function-1.rs:9:8
|
LL | pub fn test<T>() {
| ^^^^ - generic parameter `T` is unused
error: aborting due to 1 previous error

View File

@ -1,16 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![crate_type = "lib"]
#![feature(generic_const_exprs, rustc_attrs)]
//~^ WARN the feature `generic_const_exprs` is incomplete
#[rustc_polymorphize_error]
fn test<T>() {
//~^ ERROR item has unused generic parameters
let x = [0; 3 + 4];
}
pub fn caller() {
test::<String>();
test::<Vec<String>>();
}

View File

@ -1,17 +0,0 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/promoted-function-2.rs:4:12
|
LL | #![feature(generic_const_exprs, rustc_attrs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default
error: item has unused generic parameters
--> $DIR/promoted-function-2.rs:8:4
|
LL | fn test<T>() {
| ^^^^ - generic parameter `T` is unused
error: aborting due to 1 previous error; 1 warning emitted

View File

@ -1,14 +0,0 @@
//@ run-pass
//@ compile-flags: -Zpolymorphize=on -Zmir-opt-level=4
fn caller<T, U>() -> &'static usize {
callee::<U>()
}
fn callee<T>() -> &'static usize {
&std::mem::size_of::<T>()
}
fn main() {
assert_eq!(caller::<(), ()>(), &0);
}

View File

@ -1,15 +0,0 @@
//@ run-pass
//@ compile-flags:-Zpolymorphize=on
fn fop<T>() {}
fn bar<T>() -> &'static fn() {
&(fop::<T> as fn())
}
pub const FN: &'static fn() = &(fop::<i32> as fn());
fn main() {
bar::<u32>();
bar::<i32>();
(FN)();
}

View File

@ -1,22 +0,0 @@
//@ build-pass
//@ compile-flags: -Zpolymorphize=on -Csymbol-mangling-version=v0
pub(crate) struct Foo<'a, I, E>(I, &'a E);
impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
where
I: Iterator<Item = &'a (T, E)>,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.find(|_| true)
}
}
fn main() {
let mut a = Foo([(1u32, 1u16)].iter(), &1u16);
let mut b = Foo([(1u16, 1u32)].iter(), &1u32);
let _ = a.next();
let _ = b.next();
}

View File

@ -1,85 +0,0 @@
//@ build-pass
#![feature(rustc_attrs)]
// This test checks that the analysis doesn't panic when there are >64 generic parameters, but
// instead considers those parameters used.
#[rustc_polymorphize_error]
fn bar<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA,
AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW,
AX, AY, AZ, BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM>()
{
let _: Option<A> = None;
let _: Option<B> = None;
let _: Option<C> = None;
let _: Option<D> = None;
let _: Option<E> = None;
let _: Option<F> = None;
let _: Option<G> = None;
let _: Option<H> = None;
let _: Option<I> = None;
let _: Option<J> = None;
let _: Option<K> = None;
let _: Option<L> = None;
let _: Option<M> = None;
let _: Option<N> = None;
let _: Option<O> = None;
let _: Option<P> = None;
let _: Option<Q> = None;
let _: Option<R> = None;
let _: Option<S> = None;
let _: Option<T> = None;
let _: Option<U> = None;
let _: Option<V> = None;
let _: Option<W> = None;
let _: Option<X> = None;
let _: Option<Y> = None;
let _: Option<Z> = None;
let _: Option<AA> = None;
let _: Option<AB> = None;
let _: Option<AC> = None;
let _: Option<AD> = None;
let _: Option<AE> = None;
let _: Option<AF> = None;
let _: Option<AG> = None;
let _: Option<AH> = None;
let _: Option<AI> = None;
let _: Option<AJ> = None;
let _: Option<AK> = None;
let _: Option<AL> = None;
let _: Option<AM> = None;
let _: Option<AN> = None;
let _: Option<AO> = None;
let _: Option<AP> = None;
let _: Option<AQ> = None;
let _: Option<AR> = None;
let _: Option<AS> = None;
let _: Option<AT> = None;
let _: Option<AU> = None;
let _: Option<AV> = None;
let _: Option<AW> = None;
let _: Option<AX> = None;
let _: Option<AY> = None;
let _: Option<AZ> = None;
let _: Option<BA> = None;
let _: Option<BB> = None;
let _: Option<BC> = None;
let _: Option<BD> = None;
let _: Option<BE> = None;
let _: Option<BF> = None;
let _: Option<BG> = None;
let _: Option<BH> = None;
let _: Option<BI> = None;
let _: Option<BJ> = None;
let _: Option<BK> = None;
let _: Option<BL> = None;
let _: Option<BM> = None;
}
fn main() {
bar::<u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
u32>();
}

View File

@ -1,161 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![feature(stmt_expr_attributes, rustc_attrs)]
// This test checks that the polymorphization analysis correctly detects unused type
// parameters in closures.
// Function doesn't have any generic parameters to be unused.
#[rustc_polymorphize_error]
pub fn no_parameters() {
let _ = || {};
}
// Function has an unused generic parameter in parent and closure.
#[rustc_polymorphize_error]
pub fn unused<T>() -> u32 {
//~^ ERROR item has unused generic parameters
let add_one = |x: u32| x + 1;
//~^ ERROR item has unused generic parameters
add_one(3)
}
// Function has an unused generic parameter in closure, but not in parent.
#[rustc_polymorphize_error]
pub fn used_parent<T: Default>() -> u32 {
let _: T = Default::default();
let add_one = |x: u32| x + 1;
//~^ ERROR item has unused generic parameters
add_one(3)
}
// Function uses generic parameter in value of a binding in closure.
#[rustc_polymorphize_error]
pub fn used_binding_value<T: Default>() -> T {
let x = || {
let y: T = Default::default();
y
};
x()
}
// Function uses generic parameter in generic of a binding in closure.
#[rustc_polymorphize_error]
pub fn used_binding_generic<T>() -> Option<T> {
let x = || {
let y: Option<T> = None;
y
};
x()
}
// Function and closure uses generic parameter in argument.
#[rustc_polymorphize_error]
pub fn used_argument<T>(t: T) -> u32 {
let x = |_: T| 3;
x(t)
}
// Closure uses generic parameter in argument.
#[rustc_polymorphize_error]
pub fn used_argument_closure<T: Default>() -> u32 {
let t: T = Default::default();
let x = |_: T| 3;
x(t)
}
// Closure uses generic parameter as upvar.
#[rustc_polymorphize_error]
pub fn used_upvar<T: Default>() -> T {
let x: T = Default::default();
let y = || x;
y()
}
// Closure uses generic parameter in substitutions to another function.
#[rustc_polymorphize_error]
pub fn used_substs<T>() -> u32 {
let x = || unused::<T>();
x()
}
struct Foo<F>(F);
impl<F: Default> Foo<F> {
// Function has an unused generic parameter from impl and fn.
#[rustc_polymorphize_error]
pub fn unused_all<G: Default>() -> u32 {
//~^ ERROR item has unused generic parameters
let add_one = |x: u32| x + 1;
//~^ ERROR item has unused generic parameters
add_one(3)
}
// Function uses generic parameter from impl and fn in closure.
#[rustc_polymorphize_error]
pub fn used_both<G: Default>() -> u32 {
let add_one = |x: u32| {
let _: F = Default::default();
let _: G = Default::default();
x + 1
};
add_one(3)
}
// Function uses generic parameter from fn in closure.
#[rustc_polymorphize_error]
pub fn used_fn<G: Default>() -> u32 {
//~^ ERROR item has unused generic parameters
let add_one = |x: u32| {
//~^ ERROR item has unused generic parameters
let _: G = Default::default();
x + 1
};
add_one(3)
}
// Function uses generic parameter from impl in closure.
#[rustc_polymorphize_error]
pub fn used_impl<G: Default>() -> u32 {
//~^ ERROR item has unused generic parameters
let add_one = |x: u32| {
//~^ ERROR item has unused generic parameters
let _: F = Default::default();
x + 1
};
add_one(3)
}
// Closure uses generic parameter in substitutions to another function.
#[rustc_polymorphize_error]
pub fn used_substs() -> u32 {
let x = || unused::<F>();
x()
}
}
fn main() {
no_parameters();
let _ = unused::<u32>();
let _ = used_parent::<u32>();
let _ = used_binding_value::<u32>();
let _ = used_binding_generic::<u32>();
let _ = used_argument(3u32);
let _ = used_argument_closure::<u32>();
let _ = used_upvar::<u32>();
let _ = used_substs::<u32>();
let _ = Foo::<u32>::unused_all::<u32>();
let _ = Foo::<u32>::used_both::<u32>();
let _ = Foo::<u32>::used_impl::<u32>();
let _ = Foo::<u32>::used_fn::<u32>();
let _ = Foo::<u32>::used_substs();
}

View File

@ -1,80 +0,0 @@
error: item has unused generic parameters
--> $DIR/closures.rs:19:19
|
LL | pub fn unused<T>() -> u32 {
| - generic parameter `T` is unused
...
LL | let add_one = |x: u32| x + 1;
| ^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:16:8
|
LL | pub fn unused<T>() -> u32 {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
--> $DIR/closures.rs:28:19
|
LL | pub fn used_parent<T: Default>() -> u32 {
| - generic parameter `T` is unused
LL | let _: T = Default::default();
LL | let add_one = |x: u32| x + 1;
| ^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:94:23
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | pub fn unused_all<G: Default>() -> u32 {
| - generic parameter `G` is unused
LL |
LL | let add_one = |x: u32| x + 1;
| ^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:92:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | pub fn unused_all<G: Default>() -> u32 {
| ^^^^^^^^^^ - generic parameter `G` is unused
error: item has unused generic parameters
--> $DIR/closures.rs:115:23
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | let add_one = |x: u32| {
| ^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:113:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | pub fn used_fn<G: Default>() -> u32 {
| ^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:128:23
|
LL | pub fn used_impl<G: Default>() -> u32 {
| - generic parameter `G` is unused
LL |
LL | let add_one = |x: u32| {
| ^^^^^^^^
error: item has unused generic parameters
--> $DIR/closures.rs:126:12
|
LL | pub fn used_impl<G: Default>() -> u32 {
| ^^^^^^^^^ - generic parameter `G` is unused
error: aborting due to 9 previous errors

View File

@ -1,96 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![feature(rustc_attrs)]
// This test checks that the polymorphization analysis correctly detects unused type
// parameters in functions.
// Function doesn't have any generic parameters to be unused.
#[rustc_polymorphize_error]
pub fn no_parameters() {}
// Function has an unused generic parameter.
#[rustc_polymorphize_error]
pub fn unused<T>() {
//~^ ERROR item has unused generic parameters
}
// Function uses generic parameter in value of a binding.
#[rustc_polymorphize_error]
pub fn used_binding_value<T: Default>() {
let _: T = Default::default();
}
// Function uses generic parameter in generic of a binding.
#[rustc_polymorphize_error]
pub fn used_binding_generic<T>() {
let _: Option<T> = None;
}
// Function uses generic parameter in argument.
#[rustc_polymorphize_error]
pub fn used_argument<T>(_: T) {}
// Function uses generic parameter in substitutions to another function.
#[rustc_polymorphize_error]
pub fn used_substs<T>() {
unused::<T>()
}
struct Foo<F>(F);
impl<F: Default> Foo<F> {
// Function has an unused generic parameter from impl.
#[rustc_polymorphize_error]
pub fn unused_impl() {
//~^ ERROR item has unused generic parameters
}
// Function has an unused generic parameter from impl and fn.
#[rustc_polymorphize_error]
pub fn unused_both<G: Default>() {
//~^ ERROR item has unused generic parameters
}
// Function uses generic parameter from impl.
#[rustc_polymorphize_error]
pub fn used_impl() {
let _: F = Default::default();
}
// Function uses generic parameter from impl.
#[rustc_polymorphize_error]
pub fn used_fn<G: Default>() {
//~^ ERROR item has unused generic parameters
let _: G = Default::default();
}
// Function uses generic parameter from impl.
#[rustc_polymorphize_error]
pub fn used_both<G: Default>() {
let _: F = Default::default();
let _: G = Default::default();
}
// Function uses generic parameter in substitutions to another function.
#[rustc_polymorphize_error]
pub fn used_substs() {
unused::<F>()
}
}
fn main() {
no_parameters();
unused::<u32>();
used_binding_value::<u32>();
used_binding_generic::<u32>();
used_argument(3u32);
used_substs::<u32>();
Foo::<u32>::unused_impl();
Foo::<u32>::unused_both::<u32>();
Foo::<u32>::used_impl();
Foo::<u32>::used_fn::<u32>();
Foo::<u32>::used_both::<u32>();
Foo::<u32>::used_substs();
}

View File

@ -1,35 +0,0 @@
error: item has unused generic parameters
--> $DIR/functions.rs:14:8
|
LL | pub fn unused<T>() {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
--> $DIR/functions.rs:45:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | pub fn unused_impl() {
| ^^^^^^^^^^^
error: item has unused generic parameters
--> $DIR/functions.rs:51:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | pub fn unused_both<G: Default>() {
| ^^^^^^^^^^^ - generic parameter `G` is unused
error: item has unused generic parameters
--> $DIR/functions.rs:63:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
...
LL | pub fn used_fn<G: Default>() {
| ^^^^^^^
error: aborting due to 4 previous errors

View File

@ -1,30 +0,0 @@
//@ build-fail
//@ compile-flags:-Zpolymorphize=on
#![feature(fn_traits, rustc_attrs, unboxed_closures)]
// This test checks that the polymorphization analysis considers a closure
// as using all generic parameters if it does an unsizing cast.
#[rustc_polymorphize_error]
fn foo<T: Default>() {
let _: T = Default::default();
(|| Box::new(|| {}) as Box<dyn Fn()>)();
//~^ ERROR item has unused generic parameters
//~^^ ERROR item has unused generic parameters
}
#[rustc_polymorphize_error]
fn foo2<T: Default>() {
let _: T = Default::default();
(|| {
//~^ ERROR item has unused generic parameters
let call: extern "rust-call" fn(_, _) = Fn::call;
call(&|| {}, ());
//~^ ERROR item has unused generic parameters
})();
}
fn main() {
foo::<u32>();
foo2::<u32>();
}

View File

@ -1,38 +0,0 @@
error: item has unused generic parameters
--> $DIR/unsized_cast.rs:11:18
|
LL | fn foo<T: Default>() {
| - generic parameter `T` is unused
LL | let _: T = Default::default();
LL | (|| Box::new(|| {}) as Box<dyn Fn()>)();
| ^^
error: item has unused generic parameters
--> $DIR/unsized_cast.rs:11:6
|
LL | fn foo<T: Default>() {
| - generic parameter `T` is unused
LL | let _: T = Default::default();
LL | (|| Box::new(|| {}) as Box<dyn Fn()>)();
| ^^
error: item has unused generic parameters
--> $DIR/unsized_cast.rs:22:15
|
LL | fn foo2<T: Default>() {
| - generic parameter `T` is unused
...
LL | call(&|| {}, ());
| ^^
error: item has unused generic parameters
--> $DIR/unsized_cast.rs:19:6
|
LL | fn foo2<T: Default>() {
| - generic parameter `T` is unused
LL | let _: T = Default::default();
LL | (|| {
| ^^
error: aborting due to 4 previous errors

View File

@ -1,5 +1,5 @@
// `S` is infinitely recursing so it's not possible to generate a finite
// drop impl (ignoring polymorphization).
// drop impl.
//
// Dropck should therefore detect that this is the case and eagerly error.

View File

@ -1,4 +1,4 @@
//@ compile-flags: --emit=link -Zmir-opt-level=2 -Zpolymorphize=on
//@ compile-flags: --emit=link -Zmir-opt-level=2 -Zvalidate-mir
fn foo<T>() {
let a: [i32; 0] = [];