| author | bors <bors@rust-lang.org> 2026-03-13 07:28:46 UTC |
| committer | bors <bors@rust-lang.org> 2026-03-13 07:28:46 UTC |
| log | eaf4e7489b6ae3d4ba9a71b720b03b6d58e4f102 |
| tree | 5e9930f4c37dbb927a7b46accf8981b5338426d6 |
| parent | 7ad5c602172b132646213941b5102a75a77c10f6 |
| parent | 03e3b1ee7549a41fab5793fc1486d09ab03cc6fa |
Rollup of 3 pull requests
Successful merges:
- rust-lang/rust#153792 (tests/debuginfo/basic-stepping.rs: Add lldb test)
- rust-lang/rust#153492 (Add a `TaggedQueryKey` to identify a query instance)
- rust-lang/rust#153808 (rustfmt.toml: drop ignore of deleted test)13 files changed, 195 insertions(+), 224 deletions(-)
Cargo.lock-1| ... | ... | @@ -4575,7 +4575,6 @@ dependencies = [ |
| 4575 | 4575 | "rustc_macros", |
| 4576 | 4576 | "rustc_middle", |
| 4577 | 4577 | "rustc_serialize", |
| 4578 | "rustc_session", | |
| 4579 | 4578 | "rustc_span", |
| 4580 | 4579 | "rustc_thread_pool", |
| 4581 | 4580 | "tracing", |
compiler/rustc_middle/src/query/job.rs+5-11| ... | ... | @@ -7,21 +7,15 @@ use parking_lot::{Condvar, Mutex}; |
| 7 | 7 | use rustc_span::Span; |
| 8 | 8 | |
| 9 | 9 | use crate::query::plumbing::CycleError; |
| 10 | use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; | |
| 10 | use crate::query::stack::QueryStackFrame; | |
| 11 | 11 | use crate::ty::TyCtxt; |
| 12 | 12 | |
| 13 | 13 | /// Represents a span and a query key. |
| 14 | 14 | #[derive(Clone, Debug)] |
| 15 | pub struct QueryInfo<I> { | |
| 15 | pub struct QueryInfo<'tcx> { | |
| 16 | 16 | /// The span corresponding to the reason for which this query was required. |
| 17 | 17 | pub span: Span, |
| 18 | pub frame: QueryStackFrame<I>, | |
| 19 | } | |
| 20 | ||
| 21 | impl<'tcx> QueryInfo<QueryStackDeferred<'tcx>> { | |
| 22 | pub(crate) fn lift(&self) -> QueryInfo<QueryStackFrameExtra> { | |
| 23 | QueryInfo { span: self.span, frame: self.frame.lift() } | |
| 24 | } | |
| 18 | pub frame: QueryStackFrame<'tcx>, | |
| 25 | 19 | } |
| 26 | 20 | |
| 27 | 21 | /// A value uniquely identifying an active query job. |
| ... | ... | @@ -74,7 +68,7 @@ pub struct QueryWaiter<'tcx> { |
| 74 | 68 | pub query: Option<QueryJobId>, |
| 75 | 69 | pub condvar: Condvar, |
| 76 | 70 | pub span: Span, |
| 77 | pub cycle: Mutex<Option<CycleError<QueryStackDeferred<'tcx>>>>, | |
| 71 | pub cycle: Mutex<Option<CycleError<'tcx>>>, | |
| 78 | 72 | } |
| 79 | 73 | |
| 80 | 74 | #[derive(Clone, Debug)] |
| ... | ... | @@ -94,7 +88,7 @@ impl<'tcx> QueryLatch<'tcx> { |
| 94 | 88 | tcx: TyCtxt<'tcx>, |
| 95 | 89 | query: Option<QueryJobId>, |
| 96 | 90 | span: Span, |
| 97 | ) -> Result<(), CycleError<QueryStackDeferred<'tcx>>> { | |
| 91 | ) -> Result<(), CycleError<'tcx>> { | |
| 98 | 92 | let mut waiters_guard = self.waiters.lock(); |
| 99 | 93 | let Some(waiters) = &mut *waiters_guard else { |
| 100 | 94 | return Ok(()); // already complete |
compiler/rustc_middle/src/query/mod.rs+1-1| ... | ... | @@ -7,7 +7,7 @@ pub use self::plumbing::{ |
| 7 | 7 | ActiveKeyStatus, CycleError, CycleErrorHandling, EnsureMode, IntoQueryParam, QueryMode, |
| 8 | 8 | QueryState, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult, |
| 9 | 9 | }; |
| 10 | pub use self::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; | |
| 10 | pub use self::stack::QueryStackFrame; | |
| 11 | 11 | pub use crate::queries::Providers; |
| 12 | 12 | use crate::ty::TyCtxt; |
| 13 | 13 |
compiler/rustc_middle/src/query/plumbing.rs+70-20| ... | ... | @@ -12,9 +12,9 @@ pub use sealed::IntoQueryParam; |
| 12 | 12 | |
| 13 | 13 | use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; |
| 14 | 14 | use crate::ich::StableHashingContext; |
| 15 | use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables}; | |
| 15 | use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey}; | |
| 16 | 16 | use crate::query::on_disk_cache::OnDiskCache; |
| 17 | use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; | |
| 17 | use crate::query::stack::QueryStackFrame; | |
| 18 | 18 | use crate::query::{QueryCache, QueryInfo, QueryJob}; |
| 19 | 19 | use crate::ty::TyCtxt; |
| 20 | 20 | |
| ... | ... | @@ -60,19 +60,10 @@ pub enum CycleErrorHandling { |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | #[derive(Clone, Debug)] |
| 63 | pub struct CycleError<I = QueryStackFrameExtra> { | |
| 63 | pub struct CycleError<'tcx> { | |
| 64 | 64 | /// The query and related span that uses the cycle. |
| 65 | pub usage: Option<(Span, QueryStackFrame<I>)>, | |
| 66 | pub cycle: Vec<QueryInfo<I>>, | |
| 67 | } | |
| 68 | ||
| 69 | impl<'tcx> CycleError<QueryStackDeferred<'tcx>> { | |
| 70 | pub fn lift(&self) -> CycleError<QueryStackFrameExtra> { | |
| 71 | CycleError { | |
| 72 | usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift())), | |
| 73 | cycle: self.cycle.iter().map(|info| info.lift()).collect(), | |
| 74 | } | |
| 75 | } | |
| 65 | pub usage: Option<(Span, QueryStackFrame<'tcx>)>, | |
| 66 | pub cycle: Vec<QueryInfo<'tcx>>, | |
| 76 | 67 | } |
| 77 | 68 | |
| 78 | 69 | #[derive(Debug)] |
| ... | ... | @@ -139,16 +130,12 @@ pub struct QueryVTable<'tcx, C: QueryCache> { |
| 139 | 130 | pub value_from_cycle_error: fn( |
| 140 | 131 | tcx: TyCtxt<'tcx>, |
| 141 | 132 | key: C::Key, |
| 142 | cycle_error: CycleError, | |
| 133 | cycle_error: CycleError<'tcx>, | |
| 143 | 134 | guar: ErrorGuaranteed, |
| 144 | 135 | ) -> C::Value, |
| 145 | 136 | pub format_value: fn(&C::Value) -> String, |
| 146 | 137 | |
| 147 | /// Formats a human-readable description of this query and its key, as | |
| 148 | /// specified by the `desc` query modifier. | |
| 149 | /// | |
| 150 | /// Used when reporting query cycle errors and similar problems. | |
| 151 | pub description_fn: fn(TyCtxt<'tcx>, C::Key) -> String, | |
| 138 | pub create_tagged_key: fn(C::Key) -> TaggedQueryKey<'tcx>, | |
| 152 | 139 | |
| 153 | 140 | /// Function pointer that is called by the query methods on [`TyCtxt`] and |
| 154 | 141 | /// friends[^1], after they have checked the in-memory cache and found no |
| ... | ... | @@ -523,6 +510,69 @@ macro_rules! define_callbacks { |
| 523 | 510 | } |
| 524 | 511 | )* |
| 525 | 512 | |
| 513 | /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number. | |
| 514 | #[allow(non_camel_case_types)] | |
| 515 | #[derive(Clone, Debug)] | |
| 516 | pub enum TaggedQueryKey<'tcx> { | |
| 517 | $( | |
| 518 | $name($name::Key<'tcx>), | |
| 519 | )* | |
| 520 | } | |
| 521 | ||
| 522 | impl<'tcx> TaggedQueryKey<'tcx> { | |
| 523 | /// Formats a human-readable description of this query and its key, as | |
| 524 | /// specified by the `desc` query modifier. | |
| 525 | /// | |
| 526 | /// Used when reporting query cycle errors and similar problems. | |
| 527 | pub fn description(&self, tcx: TyCtxt<'tcx>) -> String { | |
| 528 | let (name, description) = ty::print::with_no_queries!(match self { | |
| 529 | $( | |
| 530 | TaggedQueryKey::$name(key) => (stringify!($name), _description_fns::$name(tcx, *key)), | |
| 531 | )* | |
| 532 | }); | |
| 533 | if tcx.sess.verbose_internals() { | |
| 534 | format!("{description} [{name:?}]") | |
| 535 | } else { | |
| 536 | description | |
| 537 | } | |
| 538 | } | |
| 539 | ||
| 540 | /// Returns the default span for this query if `span` is a dummy span. | |
| 541 | pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span { | |
| 542 | if !span.is_dummy() { | |
| 543 | return span | |
| 544 | } | |
| 545 | if let TaggedQueryKey::def_span(..) = self { | |
| 546 | // The `def_span` query is used to calculate `default_span`, | |
| 547 | // so exit to avoid infinite recursion. | |
| 548 | return DUMMY_SP | |
| 549 | } | |
| 550 | match self { | |
| 551 | $( | |
| 552 | TaggedQueryKey::$name(key) => crate::query::QueryKey::default_span(key, tcx), | |
| 553 | )* | |
| 554 | } | |
| 555 | } | |
| 556 | ||
| 557 | pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> { | |
| 558 | // This is used to reduce code generation as it | |
| 559 | // can be reused for queries with the same key type. | |
| 560 | fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<DefKind> { | |
| 561 | key.key_as_def_id().and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) | |
| 562 | } | |
| 563 | ||
| 564 | if let TaggedQueryKey::def_kind(..) = self { | |
| 565 | // Try to avoid infinite recursion. | |
| 566 | return None | |
| 567 | } | |
| 568 | match self { | |
| 569 | $( | |
| 570 | TaggedQueryKey::$name(key) => inner(key, tcx), | |
| 571 | )* | |
| 572 | } | |
| 573 | } | |
| 574 | } | |
| 575 | ||
| 526 | 576 | /// Holds a `QueryVTable` for each query. |
| 527 | 577 | pub struct QueryVTables<'tcx> { |
| 528 | 578 | $( |
compiler/rustc_middle/src/query/stack.rs+3-91| ... | ... | @@ -1,106 +1,18 @@ |
| 1 | 1 | use std::fmt::Debug; |
| 2 | use std::marker::PhantomData; | |
| 3 | use std::mem::transmute; | |
| 4 | use std::sync::Arc; | |
| 5 | 2 | |
| 6 | use rustc_data_structures::sync::{DynSend, DynSync}; | |
| 7 | use rustc_hir::def::DefKind; | |
| 8 | use rustc_span::Span; | |
| 9 | 3 | use rustc_span::def_id::DefId; |
| 10 | 4 | |
| 11 | 5 | use crate::dep_graph::DepKind; |
| 6 | use crate::queries::TaggedQueryKey; | |
| 12 | 7 | |
| 13 | 8 | /// Description of a frame in the query stack. |
| 14 | 9 | /// |
| 15 | 10 | /// This is mostly used in case of cycles for error reporting. |
| 16 | 11 | #[derive(Clone, Debug)] |
| 17 | pub struct QueryStackFrame<I> { | |
| 18 | /// This field initially stores a `QueryStackDeferred` during collection, | |
| 19 | /// but can later be changed to `QueryStackFrameExtra` containing concrete information | |
| 20 | /// by calling `lift`. This is done so that collecting query does not need to invoke | |
| 21 | /// queries, instead `lift` will call queries in a more appropriate location. | |
| 22 | pub info: I, | |
| 23 | ||
| 12 | pub struct QueryStackFrame<'tcx> { | |
| 13 | pub tagged_key: TaggedQueryKey<'tcx>, | |
| 24 | 14 | pub dep_kind: DepKind, |
| 25 | 15 | pub def_id: Option<DefId>, |
| 26 | 16 | /// A def-id that is extracted from a `Ty` in a query key |
| 27 | 17 | pub def_id_for_ty_in_cycle: Option<DefId>, |
| 28 | 18 | } |
| 29 | ||
| 30 | impl<'tcx> QueryStackFrame<QueryStackDeferred<'tcx>> { | |
| 31 | #[inline] | |
| 32 | pub fn new( | |
| 33 | info: QueryStackDeferred<'tcx>, | |
| 34 | dep_kind: DepKind, | |
| 35 | def_id: Option<DefId>, | |
| 36 | def_id_for_ty_in_cycle: Option<DefId>, | |
| 37 | ) -> Self { | |
| 38 | Self { info, def_id, dep_kind, def_id_for_ty_in_cycle } | |
| 39 | } | |
| 40 | ||
| 41 | pub fn lift(&self) -> QueryStackFrame<QueryStackFrameExtra> { | |
| 42 | QueryStackFrame { | |
| 43 | info: self.info.extract(), | |
| 44 | dep_kind: self.dep_kind, | |
| 45 | def_id: self.def_id, | |
| 46 | def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, | |
| 47 | } | |
| 48 | } | |
| 49 | } | |
| 50 | ||
| 51 | #[derive(Clone, Debug)] | |
| 52 | pub struct QueryStackFrameExtra { | |
| 53 | pub description: String, | |
| 54 | pub span: Option<Span>, | |
| 55 | pub def_kind: Option<DefKind>, | |
| 56 | } | |
| 57 | ||
| 58 | impl QueryStackFrameExtra { | |
| 59 | #[inline] | |
| 60 | pub fn new(description: String, span: Option<Span>, def_kind: Option<DefKind>) -> Self { | |
| 61 | Self { description, span, def_kind } | |
| 62 | } | |
| 63 | ||
| 64 | // FIXME(eddyb) Get more valid `Span`s on queries. | |
| 65 | #[inline] | |
| 66 | pub fn default_span(&self, span: Span) -> Span { | |
| 67 | if !span.is_dummy() { | |
| 68 | return span; | |
| 69 | } | |
| 70 | self.span.unwrap_or(span) | |
| 71 | } | |
| 72 | } | |
| 73 | ||
| 74 | /// Track a 'side effect' for a particular query. | |
| 75 | /// This is used to hold a closure which can create `QueryStackFrameExtra`. | |
| 76 | #[derive(Clone)] | |
| 77 | pub struct QueryStackDeferred<'tcx> { | |
| 78 | _dummy: PhantomData<&'tcx ()>, | |
| 79 | ||
| 80 | // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't | |
| 81 | // access it in the destructor. | |
| 82 | extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend>, | |
| 83 | } | |
| 84 | ||
| 85 | impl<'tcx> QueryStackDeferred<'tcx> { | |
| 86 | pub fn new<C: Copy + DynSync + DynSend + 'tcx>( | |
| 87 | context: C, | |
| 88 | extract: fn(C) -> QueryStackFrameExtra, | |
| 89 | ) -> Self { | |
| 90 | let extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend + 'tcx> = | |
| 91 | Arc::new(move || extract(context)); | |
| 92 | // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only | |
| 93 | // captured variable is `context` which is Copy and cannot have a destructor. | |
| 94 | Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } | |
| 95 | } | |
| 96 | ||
| 97 | pub fn extract(&self) -> QueryStackFrameExtra { | |
| 98 | (self.extract)() | |
| 99 | } | |
| 100 | } | |
| 101 | ||
| 102 | impl<'tcx> Debug for QueryStackDeferred<'tcx> { | |
| 103 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| 104 | f.write_str("QueryStackDeferred") | |
| 105 | } | |
| 106 | } |
compiler/rustc_query_impl/Cargo.toml-1| ... | ... | @@ -14,7 +14,6 @@ rustc_index = { path = "../rustc_index" } |
| 14 | 14 | rustc_macros = { path = "../rustc_macros" } |
| 15 | 15 | rustc_middle = { path = "../rustc_middle" } |
| 16 | 16 | rustc_serialize = { path = "../rustc_serialize" } |
| 17 | rustc_session = { path = "../rustc_session" } | |
| 18 | 17 | rustc_span = { path = "../rustc_span" } |
| 19 | 18 | rustc_thread_pool = { path = "../rustc_thread_pool" } |
| 20 | 19 | tracing = "0.1" |
compiler/rustc_query_impl/src/execution.rs+6-7| ... | ... | @@ -48,7 +48,7 @@ pub fn collect_active_jobs_from_all_queries<'tcx>( |
| 48 | 48 | let mut complete = true; |
| 49 | 49 | |
| 50 | 50 | for_each_query_vtable!(ALL, tcx, |query| { |
| 51 | let res = gather_active_jobs(query, tcx, require_complete, &mut job_map_out); | |
| 51 | let res = gather_active_jobs(query, require_complete, &mut job_map_out); | |
| 52 | 52 | if res.is_none() { |
| 53 | 53 | complete = false; |
| 54 | 54 | } |
| ... | ... | @@ -66,7 +66,6 @@ pub fn collect_active_jobs_from_all_queries<'tcx>( |
| 66 | 66 | /// grep for.) |
| 67 | 67 | fn gather_active_jobs<'tcx, C>( |
| 68 | 68 | query: &'tcx QueryVTable<'tcx, C>, |
| 69 | tcx: TyCtxt<'tcx>, | |
| 70 | 69 | require_complete: bool, |
| 71 | 70 | job_map_out: &mut QueryJobMap<'tcx>, // Out-param; job info is gathered into this map |
| 72 | 71 | ) -> Option<()> |
| ... | ... | @@ -113,7 +112,7 @@ where |
| 113 | 112 | // Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call |
| 114 | 113 | // queries leading to a deadlock. |
| 115 | 114 | for (key, job) in active { |
| 116 | let frame = crate::plumbing::create_deferred_query_stack_frame(tcx, query, key); | |
| 115 | let frame = crate::plumbing::create_query_stack_frame(query, key); | |
| 117 | 116 | job_map_out.insert(job.id, QueryJobInfo { frame, job }); |
| 118 | 117 | } |
| 119 | 118 | |
| ... | ... | @@ -126,9 +125,9 @@ fn mk_cycle<'tcx, C: QueryCache>( |
| 126 | 125 | query: &'tcx QueryVTable<'tcx, C>, |
| 127 | 126 | tcx: TyCtxt<'tcx>, |
| 128 | 127 | key: C::Key, |
| 129 | cycle_error: CycleError, | |
| 128 | cycle_error: CycleError<'tcx>, | |
| 130 | 129 | ) -> C::Value { |
| 131 | let error = report_cycle(tcx.sess, &cycle_error); | |
| 130 | let error = report_cycle(tcx, &cycle_error); | |
| 132 | 131 | match query.cycle_error_handling { |
| 133 | 132 | CycleErrorHandling::Error => { |
| 134 | 133 | let guar = error.emit(); |
| ... | ... | @@ -231,7 +230,7 @@ fn cycle_error<'tcx, C: QueryCache>( |
| 231 | 230 | .expect("failed to collect active queries"); |
| 232 | 231 | |
| 233 | 232 | let error = find_cycle_in_stack(try_execute, job_map, &current_query_job(), span); |
| 234 | (mk_cycle(query, tcx, key, error.lift()), None) | |
| 233 | (mk_cycle(query, tcx, key, error), None) | |
| 235 | 234 | } |
| 236 | 235 | |
| 237 | 236 | #[inline(always)] |
| ... | ... | @@ -275,7 +274,7 @@ fn wait_for_query<'tcx, C: QueryCache>( |
| 275 | 274 | |
| 276 | 275 | (v, Some(index)) |
| 277 | 276 | } |
| 278 | Err(cycle) => (mk_cycle(query, tcx, key, cycle.lift()), None), | |
| 277 | Err(cycle) => (mk_cycle(query, tcx, key, cycle), None), | |
| 279 | 278 | } |
| 280 | 279 | } |
| 281 | 280 |
compiler/rustc_query_impl/src/from_cycle_error.rs+11-7| ... | ... | @@ -45,7 +45,11 @@ pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { |
| 45 | 45 | |tcx, _, cycle, guar| erase_val(layout_of(tcx, cycle, guar)); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | pub(crate) fn default<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError, query_name: &str) -> ! { | |
| 48 | pub(crate) fn default<'tcx>( | |
| 49 | tcx: TyCtxt<'tcx>, | |
| 50 | cycle_error: CycleError<'tcx>, | |
| 51 | query_name: &str, | |
| 52 | ) -> ! { | |
| 49 | 53 | let Some(guar) = tcx.sess.dcx().has_errors() else { |
| 50 | 54 | bug!( |
| 51 | 55 | "`from_cycle_error_default` on query `{query_name}` called without errors: {:#?}", |
| ... | ... | @@ -82,7 +86,7 @@ fn fn_sig<'tcx>( |
| 82 | 86 | |
| 83 | 87 | fn check_representability<'tcx>( |
| 84 | 88 | tcx: TyCtxt<'tcx>, |
| 85 | cycle_error: CycleError, | |
| 89 | cycle_error: CycleError<'tcx>, | |
| 86 | 90 | _guar: ErrorGuaranteed, |
| 87 | 91 | ) -> ! { |
| 88 | 92 | let mut item_and_field_ids = Vec::new(); |
| ... | ... | @@ -91,7 +95,7 @@ fn check_representability<'tcx>( |
| 91 | 95 | if info.frame.dep_kind == DepKind::check_representability |
| 92 | 96 | && let Some(field_id) = info.frame.def_id |
| 93 | 97 | && let Some(field_id) = field_id.as_local() |
| 94 | && let Some(DefKind::Field) = info.frame.info.def_kind | |
| 98 | && let Some(DefKind::Field) = info.frame.tagged_key.def_kind(tcx) | |
| 95 | 99 | { |
| 96 | 100 | let parent_id = tcx.parent(field_id.to_def_id()); |
| 97 | 101 | let item_id = match tcx.def_kind(parent_id) { |
| ... | ... | @@ -118,7 +122,7 @@ fn check_representability<'tcx>( |
| 118 | 122 | |
| 119 | 123 | fn variances_of<'tcx>( |
| 120 | 124 | tcx: TyCtxt<'tcx>, |
| 121 | cycle_error: CycleError, | |
| 125 | cycle_error: CycleError<'tcx>, | |
| 122 | 126 | _guar: ErrorGuaranteed, |
| 123 | 127 | ) -> &'tcx [ty::Variance] { |
| 124 | 128 | search_for_cycle_permutation( |
| ... | ... | @@ -164,7 +168,7 @@ fn search_for_cycle_permutation<Q, T>( |
| 164 | 168 | |
| 165 | 169 | fn layout_of<'tcx>( |
| 166 | 170 | tcx: TyCtxt<'tcx>, |
| 167 | cycle_error: CycleError, | |
| 171 | cycle_error: CycleError<'tcx>, | |
| 168 | 172 | _guar: ErrorGuaranteed, |
| 169 | 173 | ) -> Result<TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> { |
| 170 | 174 | let diag = search_for_cycle_permutation( |
| ... | ... | @@ -205,7 +209,7 @@ fn layout_of<'tcx>( |
| 205 | 209 | continue; |
| 206 | 210 | }; |
| 207 | 211 | let frame_span = |
| 208 | info.frame.info.default_span(cycle[(i + 1) % cycle.len()].span); | |
| 212 | info.frame.tagged_key.default_span(tcx, cycle[(i + 1) % cycle.len()].span); | |
| 209 | 213 | if frame_span.is_dummy() { |
| 210 | 214 | continue; |
| 211 | 215 | } |
| ... | ... | @@ -239,7 +243,7 @@ fn layout_of<'tcx>( |
| 239 | 243 | ControlFlow::Continue(()) |
| 240 | 244 | } |
| 241 | 245 | }, |
| 242 | || report_cycle(tcx.sess, &cycle_error), | |
| 246 | || report_cycle(tcx, &cycle_error), | |
| 243 | 247 | ); |
| 244 | 248 | |
| 245 | 249 | let guar = diag.emit(); |
compiler/rustc_query_impl/src/job.rs+31-28| ... | ... | @@ -7,11 +7,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
| 7 | 7 | use rustc_errors::{Diag, DiagCtxtHandle}; |
| 8 | 8 | use rustc_hir::def::DefKind; |
| 9 | 9 | use rustc_middle::query::{ |
| 10 | CycleError, QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryStackDeferred, QueryStackFrame, | |
| 11 | QueryWaiter, | |
| 10 | CycleError, QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryStackFrame, QueryWaiter, | |
| 12 | 11 | }; |
| 13 | 12 | use rustc_middle::ty::TyCtxt; |
| 14 | use rustc_session::Session; | |
| 15 | 13 | use rustc_span::{DUMMY_SP, Span}; |
| 16 | 14 | |
| 17 | 15 | use crate::execution::collect_active_jobs_from_all_queries; |
| ... | ... | @@ -31,7 +29,7 @@ impl<'tcx> QueryJobMap<'tcx> { |
| 31 | 29 | self.map.insert(id, info); |
| 32 | 30 | } |
| 33 | 31 | |
| 34 | fn frame_of(&self, id: QueryJobId) -> &QueryStackFrame<QueryStackDeferred<'tcx>> { | |
| 32 | fn frame_of(&self, id: QueryJobId) -> &QueryStackFrame<'tcx> { | |
| 35 | 33 | &self.map[&id].frame |
| 36 | 34 | } |
| 37 | 35 | |
| ... | ... | @@ -50,7 +48,7 @@ impl<'tcx> QueryJobMap<'tcx> { |
| 50 | 48 | |
| 51 | 49 | #[derive(Clone, Debug)] |
| 52 | 50 | pub(crate) struct QueryJobInfo<'tcx> { |
| 53 | pub(crate) frame: QueryStackFrame<QueryStackDeferred<'tcx>>, | |
| 51 | pub(crate) frame: QueryStackFrame<'tcx>, | |
| 54 | 52 | pub(crate) job: QueryJob<'tcx>, |
| 55 | 53 | } |
| 56 | 54 | |
| ... | ... | @@ -59,7 +57,7 @@ pub(crate) fn find_cycle_in_stack<'tcx>( |
| 59 | 57 | job_map: QueryJobMap<'tcx>, |
| 60 | 58 | current_job: &Option<QueryJobId>, |
| 61 | 59 | span: Span, |
| 62 | ) -> CycleError<QueryStackDeferred<'tcx>> { | |
| 60 | ) -> CycleError<'tcx> { | |
| 63 | 61 | // Find the waitee amongst `current_job` parents |
| 64 | 62 | let mut cycle = Vec::new(); |
| 65 | 63 | let mut current_job = Option::clone(current_job); |
| ... | ... | @@ -395,12 +393,12 @@ pub fn print_query_stack<'tcx>( |
| 395 | 393 | let Some(query_info) = job_map.map.get(&query) else { |
| 396 | 394 | break; |
| 397 | 395 | }; |
| 398 | let query_extra = query_info.frame.info.extract(); | |
| 396 | let description = query_info.frame.tagged_key.description(tcx); | |
| 399 | 397 | if Some(count_printed) < limit_frames || limit_frames.is_none() { |
| 400 | 398 | // Only print to stderr as many stack frames as `num_frames` when present. |
| 401 | 399 | dcx.struct_failure_note(format!( |
| 402 | 400 | "#{} [{:?}] {}", |
| 403 | count_printed, query_info.frame.dep_kind, query_extra.description | |
| 401 | count_printed, query_info.frame.dep_kind, description | |
| 404 | 402 | )) |
| 405 | 403 | .with_span(query_info.job.span) |
| 406 | 404 | .emit(); |
| ... | ... | @@ -411,7 +409,7 @@ pub fn print_query_stack<'tcx>( |
| 411 | 409 | let _ = writeln!( |
| 412 | 410 | file, |
| 413 | 411 | "#{} [{:?}] {}", |
| 414 | count_total, query_info.frame.dep_kind, query_extra.description | |
| 412 | count_total, query_info.frame.dep_kind, description | |
| 415 | 413 | ); |
| 416 | 414 | } |
| 417 | 415 | |
| ... | ... | @@ -427,18 +425,18 @@ pub fn print_query_stack<'tcx>( |
| 427 | 425 | |
| 428 | 426 | #[inline(never)] |
| 429 | 427 | #[cold] |
| 430 | pub(crate) fn report_cycle<'a>( | |
| 431 | sess: &'a Session, | |
| 432 | CycleError { usage, cycle: stack }: &CycleError, | |
| 433 | ) -> Diag<'a> { | |
| 428 | pub(crate) fn report_cycle<'tcx>( | |
| 429 | tcx: TyCtxt<'tcx>, | |
| 430 | CycleError { usage, cycle: stack }: &CycleError<'tcx>, | |
| 431 | ) -> Diag<'tcx> { | |
| 434 | 432 | assert!(!stack.is_empty()); |
| 435 | 433 | |
| 436 | let span = stack[0].frame.info.default_span(stack[1 % stack.len()].span); | |
| 434 | let span = stack[0].frame.tagged_key.default_span(tcx, stack[1 % stack.len()].span); | |
| 437 | 435 | |
| 438 | 436 | let mut cycle_stack = Vec::new(); |
| 439 | 437 | |
| 440 | 438 | use crate::error::StackCount; |
| 441 | let stack_bottom = stack[0].frame.info.description.to_owned(); | |
| 439 | let stack_bottom = stack[0].frame.tagged_key.description(tcx); | |
| 442 | 440 | let stack_count = if stack.len() == 1 { |
| 443 | 441 | StackCount::Single { stack_bottom: stack_bottom.clone() } |
| 444 | 442 | } else { |
| ... | ... | @@ -447,27 +445,32 @@ pub(crate) fn report_cycle<'a>( |
| 447 | 445 | |
| 448 | 446 | for i in 1..stack.len() { |
| 449 | 447 | let frame = &stack[i].frame; |
| 450 | let span = frame.info.default_span(stack[(i + 1) % stack.len()].span); | |
| 448 | let span = frame.tagged_key.default_span(tcx, stack[(i + 1) % stack.len()].span); | |
| 451 | 449 | cycle_stack |
| 452 | .push(crate::error::CycleStack { span, desc: frame.info.description.to_owned() }); | |
| 450 | .push(crate::error::CycleStack { span, desc: frame.tagged_key.description(tcx) }); | |
| 453 | 451 | } |
| 454 | 452 | |
| 455 | 453 | let mut cycle_usage = None; |
| 456 | 454 | if let Some((span, ref query)) = *usage { |
| 457 | 455 | cycle_usage = Some(crate::error::CycleUsage { |
| 458 | span: query.info.default_span(span), | |
| 459 | usage: query.info.description.to_string(), | |
| 456 | span: query.tagged_key.default_span(tcx, span), | |
| 457 | usage: query.tagged_key.description(tcx), | |
| 460 | 458 | }); |
| 461 | 459 | } |
| 462 | 460 | |
| 463 | let alias = | |
| 464 | if stack.iter().all(|entry| matches!(entry.frame.info.def_kind, Some(DefKind::TyAlias))) { | |
| 465 | Some(crate::error::Alias::Ty) | |
| 466 | } else if stack.iter().all(|entry| entry.frame.info.def_kind == Some(DefKind::TraitAlias)) { | |
| 467 | Some(crate::error::Alias::Trait) | |
| 468 | } else { | |
| 469 | None | |
| 470 | }; | |
| 461 | let alias = if stack | |
| 462 | .iter() | |
| 463 | .all(|entry| matches!(entry.frame.tagged_key.def_kind(tcx), Some(DefKind::TyAlias))) | |
| 464 | { | |
| 465 | Some(crate::error::Alias::Ty) | |
| 466 | } else if stack | |
| 467 | .iter() | |
| 468 | .all(|entry| entry.frame.tagged_key.def_kind(tcx) == Some(DefKind::TraitAlias)) | |
| 469 | { | |
| 470 | Some(crate::error::Alias::Trait) | |
| 471 | } else { | |
| 472 | None | |
| 473 | }; | |
| 471 | 474 | |
| 472 | 475 | let cycle_diag = crate::error::Cycle { |
| 473 | 476 | span, |
| ... | ... | @@ -479,5 +482,5 @@ pub(crate) fn report_cycle<'a>( |
| 479 | 482 | note_span: (), |
| 480 | 483 | }; |
| 481 | 484 | |
| 482 | sess.dcx().create_err(cycle_diag) | |
| 485 | tcx.sess.dcx().create_err(cycle_diag) | |
| 483 | 486 | } |
compiler/rustc_query_impl/src/lib.rs+1-1| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | |
| 11 | 11 | use rustc_data_structures::sync::AtomicU64; |
| 12 | 12 | use rustc_middle::dep_graph; |
| 13 | use rustc_middle::queries::{self, ExternProviders, Providers}; | |
| 13 | use rustc_middle::queries::{self, ExternProviders, Providers, TaggedQueryKey}; | |
| 14 | 14 | use rustc_middle::query::on_disk_cache::OnDiskCache; |
| 15 | 15 | use rustc_middle::query::plumbing::{QuerySystem, QueryVTable}; |
| 16 | 16 | use rustc_middle::query::{AsLocalQueryKey, QueryCache, QueryMode}; |
compiler/rustc_query_impl/src/plumbing.rs+12-53| ... | ... | @@ -18,14 +18,10 @@ use rustc_middle::query::on_disk_cache::{ |
| 18 | 18 | AbsoluteBytePos, CacheDecoder, CacheEncoder, EncodedDepNodeIndex, |
| 19 | 19 | }; |
| 20 | 20 | use rustc_middle::query::plumbing::QueryVTable; |
| 21 | use rustc_middle::query::{ | |
| 22 | QueryCache, QueryJobId, QueryKey, QueryMode, QueryStackDeferred, QueryStackFrame, | |
| 23 | QueryStackFrameExtra, erase, | |
| 24 | }; | |
| 21 | use rustc_middle::query::{QueryCache, QueryJobId, QueryKey, QueryMode, QueryStackFrame, erase}; | |
| 22 | use rustc_middle::ty::TyCtxt; | |
| 25 | 23 | use rustc_middle::ty::codec::TyEncoder; |
| 26 | use rustc_middle::ty::print::with_reduced_queries; | |
| 27 | 24 | use rustc_middle::ty::tls::{self, ImplicitCtxt}; |
| 28 | use rustc_middle::ty::{self, TyCtxt}; | |
| 29 | 25 | use rustc_serialize::{Decodable, Encodable}; |
| 30 | 26 | use rustc_span::DUMMY_SP; |
| 31 | 27 | use rustc_span::def_id::LOCAL_CRATE; |
| ... | ... | @@ -47,7 +43,7 @@ fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) { |
| 47 | 43 | |
| 48 | 44 | tcx.sess.dcx().emit_fatal(QueryOverflow { |
| 49 | 45 | span: info.job.span, |
| 50 | note: QueryOverflowNote { desc: info.frame.info.extract().description, depth }, | |
| 46 | note: QueryOverflowNote { desc: info.frame.tagged_key.description(tcx), depth }, | |
| 51 | 47 | suggested_limit, |
| 52 | 48 | crate_name: tcx.crate_name(LOCAL_CRATE), |
| 53 | 49 | }); |
| ... | ... | @@ -90,60 +86,23 @@ pub(crate) fn start_query<R>( |
| 90 | 86 | }) |
| 91 | 87 | } |
| 92 | 88 | |
| 93 | /// The deferred part of a deferred query stack frame. | |
| 94 | fn mk_query_stack_frame_extra<'tcx, Cache>( | |
| 95 | (tcx, vtable, key): (TyCtxt<'tcx>, &'tcx QueryVTable<'tcx, Cache>, Cache::Key), | |
| 96 | ) -> QueryStackFrameExtra | |
| 97 | where | |
| 98 | Cache: QueryCache, | |
| 99 | Cache::Key: QueryKey, | |
| 100 | { | |
| 101 | let def_id = key.key_as_def_id(); | |
| 102 | ||
| 103 | // If reduced queries are requested, we may be printing a query stack due | |
| 104 | // to a panic. Avoid using `default_span` and `def_kind` in that case. | |
| 105 | let reduce_queries = with_reduced_queries(); | |
| 106 | ||
| 107 | // Avoid calling queries while formatting the description | |
| 108 | let description = ty::print::with_no_queries!((vtable.description_fn)(tcx, key)); | |
| 109 | let description = if tcx.sess.verbose_internals() { | |
| 110 | format!("{description} [{name:?}]", name = vtable.name) | |
| 111 | } else { | |
| 112 | description | |
| 113 | }; | |
| 114 | let span = if vtable.dep_kind == DepKind::def_span || reduce_queries { | |
| 115 | // The `def_span` query is used to calculate `default_span`, | |
| 116 | // so exit to avoid infinite recursion. | |
| 117 | None | |
| 118 | } else { | |
| 119 | Some(key.default_span(tcx)) | |
| 120 | }; | |
| 121 | ||
| 122 | let def_kind = if vtable.dep_kind == DepKind::def_kind || reduce_queries { | |
| 123 | // Try to avoid infinite recursion. | |
| 124 | None | |
| 125 | } else { | |
| 126 | def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) | |
| 127 | }; | |
| 128 | QueryStackFrameExtra::new(description, span, def_kind) | |
| 129 | } | |
| 130 | ||
| 131 | pub(crate) fn create_deferred_query_stack_frame<'tcx, C>( | |
| 132 | tcx: TyCtxt<'tcx>, | |
| 89 | pub(crate) fn create_query_stack_frame<'tcx, C>( | |
| 133 | 90 | vtable: &'tcx QueryVTable<'tcx, C>, |
| 134 | 91 | key: C::Key, |
| 135 | ) -> QueryStackFrame<QueryStackDeferred<'tcx>> | |
| 92 | ) -> QueryStackFrame<'tcx> | |
| 136 | 93 | where |
| 137 | 94 | C: QueryCache<Key: QueryKey + DynSend + DynSync>, |
| 138 | 95 | QueryVTable<'tcx, C>: DynSync, |
| 139 | 96 | { |
| 140 | let kind = vtable.dep_kind; | |
| 141 | ||
| 142 | 97 | let def_id: Option<DefId> = key.key_as_def_id(); |
| 143 | 98 | let def_id_for_ty_in_cycle: Option<DefId> = key.def_id_for_ty_in_cycle(); |
| 144 | 99 | |
| 145 | let info = QueryStackDeferred::new((tcx, vtable, key), mk_query_stack_frame_extra); | |
| 146 | QueryStackFrame::new(info, kind, def_id, def_id_for_ty_in_cycle) | |
| 100 | QueryStackFrame { | |
| 101 | tagged_key: (vtable.create_tagged_key)(key), | |
| 102 | dep_kind: vtable.dep_kind, | |
| 103 | def_id, | |
| 104 | def_id_for_ty_in_cycle, | |
| 105 | } | |
| 147 | 106 | } |
| 148 | 107 | |
| 149 | 108 | pub(crate) fn encode_all_query_results<'tcx>( |
| ... | ... | @@ -500,7 +459,7 @@ macro_rules! define_queries { |
| 500 | 459 | }), |
| 501 | 460 | |
| 502 | 461 | format_value: |value| format!("{:?}", erase::restore_val::<queries::$name::Value<'tcx>>(*value)), |
| 503 | description_fn: $crate::queries::_description_fns::$name, | |
| 462 | create_tagged_key: TaggedQueryKey::$name, | |
| 504 | 463 | execute_query_fn: if incremental { |
| 505 | 464 | query_impl::$name::execute_query_incr::__rust_end_short_backtrace |
| 506 | 465 | } else { |
rustfmt.toml-1| ... | ... | @@ -20,7 +20,6 @@ ignore = [ |
| 20 | 20 | "/tests/incremental/", # These tests are somewhat sensitive to source code layout. |
| 21 | 21 | "/tests/pretty/", # These tests are very sensitive to source code layout. |
| 22 | 22 | "/tests/run-make/export", # These tests contain syntax errors. |
| 23 | "/tests/run-make/translation/test.rs", # This test contains syntax errors. | |
| 24 | 23 | "/tests/rustdoc-html/", # Some have syntax errors, some are whitespace-sensitive. |
| 25 | 24 | "/tests/rustdoc-gui/", # Some tests are sensitive to source code layout. |
| 26 | 25 | "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. |
tests/debuginfo/basic-stepping.rs+55-2| ... | ... | @@ -14,9 +14,9 @@ |
| 14 | 14 | //@ revisions: default-mir-passes no-SingleUseConsts-mir-pass |
| 15 | 15 | //@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts |
| 16 | 16 | |
| 17 | // === GDB TESTS =================================================================================== | |
| 18 | ||
| 17 | 19 | //@ gdb-command: run |
| 18 | // FIXME(#97083): Should we be able to break on initialization of zero-sized types? | |
| 19 | // FIXME(#97083): Right now the first breakable line is: | |
| 20 | 20 | //@ gdb-check: let mut c = 27; |
| 21 | 21 | //@ gdb-command: next |
| 22 | 22 | //@ gdb-check: let d = c = 99; |
| ... | ... | @@ -39,9 +39,62 @@ |
| 39 | 39 | //@ gdb-command: next |
| 40 | 40 | //@ gdb-check: let m: *const() = &a; |
| 41 | 41 | |
| 42 | // === LLDB TESTS ================================================================================== | |
| 43 | ||
| 44 | // Unlike gdb, lldb will display 7 lines of context by default. It seems | |
| 45 | // impossible to get it down to 1. The best we can do is to show the current | |
| 46 | // line and one above. That is not ideal, but it will do for now. | |
| 47 | //@ lldb-command: settings set stop-line-count-before 1 | |
| 48 | //@ lldb-command: settings set stop-line-count-after 0 | |
| 49 | ||
| 50 | //@ lldb-command: run | |
| 51 | // In `breakpoint_callback()` in `./src/etc/lldb_batchmode.py` we do | |
| 52 | // `SetSelectedFrame()`, which causes LLDB to show the current line and one line | |
| 53 | // before (since we changed `stop-line-count-before`). Note that | |
| 54 | // `normalize_whitespace()` in `lldb_batchmode.py` removes the newlines of the | |
| 55 | // output. So the current line and the line before actually ends up on the same | |
| 56 | // output line. That's fine. | |
| 57 | //@ lldb-check: [...]let mut c = 27;[...] | |
| 58 | //@ lldb-command: next | |
| 59 | // From now on we must manually `frame select` to see the current line (and one | |
| 60 | // line before). | |
| 61 | //@ lldb-command: frame select | |
| 62 | //@ lldb-check: [...]let d = c = 99;[...] | |
| 63 | //@ lldb-command: next | |
| 64 | //@ lldb-command: frame select | |
| 65 | //@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let e = "hi bob";[...] | |
| 66 | //@ [no-SingleUseConsts-mir-pass] lldb-command: next | |
| 67 | //@ [no-SingleUseConsts-mir-pass] lldb-command: frame select | |
| 68 | //@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let f = b"hi bob";[...] | |
| 69 | //@ [no-SingleUseConsts-mir-pass] lldb-command: next | |
| 70 | //@ [no-SingleUseConsts-mir-pass] lldb-command: frame select | |
| 71 | //@ [no-SingleUseConsts-mir-pass] lldb-check: [...]let g = b'9';[...] | |
| 72 | //@ [no-SingleUseConsts-mir-pass] lldb-command: next | |
| 73 | //@ [no-SingleUseConsts-mir-pass] lldb-command: frame select | |
| 74 | //@ lldb-check: [...]let h = ["whatever"; 8];[...] | |
| 75 | //@ lldb-command: next | |
| 76 | //@ lldb-command: frame select | |
| 77 | //@ lldb-check: [...]let i = [1,2,3,4];[...] | |
| 78 | //@ lldb-command: next | |
| 79 | //@ lldb-command: frame select | |
| 80 | //@ lldb-check: [...]let j = (23, "hi");[...] | |
| 81 | //@ lldb-command: next | |
| 82 | //@ lldb-command: frame select | |
| 83 | //@ lldb-check: [...]let k = 2..3;[...] | |
| 84 | //@ lldb-command: next | |
| 85 | //@ lldb-command: frame select | |
| 86 | //@ lldb-check: [...]let l = &i[k];[...] | |
| 87 | //@ lldb-command: next | |
| 88 | //@ lldb-command: frame select | |
| 89 | //@ lldb-check: [...]let m: *const() = &a;[...] | |
| 90 | ||
| 91 | #![allow(unused_assignments, unused_variables)] | |
| 92 | ||
| 42 | 93 | fn main () { |
| 43 | 94 | let a = (); // #break |
| 44 | 95 | let b : [i32; 0] = []; |
| 96 | // FIXME(#97083): Should we be able to break on initialization of zero-sized types? | |
| 97 | // FIXME(#97083): Right now the first breakable line is: | |
| 45 | 98 | let mut c = 27; |
| 46 | 99 | let d = c = 99; |
| 47 | 100 | let e = "hi bob"; |