mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #125507 - compiler-errors:type-length-limit, r=lcnr
Re-implement a type-size based limit r? lcnr This PR reintroduces the type length limit added in #37789, which was accidentally made practically useless by the caching changes to `Ty::walk` in #72412, which caused the `walk` function to no longer walk over identical elements. Hitting this length limit is not fatal unless we are in codegen -- so it shouldn't affect passes like the mir inliner which creates potentially very large types (which we observed, for example, when the new trait solver compiles `itertools` in `--release` mode). This also increases the type length limit from `1048576 == 2 ** 20` to `2 ** 24`, which covers all of the code that can be reached with craterbot-check. Individual crates can increase the length limit further if desired. Perf regression is mild and I think we should accept it -- reinstating this limit is important for the new trait solver and to make sure we don't accidentally hit more type-size related regressions in the future. Fixes #125460
This commit is contained in:
commit
c872a1418a
@ -3733,7 +3733,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||||||
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
|
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
|
||||||
let deref_target =
|
let deref_target =
|
||||||
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||||
Instance::resolve(tcx, self.param_env, deref_target, method_args)
|
Instance::try_resolve(tcx, self.param_env, deref_target, method_args)
|
||||||
.transpose()
|
.transpose()
|
||||||
});
|
});
|
||||||
if let Some(Ok(instance)) = deref_target {
|
if let Some(Ok(instance)) = deref_target {
|
||||||
|
@ -949,7 +949,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(Some(instance)) = ty::Instance::resolve(
|
if let Ok(Some(instance)) = ty::Instance::try_resolve(
|
||||||
tcx,
|
tcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
*fn_did,
|
*fn_did,
|
||||||
|
@ -371,9 +371,14 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||||||
|
|
||||||
// Handle special calls like intrinsics and empty drop glue.
|
// Handle special calls like intrinsics and empty drop glue.
|
||||||
let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
|
let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
|
||||||
let instance =
|
let instance = ty::Instance::expect_resolve(
|
||||||
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
|
fx.tcx,
|
||||||
.polymorphize(fx.tcx);
|
ty::ParamEnv::reveal_all(),
|
||||||
|
def_id,
|
||||||
|
fn_args,
|
||||||
|
source_info.span,
|
||||||
|
)
|
||||||
|
.polymorphize(fx.tcx);
|
||||||
|
|
||||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||||
if target.is_some() {
|
if target.is_some() {
|
||||||
|
@ -4,6 +4,7 @@ use rustc_middle::ty::AssocKind;
|
|||||||
use rustc_middle::ty::GenericArg;
|
use rustc_middle::ty::GenericArg;
|
||||||
use rustc_session::config::{sigpipe, EntryFnType};
|
use rustc_session::config::{sigpipe, EntryFnType};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
use rustc_span::DUMMY_SP;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
@ -119,6 +120,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||||||
ParamEnv::reveal_all(),
|
ParamEnv::reveal_all(),
|
||||||
report.def_id,
|
report.def_id,
|
||||||
tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
|
tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
|
||||||
|
DUMMY_SP,
|
||||||
)
|
)
|
||||||
.polymorphize(tcx);
|
.polymorphize(tcx);
|
||||||
|
|
||||||
@ -144,6 +146,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||||||
ParamEnv::reveal_all(),
|
ParamEnv::reveal_all(),
|
||||||
start_def_id,
|
start_def_id,
|
||||||
tcx.mk_args(&[main_ret_ty.into()]),
|
tcx.mk_args(&[main_ret_ty.into()]),
|
||||||
|
DUMMY_SP,
|
||||||
)
|
)
|
||||||
.polymorphize(tcx);
|
.polymorphize(tcx);
|
||||||
let start_func_id = import_function(tcx, m, start_instance);
|
let start_func_id = import_function(tcx, m, start_instance);
|
||||||
|
@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{
|
|||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::{source_map::respan, Span};
|
use rustc_span::{source_map::respan, Span, DUMMY_SP};
|
||||||
use rustc_target::abi::{
|
use rustc_target::abi::{
|
||||||
call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
|
call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
|
||||||
};
|
};
|
||||||
@ -479,6 +479,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
def_id,
|
def_id,
|
||||||
ty::List::empty(),
|
ty::List::empty(),
|
||||||
|
DUMMY_SP,
|
||||||
);
|
);
|
||||||
|
|
||||||
let symbol_name = tcx.symbol_name(instance).name;
|
let symbol_name = tcx.symbol_name(instance).name;
|
||||||
|
@ -28,7 +28,7 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
|
|||||||
use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
|
use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::Span;
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx};
|
use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx};
|
||||||
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
|
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -580,6 +580,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
def_id,
|
def_id,
|
||||||
ty::List::empty(),
|
ty::List::empty(),
|
||||||
|
DUMMY_SP,
|
||||||
)),
|
)),
|
||||||
_ => {
|
_ => {
|
||||||
let name = name.unwrap_or("rust_eh_personality");
|
let name = name.unwrap_or("rust_eh_personality");
|
||||||
|
@ -37,7 +37,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
|||||||
use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
|
use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::{Symbol, DUMMY_SP};
|
||||||
use rustc_target::abi::FIRST_VARIANT;
|
use rustc_target::abi::FIRST_VARIANT;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
@ -467,6 +467,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
start_def_id,
|
start_def_id,
|
||||||
cx.tcx().mk_args(&[main_ret_ty.into()]),
|
cx.tcx().mk_args(&[main_ret_ty.into()]),
|
||||||
|
DUMMY_SP,
|
||||||
);
|
);
|
||||||
let start_fn = cx.get_fn_addr(start_instance);
|
let start_fn = cx.get_fn_addr(start_instance);
|
||||||
|
|
||||||
|
@ -842,6 +842,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
def_id,
|
def_id,
|
||||||
args,
|
args,
|
||||||
|
fn_span,
|
||||||
)
|
)
|
||||||
.polymorphize(bx.tcx()),
|
.polymorphize(bx.tcx()),
|
||||||
),
|
),
|
||||||
|
@ -768,7 +768,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
is_trait = true;
|
is_trait = true;
|
||||||
|
|
||||||
if let Ok(Some(instance)) =
|
if let Ok(Some(instance)) =
|
||||||
Instance::resolve(tcx, param_env, callee, fn_args)
|
Instance::try_resolve(tcx, param_env, callee, fn_args)
|
||||||
&& let InstanceKind::Item(def) = instance.def
|
&& let InstanceKind::Item(def) = instance.def
|
||||||
{
|
{
|
||||||
// Resolve a trait method call to its concrete implementation, which may be in a
|
// Resolve a trait method call to its concrete implementation, which may be in a
|
||||||
|
@ -253,6 +253,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
|||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
const_def_id,
|
const_def_id,
|
||||||
instance.args,
|
instance.args,
|
||||||
|
self.cur_span(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Ok(Some(new_instance));
|
return Ok(Some(new_instance));
|
||||||
|
@ -618,7 +618,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
trace!("resolve: {:?}, {:#?}", def, args);
|
trace!("resolve: {:?}, {:#?}", def, args);
|
||||||
trace!("param_env: {:#?}", self.param_env);
|
trace!("param_env: {:#?}", self.param_env);
|
||||||
trace!("args: {:#?}", args);
|
trace!("args: {:#?}", args);
|
||||||
match ty::Instance::resolve(*self.tcx, self.param_env, def, args) {
|
match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) {
|
||||||
Ok(Some(instance)) => Ok(instance),
|
Ok(Some(instance)) => Ok(instance),
|
||||||
Ok(None) => throw_inval!(TooGeneric),
|
Ok(None) => throw_inval!(TooGeneric),
|
||||||
|
|
||||||
|
@ -883,13 +883,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
|
ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
|
||||||
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
|
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
|
||||||
|
|
||||||
let concrete_method = Instance::resolve_for_vtable(
|
let concrete_method = Instance::expect_resolve_for_vtable(
|
||||||
tcx,
|
tcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
def_id,
|
def_id,
|
||||||
instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
|
instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
|
||||||
)
|
self.cur_span(),
|
||||||
.unwrap();
|
);
|
||||||
assert_eq!(fn_inst, concrete_method);
|
assert_eq!(fn_inst, concrete_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
// Find the method being called.
|
// Find the method being called.
|
||||||
let Ok(Some(instance)) = ty::Instance::resolve(
|
let Ok(Some(instance)) = ty::Instance::try_resolve(
|
||||||
tcx,
|
tcx,
|
||||||
ctxt.param_env,
|
ctxt.param_env,
|
||||||
ctxt.assoc_item.def_id,
|
ctxt.assoc_item.def_id,
|
||||||
|
@ -88,7 +88,7 @@ declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);
|
|||||||
impl LateLintPass<'_> for QueryStability {
|
impl LateLintPass<'_> for QueryStability {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
|
let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
|
||||||
if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args) {
|
if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) {
|
||||||
let def_id = instance.def_id();
|
let def_id = instance.def_id();
|
||||||
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
|
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
|
||||||
cx.emit_span_lint(
|
cx.emit_span_lint(
|
||||||
@ -393,7 +393,7 @@ impl LateLintPass<'_> for Diagnostics {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Is the callee marked with `#[rustc_lint_diagnostics]`?
|
// Is the callee marked with `#[rustc_lint_diagnostics]`?
|
||||||
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
|
let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
|
.is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
|
||||||
|
@ -96,7 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
|||||||
.tcx
|
.tcx
|
||||||
.normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id));
|
.normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id));
|
||||||
// Resolve the trait method instance.
|
// Resolve the trait method instance.
|
||||||
let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, cx.param_env, did, args) else { return };
|
let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, did, args) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
// (Re)check that it implements the noop diagnostic.
|
// (Re)check that it implements the noop diagnostic.
|
||||||
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
|
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
|
||||||
if !matches!(
|
if !matches!(
|
||||||
|
@ -41,6 +41,9 @@ middle_cannot_be_normalized =
|
|||||||
middle_conflict_types =
|
middle_conflict_types =
|
||||||
this expression supplies two conflicting concrete types for the same opaque type
|
this expression supplies two conflicting concrete types for the same opaque type
|
||||||
|
|
||||||
|
middle_consider_type_length_limit =
|
||||||
|
consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
|
||||||
|
|
||||||
middle_const_eval_non_int =
|
middle_const_eval_non_int =
|
||||||
constant evaluation of enum discriminant resulted in non-integer
|
constant evaluation of enum discriminant resulted in non-integer
|
||||||
|
|
||||||
@ -94,8 +97,11 @@ middle_strict_coherence_needs_negative_coherence =
|
|||||||
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||||
.label = due to this attribute
|
.label = due to this attribute
|
||||||
|
|
||||||
|
middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
|
||||||
|
|
||||||
middle_unknown_layout =
|
middle_unknown_layout =
|
||||||
the type `{$ty}` has an unknown layout
|
the type `{$ty}` has an unknown layout
|
||||||
|
|
||||||
middle_values_too_big =
|
middle_values_too_big =
|
||||||
values of the type `{$ty}` are too big for the current architecture
|
values of the type `{$ty}` are too big for the current architecture
|
||||||
|
middle_written_to_path = the full type name has been written to '{$path}'
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage};
|
use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
@ -149,3 +150,16 @@ pub struct ErroneousConstant {
|
|||||||
|
|
||||||
/// Used by `rustc_const_eval`
|
/// Used by `rustc_const_eval`
|
||||||
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
|
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(middle_type_length_limit)]
|
||||||
|
#[help(middle_consider_type_length_limit)]
|
||||||
|
pub struct TypeLengthLimit {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub shrunk: String,
|
||||||
|
#[note(middle_written_to_path)]
|
||||||
|
pub was_written: Option<()>,
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub type_length: usize,
|
||||||
|
}
|
||||||
|
@ -30,7 +30,7 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
tcx.hir().krate_attrs(),
|
tcx.hir().krate_attrs(),
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
sym::type_length_limit,
|
sym::type_length_limit,
|
||||||
1048576,
|
2usize.pow(24),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
bug!("did not expect inference variables here");
|
bug!("did not expect inference variables here");
|
||||||
}
|
}
|
||||||
|
|
||||||
match ty::Instance::resolve(
|
match ty::Instance::try_resolve(
|
||||||
self, param_env,
|
self, param_env,
|
||||||
// FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
|
// FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
|
||||||
ct.def, ct.args,
|
ct.def, ct.args,
|
||||||
@ -106,7 +106,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
bug!("did not expect inference variables here");
|
bug!("did not expect inference variables here");
|
||||||
}
|
}
|
||||||
|
|
||||||
match ty::Instance::resolve(self, param_env, ct.def, ct.args) {
|
match ty::Instance::try_resolve(self, param_env, ct.def, ct.args) {
|
||||||
Ok(Some(instance)) => {
|
Ok(Some(instance)) => {
|
||||||
let cid = GlobalId { instance, promoted: None };
|
let cid = GlobalId { instance, promoted: None };
|
||||||
self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
|
self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
|
||||||
|
@ -2197,8 +2197,8 @@ rustc_queries! {
|
|||||||
/// * `Err(ErrorGuaranteed)` when the `Instance` resolution process
|
/// * `Err(ErrorGuaranteed)` when the `Instance` resolution process
|
||||||
/// couldn't complete due to errors elsewhere - this is distinct
|
/// couldn't complete due to errors elsewhere - this is distinct
|
||||||
/// from `Ok(None)` to avoid misleading diagnostics when an error
|
/// from `Ok(None)` to avoid misleading diagnostics when an error
|
||||||
/// has already been/will be emitted, for the original cause
|
/// has already been/will be emitted, for the original cause.
|
||||||
query resolve_instance(
|
query resolve_instance_raw(
|
||||||
key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>
|
key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>
|
||||||
) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
|
) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
|
||||||
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
|
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
|
use crate::error;
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use crate::ty::print::{FmtPrinter, Printer};
|
use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer};
|
||||||
use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
|
use crate::ty::{
|
||||||
use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt};
|
self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
|
||||||
|
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||||
|
};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_hir::def_id::{CrateNum, DefId};
|
use rustc_hir::def_id::{CrateNum, DefId};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_index::bit_set::FiniteBitSet;
|
use rustc_index::bit_set::FiniteBitSet;
|
||||||
use rustc_macros::{
|
use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable};
|
||||||
Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable, TypeVisitable,
|
|
||||||
};
|
|
||||||
use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
|
use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
|
||||||
use rustc_span::def_id::LOCAL_CRATE;
|
use rustc_span::def_id::LOCAL_CRATE;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// An `InstanceKind` along with the args that are needed to substitute the instance.
|
/// An `InstanceKind` along with the args that are needed to substitute the instance.
|
||||||
///
|
///
|
||||||
@ -385,7 +387,28 @@ impl<'tcx> InstanceKind<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_instance(
|
fn type_length<'tcx>(item: impl TypeVisitable<TyCtxt<'tcx>>) -> usize {
|
||||||
|
struct Visitor {
|
||||||
|
type_length: usize,
|
||||||
|
}
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor {
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) {
|
||||||
|
self.type_length += 1;
|
||||||
|
t.super_visit_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
|
||||||
|
self.type_length += 1;
|
||||||
|
ct.super_visit_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut visitor = Visitor { type_length: 0 };
|
||||||
|
item.visit_with(&mut visitor);
|
||||||
|
|
||||||
|
visitor.type_length
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmt_instance(
|
||||||
f: &mut fmt::Formatter<'_>,
|
f: &mut fmt::Formatter<'_>,
|
||||||
instance: Instance<'_>,
|
instance: Instance<'_>,
|
||||||
type_length: Option<rustc_session::Limit>,
|
type_length: Option<rustc_session::Limit>,
|
||||||
@ -485,19 +508,30 @@ impl<'tcx> Instance<'tcx> {
|
|||||||
///
|
///
|
||||||
/// Presuming that coherence and type-check have succeeded, if this method is invoked
|
/// Presuming that coherence and type-check have succeeded, if this method is invoked
|
||||||
/// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
|
/// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
|
||||||
/// `Ok(Some(instance))`.
|
/// `Ok(Some(instance))`, **except** for when the instance's inputs hit the type size limit,
|
||||||
|
/// in which case it may bail out and return `Ok(None)`.
|
||||||
///
|
///
|
||||||
/// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process
|
/// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process
|
||||||
/// couldn't complete due to errors elsewhere - this is distinct
|
/// couldn't complete due to errors elsewhere - this is distinct
|
||||||
/// from `Ok(None)` to avoid misleading diagnostics when an error
|
/// from `Ok(None)` to avoid misleading diagnostics when an error
|
||||||
/// has already been/will be emitted, for the original cause
|
/// has already been/will be emitted, for the original cause
|
||||||
#[instrument(level = "debug", skip(tcx), ret)]
|
#[instrument(level = "debug", skip(tcx), ret)]
|
||||||
pub fn resolve(
|
pub fn try_resolve(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
|
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
|
||||||
|
// Rust code can easily create exponentially-long types using only a
|
||||||
|
// polynomial recursion depth. Even with the default recursion
|
||||||
|
// depth, you can easily get cases that take >2^60 steps to run,
|
||||||
|
// which means that rustc basically hangs.
|
||||||
|
//
|
||||||
|
// Bail out in these cases to avoid that bad user experience.
|
||||||
|
if !tcx.type_length_limit().value_within_limit(type_length(args)) {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
// All regions in the result of this query are erased, so it's
|
// All regions in the result of this query are erased, so it's
|
||||||
// fine to erase all of the input regions.
|
// fine to erase all of the input regions.
|
||||||
|
|
||||||
@ -505,7 +539,7 @@ impl<'tcx> Instance<'tcx> {
|
|||||||
// below is more likely to ignore the bounds in scope (e.g. if the only
|
// below is more likely to ignore the bounds in scope (e.g. if the only
|
||||||
// generic parameters mentioned by `args` were lifetime ones).
|
// generic parameters mentioned by `args` were lifetime ones).
|
||||||
let args = tcx.erase_regions(args);
|
let args = tcx.erase_regions(args);
|
||||||
tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, args))))
|
tcx.resolve_instance_raw(tcx.erase_regions(param_env.and((def_id, args))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_resolve(
|
pub fn expect_resolve(
|
||||||
@ -513,10 +547,48 @@ impl<'tcx> Instance<'tcx> {
|
|||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
|
span: Span,
|
||||||
) -> Instance<'tcx> {
|
) -> Instance<'tcx> {
|
||||||
match ty::Instance::resolve(tcx, param_env, def_id, args) {
|
// We compute the span lazily, to avoid unnecessary query calls.
|
||||||
|
// If `span` is a DUMMY_SP, and the def id is local, then use the
|
||||||
|
// def span of the def id.
|
||||||
|
let span_or_local_def_span =
|
||||||
|
|| if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span };
|
||||||
|
|
||||||
|
match ty::Instance::try_resolve(tcx, param_env, def_id, args) {
|
||||||
Ok(Some(instance)) => instance,
|
Ok(Some(instance)) => instance,
|
||||||
instance => bug!(
|
Ok(None) => {
|
||||||
|
let type_length = type_length(args);
|
||||||
|
if !tcx.type_length_limit().value_within_limit(type_length) {
|
||||||
|
let (shrunk, written_to_path) =
|
||||||
|
shrunk_instance_name(tcx, Instance::new(def_id, args));
|
||||||
|
let mut path = PathBuf::new();
|
||||||
|
let was_written = if let Some(path2) = written_to_path {
|
||||||
|
path = path2;
|
||||||
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
tcx.dcx().emit_fatal(error::TypeLengthLimit {
|
||||||
|
// We don't use `def_span(def_id)` so that diagnostics point
|
||||||
|
// to the crate root during mono instead of to foreign items.
|
||||||
|
// This is arguably better.
|
||||||
|
span: span_or_local_def_span(),
|
||||||
|
shrunk,
|
||||||
|
was_written,
|
||||||
|
path,
|
||||||
|
type_length,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
span_bug!(
|
||||||
|
span_or_local_def_span(),
|
||||||
|
"failed to resolve instance for {}",
|
||||||
|
tcx.def_path_str_with_args(def_id, args)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instance => span_bug!(
|
||||||
|
span_or_local_def_span(),
|
||||||
"failed to resolve instance for {}: {instance:#?}",
|
"failed to resolve instance for {}: {instance:#?}",
|
||||||
tcx.def_path_str_with_args(def_id, args)
|
tcx.def_path_str_with_args(def_id, args)
|
||||||
),
|
),
|
||||||
@ -533,7 +605,7 @@ impl<'tcx> Instance<'tcx> {
|
|||||||
// Use either `resolve_closure` or `resolve_for_vtable`
|
// Use either `resolve_closure` or `resolve_for_vtable`
|
||||||
assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
|
assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
|
||||||
let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
|
let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
|
||||||
Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
|
Instance::try_resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
|
||||||
match resolved.def {
|
match resolved.def {
|
||||||
InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => {
|
InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => {
|
||||||
debug!(" => fn pointer created for function with #[track_caller]");
|
debug!(" => fn pointer created for function with #[track_caller]");
|
||||||
@ -571,77 +643,82 @@ impl<'tcx> Instance<'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_for_vtable(
|
pub fn expect_resolve_for_vtable(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
) -> Option<Instance<'tcx>> {
|
span: Span,
|
||||||
|
) -> Instance<'tcx> {
|
||||||
debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args);
|
debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args);
|
||||||
let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
|
let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||||
let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
|
let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
|
||||||
&& fn_sig.input(0).skip_binder().is_param(0)
|
&& fn_sig.input(0).skip_binder().is_param(0)
|
||||||
&& tcx.generics_of(def_id).has_self;
|
&& tcx.generics_of(def_id).has_self;
|
||||||
|
|
||||||
if is_vtable_shim {
|
if is_vtable_shim {
|
||||||
debug!(" => associated item with unsizeable self: Self");
|
debug!(" => associated item with unsizeable self: Self");
|
||||||
Some(Instance { def: InstanceKind::VTableShim(def_id), args })
|
return Instance { def: InstanceKind::VTableShim(def_id), args };
|
||||||
} else {
|
|
||||||
let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
|
|
||||||
Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
|
|
||||||
match resolved.def {
|
|
||||||
InstanceKind::Item(def) => {
|
|
||||||
// We need to generate a shim when we cannot guarantee that
|
|
||||||
// the caller of a trait object method will be aware of
|
|
||||||
// `#[track_caller]` - this ensures that the caller
|
|
||||||
// and callee ABI will always match.
|
|
||||||
//
|
|
||||||
// The shim is generated when all of these conditions are met:
|
|
||||||
//
|
|
||||||
// 1) The underlying method expects a caller location parameter
|
|
||||||
// in the ABI
|
|
||||||
if resolved.def.requires_caller_location(tcx)
|
|
||||||
// 2) The caller location parameter comes from having `#[track_caller]`
|
|
||||||
// on the implementation, and *not* on the trait method.
|
|
||||||
&& !tcx.should_inherit_track_caller(def)
|
|
||||||
// If the method implementation comes from the trait definition itself
|
|
||||||
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
|
|
||||||
// then we don't need to generate a shim. This check is needed because
|
|
||||||
// `should_inherit_track_caller` returns `false` if our method
|
|
||||||
// implementation comes from the trait block, and not an impl block
|
|
||||||
&& !matches!(
|
|
||||||
tcx.opt_associated_item(def),
|
|
||||||
Some(ty::AssocItem {
|
|
||||||
container: ty::AssocItemContainer::TraitContainer,
|
|
||||||
..
|
|
||||||
})
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if tcx.is_closure_like(def) {
|
|
||||||
debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
|
|
||||||
def, def_id, args);
|
|
||||||
|
|
||||||
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
|
|
||||||
// - unlike functions, invoking a closure always goes through a
|
|
||||||
// trait.
|
|
||||||
resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args };
|
|
||||||
} else {
|
|
||||||
debug!(
|
|
||||||
" => vtable fn pointer created for function with #[track_caller]: {:?}", def
|
|
||||||
);
|
|
||||||
resolved.def = InstanceKind::ReifyShim(def, reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InstanceKind::Virtual(def_id, _) => {
|
|
||||||
debug!(" => vtable fn pointer created for virtual call");
|
|
||||||
resolved.def = InstanceKind::ReifyShim(def_id, reason)
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolved
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, span);
|
||||||
|
|
||||||
|
let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
|
||||||
|
match resolved.def {
|
||||||
|
InstanceKind::Item(def) => {
|
||||||
|
// We need to generate a shim when we cannot guarantee that
|
||||||
|
// the caller of a trait object method will be aware of
|
||||||
|
// `#[track_caller]` - this ensures that the caller
|
||||||
|
// and callee ABI will always match.
|
||||||
|
//
|
||||||
|
// The shim is generated when all of these conditions are met:
|
||||||
|
//
|
||||||
|
// 1) The underlying method expects a caller location parameter
|
||||||
|
// in the ABI
|
||||||
|
if resolved.def.requires_caller_location(tcx)
|
||||||
|
// 2) The caller location parameter comes from having `#[track_caller]`
|
||||||
|
// on the implementation, and *not* on the trait method.
|
||||||
|
&& !tcx.should_inherit_track_caller(def)
|
||||||
|
// If the method implementation comes from the trait definition itself
|
||||||
|
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
|
||||||
|
// then we don't need to generate a shim. This check is needed because
|
||||||
|
// `should_inherit_track_caller` returns `false` if our method
|
||||||
|
// implementation comes from the trait block, and not an impl block
|
||||||
|
&& !matches!(
|
||||||
|
tcx.opt_associated_item(def),
|
||||||
|
Some(ty::AssocItem {
|
||||||
|
container: ty::AssocItemContainer::TraitContainer,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if tcx.is_closure_like(def) {
|
||||||
|
debug!(
|
||||||
|
" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
|
||||||
|
def, def_id, args
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
|
||||||
|
// - unlike functions, invoking a closure always goes through a
|
||||||
|
// trait.
|
||||||
|
resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args };
|
||||||
|
} else {
|
||||||
|
debug!(
|
||||||
|
" => vtable fn pointer created for function with #[track_caller]: {:?}",
|
||||||
|
def
|
||||||
|
);
|
||||||
|
resolved.def = InstanceKind::ReifyShim(def, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InstanceKind::Virtual(def_id, _) => {
|
||||||
|
debug!(" => vtable fn pointer created for virtual call");
|
||||||
|
resolved.def = InstanceKind::ReifyShim(def_id, reason)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_closure(
|
pub fn resolve_closure(
|
||||||
@ -661,13 +738,25 @@ impl<'tcx> Instance<'tcx> {
|
|||||||
pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
|
pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
|
||||||
let def_id = tcx.require_lang_item(LangItem::DropInPlace, None);
|
let def_id = tcx.require_lang_item(LangItem::DropInPlace, None);
|
||||||
let args = tcx.mk_args(&[ty.into()]);
|
let args = tcx.mk_args(&[ty.into()]);
|
||||||
Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
|
Instance::expect_resolve(
|
||||||
|
tcx,
|
||||||
|
ty::ParamEnv::reveal_all(),
|
||||||
|
def_id,
|
||||||
|
args,
|
||||||
|
ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
|
pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
|
||||||
let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None);
|
let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None);
|
||||||
let args = tcx.mk_args(&[ty.into()]);
|
let args = tcx.mk_args(&[ty.into()]);
|
||||||
Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
|
Instance::expect_resolve(
|
||||||
|
tcx,
|
||||||
|
ty::ParamEnv::reveal_all(),
|
||||||
|
def_id,
|
||||||
|
args,
|
||||||
|
ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(tcx), ret)]
|
#[instrument(level = "debug", skip(tcx), ret)]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::ty::GenericArg;
|
use crate::ty::GenericArg;
|
||||||
use crate::ty::{self, Ty, TyCtxt};
|
use crate::ty::{self, ShortInstance, Ty, TyCtxt};
|
||||||
|
|
||||||
use hir::def::Namespace;
|
use hir::def::Namespace;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
@ -356,3 +358,31 @@ where
|
|||||||
with_no_trimmed_paths!(Self::print(t, fmt))
|
with_no_trimmed_paths!(Self::print(t, fmt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format instance name that is already known to be too long for rustc.
|
||||||
|
/// Show only the first 2 types if it is longer than 32 characters to avoid blasting
|
||||||
|
/// the user's terminal with thousands of lines of type-name.
|
||||||
|
///
|
||||||
|
/// If the type name is longer than before+after, it will be written to a file.
|
||||||
|
pub fn shrunk_instance_name<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
instance: ty::Instance<'tcx>,
|
||||||
|
) -> (String, Option<PathBuf>) {
|
||||||
|
let s = instance.to_string();
|
||||||
|
|
||||||
|
// Only use the shrunk version if it's really shorter.
|
||||||
|
// This also avoids the case where before and after slices overlap.
|
||||||
|
if s.chars().nth(33).is_some() {
|
||||||
|
let shrunk = format!("{}", ShortInstance(instance, 4));
|
||||||
|
if shrunk == s {
|
||||||
|
return (s, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None);
|
||||||
|
let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
|
||||||
|
|
||||||
|
(shrunk, written_to_path)
|
||||||
|
} else {
|
||||||
|
(s, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -98,7 +98,7 @@ pub fn call_kind<'tcx>(
|
|||||||
Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) })
|
Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) })
|
||||||
} else if is_deref {
|
} else if is_deref {
|
||||||
let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||||
Instance::resolve(tcx, param_env, deref_target, method_args).transpose()
|
Instance::try_resolve(tcx, param_env, deref_target, method_args).transpose()
|
||||||
});
|
});
|
||||||
if let Some(Ok(instance)) = deref_target {
|
if let Some(Ok(instance)) = deref_target {
|
||||||
let deref_target_ty = instance.ty(tcx, param_env);
|
let deref_target_ty = instance.ty(tcx, param_env);
|
||||||
|
@ -141,7 +141,7 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let (callee, call_args) = if let Ok(Some(instance)) =
|
let (callee, call_args) = if let Ok(Some(instance)) =
|
||||||
Instance::resolve(tcx, param_env, callee, normalized_args)
|
Instance::try_resolve(tcx, param_env, callee, normalized_args)
|
||||||
{
|
{
|
||||||
(instance.def_id(), instance.args)
|
(instance.def_id(), instance.args)
|
||||||
} else {
|
} else {
|
||||||
|
@ -558,7 +558,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
let args = self
|
let args = self
|
||||||
.tcx
|
.tcx
|
||||||
.normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id));
|
.normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id));
|
||||||
let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, args) {
|
let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args)
|
||||||
|
{
|
||||||
Ok(Some(i)) => i,
|
Ok(Some(i)) => i,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// It should be assoc consts if there's no error but we cannot resolve it.
|
// It should be assoc consts if there's no error but we cannot resolve it.
|
||||||
|
@ -389,7 +389,7 @@ impl<'tcx> Inliner<'tcx> {
|
|||||||
// To resolve an instance its args have to be fully normalized.
|
// To resolve an instance its args have to be fully normalized.
|
||||||
let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?;
|
let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?;
|
||||||
let callee =
|
let callee =
|
||||||
Instance::resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?;
|
Instance::try_resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?;
|
||||||
|
|
||||||
if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def {
|
if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def {
|
||||||
return None;
|
return None;
|
||||||
|
@ -53,7 +53,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
|
|||||||
trace!(?caller, ?param_env, ?args, "cannot normalize, skipping");
|
trace!(?caller, ?param_env, ?args, "cannot normalize, skipping");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, args) else {
|
let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, param_env, callee, args) else {
|
||||||
trace!(?callee, "cannot resolve, skipping");
|
trace!(?callee, "cannot resolve, skipping");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
monomorphize_consider_type_length_limit =
|
|
||||||
consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
|
|
||||||
|
|
||||||
monomorphize_couldnt_dump_mono_stats =
|
monomorphize_couldnt_dump_mono_stats =
|
||||||
unexpected error occurred while dumping monomorphization stats: {$error}
|
unexpected error occurred while dumping monomorphization stats: {$error}
|
||||||
|
|
||||||
@ -25,8 +22,6 @@ monomorphize_start_not_found = using `fn main` requires the standard library
|
|||||||
|
|
||||||
monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
|
monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
|
||||||
|
|
||||||
monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
|
|
||||||
|
|
||||||
monomorphize_unknown_cgu_collection_mode =
|
monomorphize_unknown_cgu_collection_mode =
|
||||||
unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
|
unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
|
||||||
|
|
||||||
|
@ -222,12 +222,12 @@ use rustc_middle::mir::{self, Location, MentionedItem};
|
|||||||
use rustc_middle::query::TyCtxtAt;
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
|
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
|
||||||
use rustc_middle::ty::layout::ValidityRequirement;
|
use rustc_middle::ty::layout::ValidityRequirement;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
|
||||||
|
use rustc_middle::ty::GenericArgs;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
|
self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
|
||||||
TypeVisitableExt, VtblEntry,
|
TypeVisitableExt, VtblEntry,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{GenericArgKind, GenericArgs};
|
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::config::EntryFnType;
|
use rustc_session::config::EntryFnType;
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
@ -238,9 +238,7 @@ use rustc_target::abi::Size;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit};
|
||||||
self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit,
|
|
||||||
};
|
|
||||||
use move_check::MoveCheckState;
|
use move_check::MoveCheckState;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
@ -443,7 +441,6 @@ fn collect_items_rec<'tcx>(
|
|||||||
recursion_depths,
|
recursion_depths,
|
||||||
recursion_limit,
|
recursion_limit,
|
||||||
));
|
));
|
||||||
check_type_length_limit(tcx, instance);
|
|
||||||
|
|
||||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||||
collect_items_of_instance(
|
collect_items_of_instance(
|
||||||
@ -554,34 +551,6 @@ fn collect_items_rec<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format instance name that is already known to be too long for rustc.
|
|
||||||
/// Show only the first 2 types if it is longer than 32 characters to avoid blasting
|
|
||||||
/// the user's terminal with thousands of lines of type-name.
|
|
||||||
///
|
|
||||||
/// If the type name is longer than before+after, it will be written to a file.
|
|
||||||
fn shrunk_instance_name<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
instance: Instance<'tcx>,
|
|
||||||
) -> (String, Option<PathBuf>) {
|
|
||||||
let s = instance.to_string();
|
|
||||||
|
|
||||||
// Only use the shrunk version if it's really shorter.
|
|
||||||
// This also avoids the case where before and after slices overlap.
|
|
||||||
if s.chars().nth(33).is_some() {
|
|
||||||
let shrunk = format!("{}", ty::ShortInstance(instance, 4));
|
|
||||||
if shrunk == s {
|
|
||||||
return (s, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None);
|
|
||||||
let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
|
|
||||||
|
|
||||||
(shrunk, written_to_path)
|
|
||||||
} else {
|
|
||||||
(s, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_recursion_limit<'tcx>(
|
fn check_recursion_limit<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
instance: Instance<'tcx>,
|
instance: Instance<'tcx>,
|
||||||
@ -630,38 +599,6 @@ fn check_recursion_limit<'tcx>(
|
|||||||
(def_id, recursion_depth)
|
(def_id, recursion_depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
|
|
||||||
let type_length = instance
|
|
||||||
.args
|
|
||||||
.iter()
|
|
||||||
.flat_map(|arg| arg.walk())
|
|
||||||
.filter(|arg| match arg.unpack() {
|
|
||||||
GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
|
|
||||||
GenericArgKind::Lifetime(_) => false,
|
|
||||||
})
|
|
||||||
.count();
|
|
||||||
debug!(" => type length={}", type_length);
|
|
||||||
|
|
||||||
// Rust code can easily create exponentially-long types using only a
|
|
||||||
// polynomial recursion depth. Even with the default recursion
|
|
||||||
// depth, you can easily get cases that take >2^60 steps to run,
|
|
||||||
// which means that rustc basically hangs.
|
|
||||||
//
|
|
||||||
// Bail out in these cases to avoid that bad user experience.
|
|
||||||
if !tcx.type_length_limit().value_within_limit(type_length) {
|
|
||||||
let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance);
|
|
||||||
let span = tcx.def_span(instance.def_id());
|
|
||||||
let mut path = PathBuf::new();
|
|
||||||
let was_written = if let Some(path2) = written_to_path {
|
|
||||||
path = path2;
|
|
||||||
Some(())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
tcx.dcx().emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MirUsedCollector<'a, 'tcx> {
|
struct MirUsedCollector<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &'a mir::Body<'tcx>,
|
body: &'a mir::Body<'tcx>,
|
||||||
@ -916,7 +853,7 @@ fn visit_fn_use<'tcx>(
|
|||||||
) {
|
) {
|
||||||
if let ty::FnDef(def_id, args) = *ty.kind() {
|
if let ty::FnDef(def_id, args) = *ty.kind() {
|
||||||
let instance = if is_direct_call {
|
let instance = if is_direct_call {
|
||||||
ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
|
ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, source)
|
||||||
} else {
|
} else {
|
||||||
match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) {
|
match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) {
|
||||||
Some(instance) => instance,
|
Some(instance) => instance,
|
||||||
@ -1319,7 +1256,7 @@ fn visit_mentioned_item<'tcx>(
|
|||||||
MentionedItem::Fn(ty) => {
|
MentionedItem::Fn(ty) => {
|
||||||
if let ty::FnDef(def_id, args) = *ty.kind() {
|
if let ty::FnDef(def_id, args) = *ty.kind() {
|
||||||
let instance =
|
let instance =
|
||||||
Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args);
|
Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, span);
|
||||||
// `visit_instance_use` was written for "used" item collection but works just as well
|
// `visit_instance_use` was written for "used" item collection but works just as well
|
||||||
// for "mentioned" item collection.
|
// for "mentioned" item collection.
|
||||||
// We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
|
// We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
|
||||||
@ -1544,6 +1481,7 @@ impl<'v> RootCollector<'_, 'v> {
|
|||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
start_def_id,
|
start_def_id,
|
||||||
self.tcx.mk_args(&[main_ret_ty.into()]),
|
self.tcx.mk_args(&[main_ret_ty.into()]),
|
||||||
|
DUMMY_SP,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
|
self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
|
||||||
@ -1612,9 +1550,10 @@ fn create_mono_items_for_default_impls<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// As mentioned above, the method is legal to eagerly instantiate if it
|
// As mentioned above, the method is legal to eagerly instantiate if it
|
||||||
// only has lifetime generic parameters. This is validated by
|
// only has lifetime generic parameters. This is validated by calling
|
||||||
|
// `own_requires_monomorphization` on both the impl and method.
|
||||||
let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params);
|
let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params);
|
||||||
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args);
|
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP);
|
||||||
|
|
||||||
let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
|
let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
|
||||||
if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) {
|
if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) {
|
||||||
|
@ -19,19 +19,6 @@ pub struct RecursionLimit {
|
|||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(monomorphize_type_length_limit)]
|
|
||||||
#[help(monomorphize_consider_type_length_limit)]
|
|
||||||
pub struct TypeLengthLimit {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
pub shrunk: String,
|
|
||||||
#[note(monomorphize_written_to_path)]
|
|
||||||
pub was_written: Option<()>,
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub type_length: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(monomorphize_no_optimized_mir)]
|
#[diag(monomorphize_no_optimized_mir)]
|
||||||
pub struct NoOptimizedMir {
|
pub struct NoOptimizedMir {
|
||||||
|
@ -61,7 +61,7 @@ fn unwrap_fn_abi<'tcx>(
|
|||||||
fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
|
fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
|
||||||
let param_env = tcx.param_env(item_def_id);
|
let param_env = tcx.param_env(item_def_id);
|
||||||
let args = GenericArgs::identity_for_item(tcx, item_def_id);
|
let args = GenericArgs::identity_for_item(tcx, item_def_id);
|
||||||
let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) {
|
let instance = match Instance::try_resolve(tcx, param_env, item_def_id.into(), args) {
|
||||||
Ok(Some(instance)) => instance,
|
Ok(Some(instance)) => instance,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
|
// Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
|
||||||
|
@ -629,7 +629,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||||||
let tcx = tables.tcx;
|
let tcx = tables.tcx;
|
||||||
let def_id = def.0.internal(&mut *tables, tcx);
|
let def_id = def.0.internal(&mut *tables, tcx);
|
||||||
let args_ref = args.internal(&mut *tables, tcx);
|
let args_ref = args.internal(&mut *tables, tcx);
|
||||||
match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
|
match Instance::try_resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
|
||||||
Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
|
Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
|
||||||
Ok(None) | Err(_) => None,
|
Ok(None) | Err(_) => None,
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use rustc_middle::bug;
|
|||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
|
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
|
||||||
use rustc_middle::ty::{GenericArgs, TypeVisitableExt};
|
use rustc_middle::ty::{GenericArgs, TypeVisitableExt};
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::{sym, Span, DUMMY_SP};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -285,13 +285,14 @@ fn vtable_entries<'tcx>(
|
|||||||
return VtblEntry::Vacant;
|
return VtblEntry::Vacant;
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance = ty::Instance::resolve_for_vtable(
|
let instance = ty::Instance::expect_resolve_for_vtable(
|
||||||
tcx,
|
tcx,
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
def_id,
|
def_id,
|
||||||
args,
|
args,
|
||||||
)
|
DUMMY_SP,
|
||||||
.expect("resolution failed during building vtable representation");
|
);
|
||||||
|
|
||||||
VtblEntry::Method(instance)
|
VtblEntry::Method(instance)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ use traits::{translate_args, Reveal};
|
|||||||
|
|
||||||
use crate::errors::UnexpectedFnPtrAssociatedItem;
|
use crate::errors::UnexpectedFnPtrAssociatedItem;
|
||||||
|
|
||||||
fn resolve_instance<'tcx>(
|
fn resolve_instance_raw<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>,
|
key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>,
|
||||||
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
|
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
|
||||||
@ -364,5 +364,5 @@ fn resolve_associated_item<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers { resolve_instance, ..*providers };
|
*providers = Providers { resolve_instance_raw, ..*providers };
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
|
|||||||
let args = cx.typeck_results().node_args(expr.hir_id);
|
let args = cx.typeck_results().node_args(expr.hir_id);
|
||||||
|
|
||||||
// If we could not resolve the method, don't apply the lint
|
// If we could not resolve the method, don't apply the lint
|
||||||
let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
|
let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
|
if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
|
||||||
@ -119,7 +119,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
|
|||||||
|
|
||||||
// If we could not resolve the method, don't apply the lint
|
// If we could not resolve the method, don't apply the lint
|
||||||
let Ok(Some(resolved_method)) = (match kind {
|
let Ok(Some(resolved_method)) = (match kind {
|
||||||
ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args),
|
ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args),
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
}) else {
|
}) else {
|
||||||
return None;
|
return None;
|
||||||
|
@ -293,7 +293,7 @@ impl<'tcx> NonCopyConst<'tcx> {
|
|||||||
ct: ty::UnevaluatedConst<'tcx>,
|
ct: ty::UnevaluatedConst<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> EvalToValTreeResult<'tcx> {
|
) -> EvalToValTreeResult<'tcx> {
|
||||||
match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
|
match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) {
|
||||||
Ok(Some(instance)) => {
|
Ok(Some(instance)) => {
|
||||||
let cid = GlobalId {
|
let cid = GlobalId {
|
||||||
instance,
|
instance,
|
||||||
|
@ -375,7 +375,7 @@ pub fn create_ecx<'tcx>(
|
|||||||
});
|
});
|
||||||
let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
|
let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
|
||||||
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
|
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
|
||||||
let start_instance = ty::Instance::resolve(
|
let start_instance = ty::Instance::try_resolve(
|
||||||
tcx,
|
tcx,
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
start_id,
|
start_id,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
//@ build-pass
|
//@ build-fail
|
||||||
//@ ignore-compare-mode-next-solver (hangs)
|
|
||||||
|
|
||||||
// Closures include captured types twice in a type tree.
|
// Closures include captured types twice in a type tree.
|
||||||
//
|
//
|
||||||
@ -46,6 +45,7 @@ fn main() {
|
|||||||
|
|
||||||
let f = dup(f);
|
let f = dup(f);
|
||||||
let f = dup(f);
|
let f = dup(f);
|
||||||
|
//~^ ERROR reached the type-length limit
|
||||||
let f = dup(f);
|
let f = dup(f);
|
||||||
let f = dup(f);
|
let f = dup(f);
|
||||||
let f = dup(f);
|
let f = dup(f);
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>`
|
||||||
|
--> $DIR/issue-72408-nested-closures-exponential.rs:47:13
|
||||||
|
|
|
||||||
|
LL | let f = dup(f);
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//~^ ERROR overflow evaluating the requirement
|
//@ error-pattern: reached the type-length limit while instantiating
|
||||||
|
|
||||||
#![recursion_limit = "32"]
|
#![recursion_limit = "32"]
|
||||||
|
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized`
|
error: reached the type-length limit while instantiating `<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>`
|
||||||
|
--> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
|
||||||
|
|
|
|
||||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`)
|
= help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate
|
||||||
= note: required for `Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
|
= note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt'
|
||||||
= note: 31 redundant requirements hidden
|
|
||||||
= note: required for `Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
|
|
||||||
= note: required for `Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0275`.
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ normalize-stderr-test: "<\{closure@.+`" -> "$$CLOSURE`"
|
|
||||||
//@ normalize-stderr-test: ".nll/" -> "/"
|
|
||||||
//@ ignore-compare-mode-next-solver (hangs)
|
|
||||||
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
@ -43,6 +40,7 @@ impl C {
|
|||||||
pub fn matches<F: Fn()>(&self, f: &F) {
|
pub fn matches<F: Fn()>(&self, f: &F) {
|
||||||
let &C(ref base) = self;
|
let &C(ref base) = self;
|
||||||
base.matches(&|| {
|
base.matches(&|| {
|
||||||
|
//~^ ERROR reached the type-length limit
|
||||||
C(base.clone()).matches(f)
|
C(base.clone()).matches(f)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -55,7 +53,6 @@ impl D {
|
|||||||
pub fn matches<F: Fn()>(&self, f: &F) {
|
pub fn matches<F: Fn()>(&self, f: &F) {
|
||||||
let &D(ref a) = self;
|
let &D(ref a) = self;
|
||||||
a.matches(f)
|
a.matches(f)
|
||||||
//~^ ERROR reached the recursion limit while instantiating `A::matches::<{closure
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
error: reached the recursion limit while instantiating `A::matches::$CLOSURE`
|
error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>`
|
||||||
--> $DIR/issue-22638.rs:57:9
|
--> $DIR/issue-22638.rs:42:9
|
||||||
|
|
|
|
||||||
LL | a.matches(f)
|
LL | / base.matches(&|| {
|
||||||
| ^^^^^^^^^^^^
|
LL | |
|
||||||
|
LL | | C(base.clone()).matches(f)
|
||||||
|
LL | | })
|
||||||
|
| |__________^
|
||||||
|
|
|
|
||||||
note: `A::matches` defined here
|
= help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
|
||||||
--> $DIR/issue-22638.rs:16:5
|
|
||||||
|
|
|
||||||
LL | pub fn matches<F: Fn()>(&self, f: &F) {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ normalize-stderr-test: ".nll/" -> "/"
|
//@ normalize-stderr-test: ".nll/" -> "/"
|
||||||
//@ ignore-compare-mode-next-solver (hangs)
|
|
||||||
|
|
||||||
trait Mirror {
|
trait Mirror {
|
||||||
type Image;
|
type Image;
|
||||||
@ -15,7 +14,8 @@ trait Foo {
|
|||||||
impl<T> Foo for T {
|
impl<T> Foo for T {
|
||||||
#[allow(unconditional_recursion)]
|
#[allow(unconditional_recursion)]
|
||||||
fn recurse(&self) {
|
fn recurse(&self) {
|
||||||
(self, self).recurse(); //~ ERROR reached the recursion limit
|
(self, self).recurse();
|
||||||
|
//~^ ERROR reached the type-length limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
|
error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
|
||||||
--> $DIR/issue-37311.rs:18:9
|
--> $DIR/issue-37311.rs:17:9
|
||||||
|
|
|
|
||||||
LL | (self, self).recurse();
|
LL | (self, self).recurse();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: `<T as Foo>::recurse` defined here
|
= help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate
|
||||||
--> $DIR/issue-37311.rs:17:5
|
|
||||||
|
|
|
||||||
LL | fn recurse(&self) {
|
|
||||||
| ^^^^^^^^^^^^^^^^^
|
|
||||||
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt'
|
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt'
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//@ run-pass
|
//@ build-fail
|
||||||
//@ ignore-compare-mode-next-solver (hangs)
|
//@ error-pattern: reached the type-length limit while instantiating
|
||||||
|
|
||||||
//! This snippet causes the type length to blowup exponentially,
|
//! This snippet causes the type length to blowup exponentially,
|
||||||
//! so check that we don't accidentally exceed the type length limit.
|
//! so check that we don't accidentally exceed the type length limit.
|
||||||
@ -30,5 +30,9 @@ fn main() {
|
|||||||
.filter(|a| b.clone().any(|b| *b == *a))
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
.filter(|a| b.clone().any(|b| *b == *a))
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
.filter(|a| b.clone().any(|b| *b == *a))
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
|
.filter(|a| b.clone().any(|b| *b == *a))
|
||||||
.collect::<VecDeque<_>>();
|
.collect::<VecDeque<_>>();
|
||||||
}
|
}
|
||||||
|
8
tests/ui/iterators/issue-58952-filter-type-length.stderr
Normal file
8
tests/ui/iterators/issue-58952-filter-type-length.stderr
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
error: reached the type-length limit while instantiating `<std::vec::IntoIter<i32> as Iterator>::try_fold::<vec::in_place_drop::InPlaceDrop<i32>, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>`
|
||||||
|
--> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
|
||||||
|
|
|
||||||
|
= help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate
|
||||||
|
= note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt'
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
//!
|
//!
|
||||||
//! The normal limit is a million, and this test used to exceed 1.5 million, but
|
//! The normal limit is a million, and this test used to exceed 1.5 million, but
|
||||||
//! now we can survive an even tighter limit. Still seems excessive though...
|
//! now we can survive an even tighter limit. Still seems excessive though...
|
||||||
#![type_length_limit = "256000"]
|
#![type_length_limit = "1327047"]
|
||||||
|
|
||||||
// Custom wrapper so Iterator methods aren't specialized.
|
// Custom wrapper so Iterator methods aren't specialized.
|
||||||
struct Iter<I>(I);
|
struct Iter<I>(I);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ compile-flags: -Copt-level=0
|
//@ compile-flags: -Copt-level=0
|
||||||
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
|
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
|
||||||
//~^^^ ERROR overflow evaluating the requirement
|
|
||||||
//@ ignore-compare-mode-next-solver (hangs)
|
//@ ignore-compare-mode-next-solver (hangs)
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -9,6 +8,8 @@ fn main() {
|
|||||||
func(&mut iter)
|
func(&mut iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func<T: Iterator<Item = u8>>(iter: &mut T) { //~ WARN function cannot return without recursing
|
fn func<T: Iterator<Item = u8>>(iter: &mut T) {
|
||||||
|
//~^ WARN function cannot return without recursing
|
||||||
func(&mut iter.map(|x| x + 1))
|
func(&mut iter.map(|x| x + 1))
|
||||||
|
//~^ ERROR reached the type-length limit
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
warning: function cannot return without recursing
|
warning: function cannot return without recursing
|
||||||
--> $DIR/issue-83150.rs:12:1
|
--> $DIR/issue-83150.rs:11:1
|
||||||
|
|
|
|
||||||
LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
|
LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
|
||||||
|
LL |
|
||||||
LL | func(&mut iter.map(|x| x + 1))
|
LL | func(&mut iter.map(|x| x + 1))
|
||||||
| ------------------------------ recursive call site
|
| ------------------------------ recursive call site
|
||||||
|
|
|
|
||||||
= help: a `loop` may express intention better if this is on purpose
|
= help: a `loop` may express intention better if this is on purpose
|
||||||
= note: `#[warn(unconditional_recursion)]` on by default
|
= note: `#[warn(unconditional_recursion)]` on by default
|
||||||
|
|
||||||
error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>: Iterator`
|
error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>`
|
||||||
|
--> $DIR/issue-83150.rs:13:15
|
||||||
|
|
|
|
||||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
|
LL | func(&mut iter.map(|x| x + 1))
|
||||||
= note: required for `&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator`
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
= note: 65 redundant requirements hidden
|
|
|
||||||
= note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator`
|
= help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate
|
||||||
|
= note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt'
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 1 warning emitted
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0275`.
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ compile-flags: -Zinline-mir=no
|
//@ compile-flags: -Zinline-mir=no
|
||||||
//@ error-pattern: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
|
|
||||||
//@ error-pattern: function cannot return without recursing
|
|
||||||
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
|
|
||||||
//@ ignore-compare-mode-next-solver (hangs)
|
|
||||||
|
|
||||||
// Regression test for #91949.
|
// Regression test for #91949.
|
||||||
// This hanged *forever* on 1.56, fixed by #90423.
|
// This hanged *forever* on 1.56, fixed by #90423.
|
||||||
@ -22,10 +18,12 @@ impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn recurse<T>(elements: T) -> Vec<char>
|
fn recurse<T>(elements: T) -> Vec<char>
|
||||||
|
//~^ WARN function cannot return without recursing
|
||||||
where
|
where
|
||||||
T: Iterator<Item = ()>,
|
T: Iterator<Item = ()>,
|
||||||
{
|
{
|
||||||
recurse(IteratorOfWrapped(elements).map(|t| t.0))
|
recurse(IteratorOfWrapped(elements).map(|t| t.0))
|
||||||
|
//~^ ERROR reached the type-length limit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,7 +1,6 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ error-pattern: reached the type-length limit while instantiating
|
|
||||||
//@ compile-flags: -Copt-level=0
|
//@ compile-flags: -Copt-level=0
|
||||||
//@ normalize-stderr-test: ".nll/" -> "/"
|
//~^^ ERROR reached the type-length limit
|
||||||
|
|
||||||
// Test that the type length limit can be changed.
|
// Test that the type length limit can be changed.
|
||||||
// The exact type depends on optimizations, so disable them.
|
// The exact type depends on optimizations, so disable them.
|
||||||
@ -31,4 +30,5 @@ pub struct G<T, K>(std::marker::PhantomData::<(T, K)>);
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
drop::<Option<A>>(None);
|
drop::<Option<A>>(None);
|
||||||
|
//~^ ERROR reached the type-length limit
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((..., ..., ...), ..., ...), ..., ...), ..., ...)>>`
|
error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((..., ..., ...), ..., ...), ..., ...), ..., ...)>>`
|
||||||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
--> $DIR/type_length_limit.rs:32:5
|
||||||
|
|
|
|
||||||
= help: consider adding a `#![type_length_limit="10"]` attribute to your crate
|
LL | drop::<Option<A>>(None);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a `#![type_length_limit="4010"]` attribute to your crate
|
||||||
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut`
|
||||||
|
|
|
||||||
|
= help: consider adding a `#![type_length_limit="10"]` attribute to your crate
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user