Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::num::NonZero;
use std::ops::DerefMut;
use std::path::{Path, PathBuf};
use std::thread::ThreadId;
use std::{assert_matches, fmt, panic};
use std::{assert_matches, fmt, mem, panic};

use Level::*;
// Used by external projects such as `rust-gpu`.
Expand Down Expand Up @@ -336,6 +336,15 @@ struct DiagCtxtInner {
/// twice.
emitted_diagnostics: FxHashSet<Hash128>,

/// We only want to emit `recursion_depth_exceeding_limit` once per
/// crate. Otherwise crates like `calimero-store` emit more than
/// a thousand warnings.
///
/// We only check this in `TRACK_DIAGNOSTIC` meaning that the diagnostics
/// still get tracked by the query system, even if they don't get emitted
/// to users.
emitted_recursion_depth_exceeding_limit: bool,

/// Stashed diagnostics emitted in one stage of the compiler that may be
/// stolen and emitted/cancelled by other stages (e.g. to improve them and
/// add more information). All stashed diagnostics must be emitted with
Expand Down Expand Up @@ -527,6 +536,7 @@ impl DiagCtxt {
taught_diagnostics,
emitted_diagnostic_codes,
emitted_diagnostics,
emitted_recursion_depth_exceeding_limit,
stashed_diagnostics,
future_breakage_diagnostics,
fulfilled_expectations,
Expand All @@ -547,6 +557,7 @@ impl DiagCtxt {
*taught_diagnostics = Default::default();
*emitted_diagnostic_codes = Default::default();
*emitted_diagnostics = Default::default();
*emitted_recursion_depth_exceeding_limit = false;
*stashed_diagnostics = Default::default();
*future_breakage_diagnostics = Default::default();
*fulfilled_expectations = Default::default();
Expand Down Expand Up @@ -879,7 +890,7 @@ impl<'a> DiagCtxtHandle<'a> {

pub fn emit_future_breakage_report(&self) {
let inner = &mut *self.inner.borrow_mut();
let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
let diags = mem::take(&mut inner.future_breakage_diagnostics);
if !diags.is_empty() {
inner.emitter.emit_future_breakage_report(diags);
}
Expand Down Expand Up @@ -919,7 +930,7 @@ impl<'a> DiagCtxtHandle<'a> {
/// [`DiagCtxtInner`] and indicate that the linked expectation has been fulfilled.
#[must_use]
pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
}

/// Trigger an ICE if there are any delayed bugs and no hard errors.
Expand Down Expand Up @@ -1195,6 +1206,7 @@ impl DiagCtxtInner {
taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(),
emitted_diagnostics: Default::default(),
emitted_recursion_depth_exceeding_limit: false,
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
fulfilled_expectations: Default::default(),
Expand All @@ -1207,7 +1219,7 @@ impl DiagCtxtInner {
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
let mut guar = None;
let has_errors = !self.err_guars.is_empty();
for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
for (_, stashed_diagnostics) in mem::take(&mut self.stashed_diagnostics).into_iter() {
for (_, (diag, _guar, _thread)) in stashed_diagnostics {
if !diag.is_error() {
// Unless they're forced, don't flush stashed warnings when
Expand Down Expand Up @@ -1334,10 +1346,19 @@ impl DiagCtxtInner {

let is_error = diagnostic.is_error();
let is_lint = diagnostic.is_lint.is_some();
// We only emit the first occurrence of `recursion_depth_exceeding_limit`.
let silence_recursion_depth_exceeded_limit =
diagnostic.is_lint.as_ref().is_some_and(|lint| {
lint.name.eq_ignore_ascii_case(
rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT.name,
) && mem::replace(&mut self.emitted_recursion_depth_exceeding_limit, true)
});

// Only emit the diagnostic if we've been asked to deduplicate or
// haven't already emitted an equivalent diagnostic.
if !(self.flags.deduplicate_diagnostics && already_emitted) {
if !silence_recursion_depth_exceeded_limit
&& !(self.flags.deduplicate_diagnostics && already_emitted)
{
debug!(?diagnostic);
debug!(?self.emitted_diagnostics);

Expand Down Expand Up @@ -1460,8 +1481,7 @@ impl DiagCtxtInner {
return;
}

let bugs: Vec<_> =
std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
let bugs: Vec<_> = mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();

let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
let decorate = backtrace || self.ice_file.is_none();
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl<'tcx> InferCtxt<'tcx> {
.placeholder_assumptions_for_next_solver
.clone(),
next_trait_solver: self.next_trait_solver,
enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw,
enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(),
obligation_inspector: self.obligation_inspector.clone(),
canonicalizer_state: Default::default(),
}
Expand Down Expand Up @@ -115,7 +115,7 @@ impl<'tcx> InferCtxt<'tcx> {
.placeholder_assumptions_for_next_solver
.clone(),
next_trait_solver: self.next_trait_solver,
enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw,
enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(),
obligation_inspector: self.obligation_inspector.clone(),
canonicalizer_state: Default::default(),
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
}

fn enable_next_solver_overflow_fcw(&self) -> bool {
self.enable_next_solver_overflow_fcw
self.enable_next_solver_overflow_fcw.get()
}

fn disable_trait_solver_fast_paths(&self) -> bool {
Expand Down
16 changes: 14 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ pub struct InferCtxt<'tcx> {
/// already used by default in some places so we know they won't have
/// additional breakages. We also don't want spurious result in coherence
/// checking so we disable the FCW there as well.
enable_next_solver_overflow_fcw: bool,
enable_next_solver_overflow_fcw: Cell<bool>,

pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>,

Expand Down Expand Up @@ -691,7 +691,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
universe: Cell::new(ty::UniverseIndex::ROOT),
placeholder_assumptions_for_next_solver: RefCell::new(Default::default()),
next_trait_solver,
enable_next_solver_overflow_fcw,
enable_next_solver_overflow_fcw: Cell::new(enable_next_solver_overflow_fcw),
obligation_inspector: Cell::new(None),
canonicalizer_state: Default::default(),
}
Expand Down Expand Up @@ -1556,6 +1556,18 @@ impl<'tcx> InferCtxt<'tcx> {
u
}

/// We need to disable the fcw if we're already in a fcw emitting to avoid
/// indefinite triggering.
pub fn with_disabled_next_solver_overflow_fcw<F, R>(&self, mut f: F) -> R
where
F: FnMut() -> R,
{
let prev = self.enable_next_solver_overflow_fcw.replace(false);
let ret = f();
self.enable_next_solver_overflow_fcw.set(prev);
ret
}

/// Extract [`ty::TypingMode`] of this inference context to get a `TypingEnv`
/// which contains the necessary information to use the trait system without
/// using canonicalization or carrying this inference context around.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ use crate::ty::print::PrintTraitRefExt;
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{
self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput,
SizedTraitKind, Ty, TyCtxt, TyCtxtFeed,
RequiredDepth, SizedTraitKind, Ty, TyCtxt, TyCtxtFeed,
};
use crate::{mir, thir};

Expand Down Expand Up @@ -2643,7 +2643,7 @@ rustc_queries! {
/// Used by `-Znext-solver` to compute proof trees.
query evaluate_root_goal_for_proof_tree_raw(
key: (solve::CanonicalInput<'tcx>, usize)
) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe<TyCtxt<'tcx>>) {
) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe<TyCtxt<'tcx>>, RequiredDepth) {
no_hash
desc { "computing proof tree for `{}` with depth `{}`", key.0.canonical.value.goal.predicate, key.1 }
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl_erasable_for_types_with_no_type_params! {
// tidy-alphabetical-start
(&'_ ty::CrateInherentImpls, Result<(), ErrorGuaranteed>),
(),
(traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe<TyCtxt<'_>>),
(traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe<TyCtxt<'_>>, ty::RequiredDepth),
Option<&'_ OsStr>,
Option<&'_ [rustc_hir::PreciseCapturingArgKind<rustc_span::Symbol, rustc_span::Symbol>]>,
Option<(mir::ConstValue, Ty<'_>)>,
Expand Down
47 changes: 4 additions & 43 deletions compiler/rustc_middle/src/ty/context/impl_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@ use std::{debug_assert_matches, fmt};
use rustc_data_structures::intern::Interned;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::CRATE_HIR_ID;
use rustc_hir::attrs::lang_items::LangItem;
use rustc_hir::def::{CtorKind, DefKind, Namespace};
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT;
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_structures::Limit;
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem};
use rustc_type_ir::{
BoundVar, CollectAndApply, DebruijnIndex, Interner, TypeFoldable, Unnormalized, VisitorResult,
Expand All @@ -24,10 +21,9 @@ use crate::traits::cache::WithDepNode;
use crate::traits::solve::{
self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect,
};
use crate::ty::print::{FmtPrinter, Print};
use crate::ty::{
self, BoundRegion, Clause, Const, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate,
Region, RegionKind, Ty, TyCtxt,
Region, RegionKind, RequiredDepth, Ty, TyCtxt,
};

#[allow(rustc::usage_of_ty_tykind)]
Expand Down Expand Up @@ -672,45 +668,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self,
canonical_goal: CanonicalInput<'tcx>,
root_depth: usize,
) -> (QueryResult<'tcx>, &'tcx inspect::Probe<TyCtxt<'tcx>>) {
) -> (QueryResult<'tcx>, &'tcx inspect::Probe<TyCtxt<'tcx>>, RequiredDepth) {
self.evaluate_root_goal_for_proof_tree_raw((canonical_goal, root_depth))
}

fn emit_next_solver_overflow_fcw(self, predicate: ty::Predicate<'tcx>, span: Span) {
self.emit_node_span_lint(
RECURSION_DEPTH_EXCEEDING_LIMIT,
CRATE_HIR_ID,
span,
rustc_errors::DiagDecorator(|diag| {
// FIXME: share this with overflow error in fulfillment instead of duplicating.
let pred_str = {
let s = predicate.to_string();
if s.len() > 50 {
let mut p: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(self, Namespace::TypeNS, Limit(6));
predicate.print(&mut p).unwrap();
p.into_buffer()
} else {
s
}
};
diag.primary_message(format!(
"overflow evaluating the requirement `{pred_str}`",
));
diag.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
self.recursion_limit() * 2,
self.crate_name(LOCAL_CRATE),
));
diag.help(
"or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved",
);
diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis");
}),
)
}

fn item_name(self, id: DefId) -> Symbol {
self.opt_item_name(id).unwrap_or_else(|| {
bug!("item_name: no name for {:?}", self.def_path(id));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use rustc_target::callconv::FnAbi;
pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet};
pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::search_graph::RequiredDepth;
pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleForLeakCheck};
pub use rustc_type_ir::*;
use tracing::{debug, instrument};
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_next_trait_solver/src/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,10 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
/// Release canonicalizer state, either by deallocating it (the default) or by clearing it and
/// stashing it for later reuse.
fn release_canonicalizer_state(&self, _: CanonicalizerState<Self::Interner>) {}

fn emit_next_solver_overflow_fcw(
&self,
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
span: <Self::Interner as Interner>::Span,
);
}
Loading
Loading