From 050643a9606c279d9b959976c3718ad3d7bdb84a Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 13 Jan 2021 17:54:24 -0600 Subject: [PATCH 01/19] Add Frames iterator for Backtrace --- library/std/src/backtrace.rs | 21 +++++- library/std/src/backtrace/tests.rs | 109 +++++++++++++++++++---------- 2 files changed, 92 insertions(+), 38 deletions(-) diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 95e18ef2a6543..0aae4674b2942 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -147,11 +147,14 @@ fn _assert_send_sync() { _assert::(); } -struct BacktraceFrame { +/// A single frame of a backtrace. +#[unstable(feature = "backtrace_frames", issue = "79676")] +pub struct BacktraceFrame { frame: RawFrame, symbols: Vec, } +#[derive(Debug)] enum RawFrame { Actual(backtrace_rs::Frame), #[cfg(test)] @@ -196,6 +199,14 @@ impl fmt::Debug for Backtrace { } } +impl fmt::Debug for BacktraceFrame { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut dbg = fmt.debug_list(); + dbg.entries(&self.symbols); + dbg.finish() + } +} + impl fmt::Debug for BacktraceSymbol { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280 @@ -353,6 +364,14 @@ impl Backtrace { } } +impl<'a> Backtrace { + /// Returns an iterator over the backtrace frames. + #[unstable(feature = "backtrace_frames", issue = "79676")] + pub fn frames(&'a self) -> &'a [BacktraceFrame] { + if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] } + } +} + impl fmt::Display for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let capture = match &self.inner { diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index 31cf0f702185c..f5da93f93fd93 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -1,48 +1,52 @@ use super::*; +fn generate_fake_frames() -> Vec { + vec![ + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"std::backtrace::Backtrace::create".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), + lineno: Some(100), + colno: None, + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"__rust_maybe_catch_panic".to_vec()), + filename: None, + lineno: None, + colno: None, + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![ + BacktraceSymbol { + name: Some(b"std::rt::lang_start_internal".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(300), + colno: Some(5), + }, + BacktraceSymbol { + name: Some(b"std::rt::lang_start".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(400), + colno: None, + }, + ], + }, + ] +} + #[test] fn test_debug() { let backtrace = Backtrace { inner: Inner::Captured(LazilyResolvedCapture::new(Capture { actual_start: 1, resolved: true, - frames: vec![ - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![BacktraceSymbol { - name: Some(b"std::backtrace::Backtrace::create".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), - lineno: Some(100), - colno: None, - }], - }, - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![BacktraceSymbol { - name: Some(b"__rust_maybe_catch_panic".to_vec()), - filename: None, - lineno: None, - colno: None, - }], - }, - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![ - BacktraceSymbol { - name: Some(b"std::rt::lang_start_internal".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), - lineno: Some(300), - colno: Some(5), - }, - BacktraceSymbol { - name: Some(b"std::rt::lang_start".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), - lineno: Some(400), - colno: None, - }, - ], - }, - ], + frames: generate_fake_frames(), })), }; @@ -58,3 +62,34 @@ fn test_debug() { // Format the backtrace a second time, just to make sure lazily resolved state is stable assert_eq!(format!("{:#?}", backtrace), expected); } + +#[test] +fn test_frames() { + let backtrace = Backtrace { + inner: Inner::Captured(LazilyResolvedCapture::new(Capture { + actual_start: 1, + resolved: true, + frames: generate_fake_frames(), + })), + }; + + let frames = backtrace.frames(); + + #[rustfmt::skip] + let expected = vec![ + "[ + { fn: \"std::backtrace::Backtrace::create\", file: \"rust/backtrace.rs\", line: 100 }, +]", + "[ + { fn: \"__rust_maybe_catch_panic\" }, +]", + "[ + { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 }, + { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 }, +]" + ]; + + let mut iter = frames.iter().zip(expected.iter()); + + assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e)); +} From 61f6fa70ac2e7bf79eb46bd959345115596282c4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 28 Jan 2021 18:42:44 +0100 Subject: [PATCH 02/19] move a bunch of tests --- src/test/ui/{ => cast}/fat-ptr-cast-rpass.rs | 0 src/test/ui/{ => cast}/fat-ptr-cast.rs | 0 src/test/ui/{ => cast}/fat-ptr-cast.stderr | 0 src/test/ui/{issues => cast}/issue-17444.rs | 0 src/test/ui/{issues => cast}/issue-17444.stderr | 0 src/test/ui/cast/unsupported-cast.rs | 5 +++++ src/test/ui/{ => cast}/unsupported-cast.stderr | 4 ++-- src/test/ui/unsupported-cast.rs | 7 ------- 8 files changed, 7 insertions(+), 9 deletions(-) rename src/test/ui/{ => cast}/fat-ptr-cast-rpass.rs (100%) rename src/test/ui/{ => cast}/fat-ptr-cast.rs (100%) rename src/test/ui/{ => cast}/fat-ptr-cast.stderr (100%) rename src/test/ui/{issues => cast}/issue-17444.rs (100%) rename src/test/ui/{issues => cast}/issue-17444.stderr (100%) create mode 100644 src/test/ui/cast/unsupported-cast.rs rename src/test/ui/{ => cast}/unsupported-cast.stderr (65%) delete mode 100644 src/test/ui/unsupported-cast.rs diff --git a/src/test/ui/fat-ptr-cast-rpass.rs b/src/test/ui/cast/fat-ptr-cast-rpass.rs similarity index 100% rename from src/test/ui/fat-ptr-cast-rpass.rs rename to src/test/ui/cast/fat-ptr-cast-rpass.rs diff --git a/src/test/ui/fat-ptr-cast.rs b/src/test/ui/cast/fat-ptr-cast.rs similarity index 100% rename from src/test/ui/fat-ptr-cast.rs rename to src/test/ui/cast/fat-ptr-cast.rs diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/cast/fat-ptr-cast.stderr similarity index 100% rename from src/test/ui/fat-ptr-cast.stderr rename to src/test/ui/cast/fat-ptr-cast.stderr diff --git a/src/test/ui/issues/issue-17444.rs b/src/test/ui/cast/issue-17444.rs similarity index 100% rename from src/test/ui/issues/issue-17444.rs rename to src/test/ui/cast/issue-17444.rs diff --git a/src/test/ui/issues/issue-17444.stderr b/src/test/ui/cast/issue-17444.stderr similarity index 100% rename from src/test/ui/issues/issue-17444.stderr rename to src/test/ui/cast/issue-17444.stderr diff --git a/src/test/ui/cast/unsupported-cast.rs b/src/test/ui/cast/unsupported-cast.rs new file mode 100644 index 0000000000000..1384ecc6ef251 --- /dev/null +++ b/src/test/ui/cast/unsupported-cast.rs @@ -0,0 +1,5 @@ +struct A; + +fn main() { + println!("{:?}", 1.0 as *const A); //~ERROR casting `f64` as `*const A` is invalid +} diff --git a/src/test/ui/unsupported-cast.stderr b/src/test/ui/cast/unsupported-cast.stderr similarity index 65% rename from src/test/ui/unsupported-cast.stderr rename to src/test/ui/cast/unsupported-cast.stderr index 63e7713d2f4e7..56a375a1d942a 100644 --- a/src/test/ui/unsupported-cast.stderr +++ b/src/test/ui/cast/unsupported-cast.stderr @@ -1,7 +1,7 @@ error[E0606]: casting `f64` as `*const A` is invalid - --> $DIR/unsupported-cast.rs:6:20 + --> $DIR/unsupported-cast.rs:4:20 | -LL | println!("{:?}", 1.0 as *const A); // Can't cast float to foreign. +LL | println!("{:?}", 1.0 as *const A); | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsupported-cast.rs b/src/test/ui/unsupported-cast.rs deleted file mode 100644 index cb6a57a4d39d5..0000000000000 --- a/src/test/ui/unsupported-cast.rs +++ /dev/null @@ -1,7 +0,0 @@ -// error-pattern:casting - -struct A; - -fn main() { - println!("{:?}", 1.0 as *const A); // Can't cast float to foreign. -} From fe1fc36f8ed2ab7527536c85f385b717b695a53d Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Thu, 28 Jan 2021 13:24:52 -0500 Subject: [PATCH 03/19] Add some test for ATB issues --- src/test/ui/associated-types/issue-38917.rs | 25 +++++++++++++++++++++ src/test/ui/associated-types/issue-40093.rs | 14 ++++++++++++ src/test/ui/associated-types/issue-43475.rs | 10 +++++++++ src/test/ui/associated-types/issue-63591.rs | 24 ++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 src/test/ui/associated-types/issue-38917.rs create mode 100644 src/test/ui/associated-types/issue-40093.rs create mode 100644 src/test/ui/associated-types/issue-43475.rs create mode 100644 src/test/ui/associated-types/issue-63591.rs diff --git a/src/test/ui/associated-types/issue-38917.rs b/src/test/ui/associated-types/issue-38917.rs new file mode 100644 index 0000000000000..7e898851aa83a --- /dev/null +++ b/src/test/ui/associated-types/issue-38917.rs @@ -0,0 +1,25 @@ +// check-pass + +use std::borrow::Borrow; + +trait TNode: Sized { + type ConcreteElement: TElement; +} + +trait TElement: Sized { + type ConcreteNode: TNode; +} + +trait DomTraversal { + type BorrowElement: Borrow; +} + +#[allow(dead_code)] +fn recalc_style_at() +where + E: TElement, + D: DomTraversal, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-40093.rs b/src/test/ui/associated-types/issue-40093.rs new file mode 100644 index 0000000000000..fd325ae100861 --- /dev/null +++ b/src/test/ui/associated-types/issue-40093.rs @@ -0,0 +1,14 @@ +// check-pass + +pub trait Test { + type Item; + type Bundle: From; +} + +fn fails() +where + T: Test, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-43475.rs b/src/test/ui/associated-types/issue-43475.rs new file mode 100644 index 0000000000000..5f177333c93d5 --- /dev/null +++ b/src/test/ui/associated-types/issue-43475.rs @@ -0,0 +1,10 @@ +// check-pass + +trait Foo { type FooT: Foo; } +impl Foo for () { type FooT = (); } +trait Bar { type BarT: Bar; } +impl Bar<()> for () { type BarT = (); } + +#[allow(dead_code)] +fn test>() { } +fn main() { } diff --git a/src/test/ui/associated-types/issue-63591.rs b/src/test/ui/associated-types/issue-63591.rs new file mode 100644 index 0000000000000..4d2e39f4da60c --- /dev/null +++ b/src/test/ui/associated-types/issue-63591.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(associated_type_bounds)] +#![feature(type_alias_impl_trait)] + +fn main() {} + +trait Bar { type Assoc; } + +trait Thing { + type Out; + fn func() -> Self::Out; +} + +struct AssocIsCopy; +impl Bar for AssocIsCopy { type Assoc = u8; } + +impl Thing for AssocIsCopy { + type Out = impl Bar; + + fn func() -> Self::Out { + AssocIsCopy + } +} From 6c14aad58e65c9c50faa45ed88369c5c72d6d0d7 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 31 Jan 2021 15:21:28 -0500 Subject: [PATCH 04/19] Improve handling of spans around macro result parse errors Fixes #81543 After we expand a macro, we try to parse the resulting tokens as a AST node. This commit makes several improvements to how we handle spans when an error occurs: * Only ovewrite the original `Span` if it's a dummy span. This preserves a more-specific span if one is available. * Use `self.prev_token` instead of `self.token` when emitting an error message after encountering EOF, since an EOF token always has a dummy span * Make `SourceMap::next_point` leave dummy spans unused. A dummy span does not have a logical 'next point', since it's a zero-length span. Re-using the span span preserves its 'dummy-ness' for other checks --- compiler/rustc_expand/src/expand.rs | 4 +++- compiler/rustc_parse/src/parser/diagnostics.rs | 4 ++-- compiler/rustc_span/src/source_map.rs | 3 +++ .../ui/proc-macro/issue-81543-item-parse-err.rs | 14 ++++++++++++++ .../proc-macro/issue-81543-item-parse-err.stderr | 8 ++++++++ src/test/ui/proc-macro/lifetimes.stderr | 7 ++++++- 6 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/proc-macro/issue-81543-item-parse-err.rs create mode 100644 src/test/ui/proc-macro/issue-81543-item-parse-err.stderr diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 50832d5edbfc5..5fdb7fc591594 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -896,7 +896,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fragment } Err(mut err) => { - err.set_span(span); + if err.span.is_dummy() { + err.set_span(span); + } annotate_err_with_kind(&mut err, kind, span); err.emit(); self.cx.trace_macros_diag(); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f2fcce5c22662..5512e849c451d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1104,7 +1104,7 @@ impl<'a> Parser<'a> { let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { // Point at the end of the macro call when reaching end of macro arguments. (token::Eof, Some(_)) => { - let sp = self.sess.source_map().next_point(self.token.span); + let sp = self.sess.source_map().next_point(self.prev_token.span); (sp, sp) } // We don't want to point at the following span after DUMMY_SP. @@ -1721,7 +1721,7 @@ impl<'a> Parser<'a> { pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { let (span, msg) = match (&self.token.kind, self.subparser_name) { (&token::Eof, Some(origin)) => { - let sp = self.sess.source_map().next_point(self.token.span); + let sp = self.sess.source_map().next_point(self.prev_token.span); (sp, format!("expected expression, found end of {}", origin)) } _ => ( diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 4e0ce0d344de4..2b429372dcffb 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -799,6 +799,9 @@ impl SourceMap { /// Returns a new span representing the next character after the end-point of this span. pub fn next_point(&self, sp: Span) -> Span { + if sp.is_dummy() { + return sp; + } let start_of_next_point = sp.hi().0; let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true); diff --git a/src/test/ui/proc-macro/issue-81543-item-parse-err.rs b/src/test/ui/proc-macro/issue-81543-item-parse-err.rs new file mode 100644 index 0000000000000..027389556fe24 --- /dev/null +++ b/src/test/ui/proc-macro/issue-81543-item-parse-err.rs @@ -0,0 +1,14 @@ +// aux-build:test-macros.rs + +// Regression test for issue #81543 +// Tests that we emit a properly spanned error +// when the output of a proc-macro cannot be parsed +// as the expected AST node kind + +extern crate test_macros; + +test_macros::identity! { + fn 32() {} //~ ERROR expected identifier +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-81543-item-parse-err.stderr b/src/test/ui/proc-macro/issue-81543-item-parse-err.stderr new file mode 100644 index 0000000000000..ca524176035b8 --- /dev/null +++ b/src/test/ui/proc-macro/issue-81543-item-parse-err.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `32` + --> $DIR/issue-81543-item-parse-err.rs:11:8 + | +LL | fn 32() {} + | ^^ expected identifier + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/lifetimes.stderr b/src/test/ui/proc-macro/lifetimes.stderr index 10acd4304aa23..58f6165388ca1 100644 --- a/src/test/ui/proc-macro/lifetimes.stderr +++ b/src/test/ui/proc-macro/lifetimes.stderr @@ -2,7 +2,12 @@ error: expected type, found `'` --> $DIR/lifetimes.rs:7:10 | LL | type A = single_quote_alone!(); - | ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type + | ^^^^^^^^^^^^^^^^^^^^^ + | | + | expected type + | this macro call doesn't expand to a type + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error From 7bc09f78af16cbc95c5139496e6cfd4045edff3a Mon Sep 17 00:00:00 2001 From: Julian Wollersberger Date: Sun, 31 Jan 2021 21:37:17 +0100 Subject: [PATCH 05/19] Remove the remains of the query categories. --- compiler/rustc_macros/src/query.rs | 27 +----- compiler/rustc_middle/src/query/mod.rs | 119 +++---------------------- 2 files changed, 17 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index d264462bf0895..92269920d2971 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -189,25 +189,6 @@ impl Parse for List { } } -/// A named group containing queries. -/// -/// For now, the name is not used any more, but the capability remains interesting for future -/// developments of the query system. -struct Group { - #[allow(unused)] - name: Ident, - queries: List, -} - -impl Parse for Group { - fn parse(input: ParseStream<'_>) -> Result { - let name: Ident = input.parse()?; - let content; - braced!(content in input); - Ok(Group { name, queries: content.parse()? }) - } -} - struct QueryModifiers { /// The description of the query. desc: (Option, Punctuated), @@ -450,15 +431,15 @@ fn add_query_description_impl( } pub fn rustc_queries(input: TokenStream) -> TokenStream { - let groups = parse_macro_input!(input as List); + let queries = parse_macro_input!(input as List); let mut query_stream = quote! {}; let mut query_description_stream = quote! {}; let mut dep_node_def_stream = quote! {}; let mut cached_queries = quote! {}; - for group in groups.0 { - for mut query in group.queries.0 { + //for group in groups.0 { + for mut query in queries.0 { let modifiers = process_modifiers(&mut query); let name = &query.name; let arg = &query.arg; @@ -516,7 +497,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { add_query_description_impl(&query, modifiers, &mut query_description_stream); } - } + //} TokenStream::from(quote! { macro_rules! rustc_query_append { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d89e3ab4352bb..abaa60dec4a96 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -35,13 +35,10 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { - Other { query trigger_delay_span_bug(key: DefId) -> () { desc { "trigger a delay span bug" } } - } - Other { /// Represents crate as a whole (as distinct from the top-level crate module). /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), /// we will have to assume that any change means that you need to be recompiled. @@ -223,16 +220,12 @@ rustc_queries! { query expn_that_defined(key: DefId) -> rustc_span::ExpnId { desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) } } - } - Codegen { query is_panic_runtime(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate is_panic_runtime" } } - } - Codegen { /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. @@ -386,9 +379,7 @@ rustc_queries! { tcx.def_path_str(key.0.to_def_id()), } } - } - TypeChecking { /// Erases regions from `ty` to yield a new type. /// Normally you would just use `tcx.erase_regions(value)`, /// however, which uses this query as a kind of cache. @@ -402,16 +393,12 @@ rustc_queries! { anon desc { "erasing regions from `{:?}`", ty } } - } - Linking { query wasm_import_module_map(_: CrateNum) -> FxHashMap { storage(ArenaCacheSelector<'tcx>) desc { "wasm import module map" } } - } - Other { /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the /// predicates (where-clauses) directly defined on it. This is /// equal to the `explicit_predicates_of` predicates plus the @@ -555,18 +542,14 @@ rustc_queries! { query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) } } - } - TypeChecking { /// Maps from thee `DefId` of a type to its (inferred) outlives. query inferred_outlives_crate(_: CrateNum) -> ty::CratePredicatesMap<'tcx> { storage(ArenaCacheSelector<'tcx>) desc { "computing the inferred outlives predicates for items in this crate" } } - } - - Other { + /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } @@ -596,9 +579,7 @@ rustc_queries! { query issue33140_self_ty(key: DefId) -> Option> { desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } } - } - - TypeChecking { + /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. @@ -606,9 +587,7 @@ rustc_queries! { desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } eval_always } - } - - TypeChecking { + /// The result of unsafety-checking this `LocalDefId`. query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) } @@ -634,9 +613,7 @@ rustc_queries! { query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } } - } - - Other { + query lint_mod(key: LocalDefId) -> () { desc { |tcx| "linting {}", describe_as_module(key, tcx) } } @@ -693,9 +670,7 @@ rustc_queries! { -> ty::adjustment::CoerceUnsizedInfo { desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } } - } - - TypeChecking { + query typeck_item_bodies(_: CrateNum) -> () { desc { "type-checking all item bodies" } } @@ -723,16 +698,12 @@ rustc_queries! { typeck_results.map(|x| &*tcx.arena.alloc(x)) } } - } - - Other { + query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet { desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } - } - - TypeChecking { + query has_typeck_results(def_id: DefId) -> bool { desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) } } @@ -740,9 +711,7 @@ rustc_queries! { query coherent_trait(def_id: DefId) -> () { desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } } - } - - BorrowChecking { + /// Borrow-checks the function body. If this is a closure, returns /// additional requirements that the closure's creator must verify. query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { @@ -758,9 +727,7 @@ rustc_queries! { tcx.def_path_str(key.0.to_def_id()) } } - } - - TypeChecking { + /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. /// (Defined only for `LOCAL_CRATE`.) @@ -779,9 +746,7 @@ rustc_queries! { eval_always desc { "check for overlap between inherent impls defined in this crate" } } - } - - Other { + /// Check whether the function has any recursion that could cause the inliner to trigger /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the /// current function, just all intermediate functions. @@ -855,9 +820,7 @@ rustc_queries! { ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { desc { "converting literal to const" } } - } - - TypeChecking { + query check_match(key: DefId) { desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -872,9 +835,7 @@ rustc_queries! { eval_always desc { "checking for private elements in public interfaces" } } - } - - Other { + query reachable_set(_: CrateNum) -> FxHashSet { storage(ArenaCacheSelector<'tcx>) desc { "reachability" } @@ -932,17 +893,13 @@ rustc_queries! { query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } } - } - - Codegen { + query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { true } } - } - Other { query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] { desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } } @@ -954,33 +911,25 @@ rustc_queries! { query impl_parent(def_id: DefId) -> Option { desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } } - } - TypeChecking { /// Given an `associated_item`, find the trait it belongs to. /// Return `None` if the `DefId` is not an associated item. query trait_of_item(associated_item: DefId) -> Option { desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } } - } - Codegen { query is_ctfe_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) } } query is_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } } - } - Other { query vtable_methods(key: ty::PolyTraitRef<'tcx>) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } } - } - Codegen { query codegen_fulfill_obligation( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) ) -> Result, ErrorReported> { @@ -990,9 +939,7 @@ rustc_queries! { tcx.def_path_str(key.1.def_id()) } } - } - TypeChecking { /// Return all `impl` blocks in the current crate. /// /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. @@ -1077,9 +1024,7 @@ rustc_queries! { ) -> Result<&'tcx rustc_target::abi::Layout, ty::layout::LayoutError<'tcx>> { desc { "computing layout of `{}`", env.value } } - } - Other { query dylib_dependency_formats(_: CrateNum) -> &'tcx [(CrateNum, LinkagePreference)] { desc { "dylib dependency formats of crate" } @@ -1090,9 +1035,7 @@ rustc_queries! { { desc { "get the linkage format of all dependencies" } } - } - Codegen { query is_compiler_builtins(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate is_compiler_builtins" } @@ -1126,9 +1069,7 @@ rustc_queries! { eval_always desc { "getting crate's ExternCrateData" } } - } - TypeChecking { query specializes(_: (DefId, DefId)) -> bool { desc { "computing whether impls specialize one another" } } @@ -1137,16 +1078,12 @@ rustc_queries! { eval_always desc { "traits in scope at a block" } } - } - Other { query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) } eval_always } - } - TypeChecking { query impl_defaultness(def_id: DefId) -> hir::Defaultness { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } } @@ -1160,10 +1097,7 @@ rustc_queries! { query check_impl_item_well_formed(key: LocalDefId) -> () { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } } - } - - Linking { // The `DefId`s of all non-generic functions and statics in the given crate // that can be reached from outside the crate. // @@ -1190,9 +1124,7 @@ rustc_queries! { tcx.def_path_str(def_id), } } - } - Codegen { /// The entire set of monomorphizations the local crate can safely link /// to because they are exported from upstream crates. Do not depend on /// this directly, as its value changes anytime a monomorphization gets @@ -1239,9 +1171,7 @@ rustc_queries! { query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option { desc { "available upstream drop-glue for `{:?}`", substs } } - } - Other { query foreign_modules(_: CrateNum) -> Lrc> { desc { "looking up the foreign modules of a linked crate" } } @@ -1283,9 +1213,7 @@ rustc_queries! { eval_always desc { "looking up the paths for extern crates" } } - } - TypeChecking { /// Given a crate and a trait, look up all impls of that trait in the crate. /// Return `(impl_id, self_ty)`. query implementations_of_trait(_: (CrateNum, DefId)) @@ -1299,9 +1227,7 @@ rustc_queries! { -> &'tcx [(DefId, Option)] { desc { "looking up all (?) trait implementations" } } - } - Other { query is_dllimport_foreign_item(def_id: DefId) -> bool { desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } } @@ -1312,16 +1238,12 @@ rustc_queries! { -> Option { desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) } } - } - Linking { query link_args(_: CrateNum) -> Lrc> { eval_always desc { "looking up link arguments for a crate" } } - } - BorrowChecking { /// Lifetime resolution. See `middle::resolve_lifetimes`. query resolve_lifetimes(_: CrateNum) -> ResolveLifetimes { storage(ArenaCacheSelector<'tcx>) @@ -1339,9 +1261,7 @@ rustc_queries! { -> Option<&'tcx FxHashMap>> { desc { "looking up lifetime defaults for a region" } } - } - TypeChecking { query visibility(def_id: DefId) -> ty::Visibility { eval_always desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } @@ -1355,9 +1275,7 @@ rustc_queries! { ) -> ty::inhabitedness::DefIdForest { desc { "computing the inhabitedness of `{:?}`", key } } - } - Other { query dep_kind(_: CrateNum) -> CrateDepKind { eval_always desc { "fetching what a dependency looks like" } @@ -1470,9 +1388,7 @@ rustc_queries! { query all_traits(_: CrateNum) -> &'tcx [DefId] { desc { "fetching all foreign and local traits" } } - } - Linking { /// The list of symbols exported from the given crate. /// /// - All names contained in `exported_symbols(cnum)` are guaranteed to @@ -1482,9 +1398,7 @@ rustc_queries! { -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { desc { "exported_symbols" } } - } - Codegen { query collect_and_partition_mono_items(_: CrateNum) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { eval_always @@ -1506,16 +1420,12 @@ rustc_queries! { query backend_optimization_level(_: CrateNum) -> OptLevel { desc { "optimization level used by backend" } } - } - Other { query output_filenames(_: CrateNum) -> Arc { eval_always desc { "output_filenames" } } - } - TypeChecking { /// Do not call this query directly: invoke `normalize` instead. query normalize_projection_ty( goal: CanonicalProjectionGoal<'tcx> @@ -1667,9 +1577,7 @@ rustc_queries! { ) -> MethodAutoderefStepsResult<'tcx> { desc { "computing autoderef types for `{:?}`", goal } } - } - Other { query supported_target_features(_: CrateNum) -> FxHashMap> { storage(ArenaCacheSelector<'tcx>) eval_always @@ -1714,5 +1622,4 @@ rustc_queries! { query normalize_opaque_types(key: &'tcx ty::List>) -> &'tcx ty::List> { desc { "normalizing opaque types in {:?}", key } } - } } From 988d93c8a0b122a9923e0df6fb49cb430dbab3f2 Mon Sep 17 00:00:00 2001 From: Julian Wollersberger Date: Sun, 31 Jan 2021 21:40:03 +0100 Subject: [PATCH 06/19] Indent the code correctly again after removing the query categories. --- compiler/rustc_macros/src/query.rs | 106 +- compiler/rustc_middle/src/query/mod.rs | 2798 ++++++++++++------------ 2 files changed, 1451 insertions(+), 1453 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 92269920d2971..cff8e9833189b 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -438,66 +438,64 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut dep_node_def_stream = quote! {}; let mut cached_queries = quote! {}; - //for group in groups.0 { - for mut query in queries.0 { - let modifiers = process_modifiers(&mut query); - let name = &query.name; - let arg = &query.arg; - let result_full = &query.result; - let result = match query.result { - ReturnType::Default => quote! { -> () }, - _ => quote! { #result_full }, - }; + for mut query in queries.0 { + let modifiers = process_modifiers(&mut query); + let name = &query.name; + let arg = &query.arg; + let result_full = &query.result; + let result = match query.result { + ReturnType::Default => quote! { -> () }, + _ => quote! { #result_full }, + }; - if modifiers.cache.is_some() { - cached_queries.extend(quote! { - #name, - }); - } + if modifiers.cache.is_some() { + cached_queries.extend(quote! { + #name, + }); + } - let mut attributes = Vec::new(); + let mut attributes = Vec::new(); - // Pass on the fatal_cycle modifier - if modifiers.fatal_cycle { - attributes.push(quote! { fatal_cycle }); - }; - // Pass on the storage modifier - if let Some(ref ty) = modifiers.storage { - attributes.push(quote! { storage(#ty) }); - }; - // Pass on the cycle_delay_bug modifier - if modifiers.cycle_delay_bug { - attributes.push(quote! { cycle_delay_bug }); - }; - // Pass on the no_hash modifier - if modifiers.no_hash { - attributes.push(quote! { no_hash }); - }; - // Pass on the anon modifier - if modifiers.anon { - attributes.push(quote! { anon }); - }; - // Pass on the eval_always modifier - if modifiers.eval_always { - attributes.push(quote! { eval_always }); - }; + // Pass on the fatal_cycle modifier + if modifiers.fatal_cycle { + attributes.push(quote! { fatal_cycle }); + }; + // Pass on the storage modifier + if let Some(ref ty) = modifiers.storage { + attributes.push(quote! { storage(#ty) }); + }; + // Pass on the cycle_delay_bug modifier + if modifiers.cycle_delay_bug { + attributes.push(quote! { cycle_delay_bug }); + }; + // Pass on the no_hash modifier + if modifiers.no_hash { + attributes.push(quote! { no_hash }); + }; + // Pass on the anon modifier + if modifiers.anon { + attributes.push(quote! { anon }); + }; + // Pass on the eval_always modifier + if modifiers.eval_always { + attributes.push(quote! { eval_always }); + }; - let attribute_stream = quote! {#(#attributes),*}; - let doc_comments = query.doc_comments.iter(); - // Add the query to the group - query_stream.extend(quote! { - #(#doc_comments)* - [#attribute_stream] fn #name(#arg) #result, - }); + let attribute_stream = quote! {#(#attributes),*}; + let doc_comments = query.doc_comments.iter(); + // Add the query to the group + query_stream.extend(quote! { + #(#doc_comments)* + [#attribute_stream] fn #name(#arg) #result, + }); - // Create a dep node for the query - dep_node_def_stream.extend(quote! { - [#attribute_stream] #name(#arg), - }); + // Create a dep node for the query + dep_node_def_stream.extend(quote! { + [#attribute_stream] #name(#arg), + }); - add_query_description_impl(&query, modifiers, &mut query_description_stream); - } - //} + add_query_description_impl(&query, modifiers, &mut query_description_stream); + } TokenStream::from(quote! { macro_rules! rustc_query_append { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index abaa60dec4a96..ca528b2f0914b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -35,1591 +35,1591 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { - query trigger_delay_span_bug(key: DefId) -> () { - desc { "trigger a delay span bug" } - } + query trigger_delay_span_bug(key: DefId) -> () { + desc { "trigger a delay span bug" } + } - /// Represents crate as a whole (as distinct from the top-level crate module). - /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), - /// we will have to assume that any change means that you need to be recompiled. - /// This is because the `hir_crate` query gives you access to all other items. - /// To avoid this fate, do not call `tcx.hir().krate()`; instead, - /// prefer wrappers like `tcx.visit_all_items_in_krate()`. - query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> { - eval_always - no_hash - desc { "get the crate HIR" } - } + /// Represents crate as a whole (as distinct from the top-level crate module). + /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), + /// we will have to assume that any change means that you need to be recompiled. + /// This is because the `hir_crate` query gives you access to all other items. + /// To avoid this fate, do not call `tcx.hir().krate()`; instead, + /// prefer wrappers like `tcx.visit_all_items_in_krate()`. + query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> { + eval_always + no_hash + desc { "get the crate HIR" } + } - /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - /// Avoid calling this query directly. - query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> { - eval_always - no_hash - desc { "index HIR" } - } + /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. + /// Avoid calling this query directly. + query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> { + eval_always + no_hash + desc { "index HIR" } + } - /// The items in a module. - /// - /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. - /// Avoid calling this query directly. - query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems { - eval_always - desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } - } + /// The items in a module. + /// + /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. + /// Avoid calling this query directly. + query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems { + eval_always + desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Gives access to the HIR node for the HIR owner `key`. - /// - /// This can be conveniently accessed by methods on `tcx.hir()`. - /// Avoid calling this query directly. - query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { - eval_always - desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } - } + /// Gives access to the HIR node for the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. + query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { + eval_always + desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. - /// - /// This can be conveniently accessed by methods on `tcx.hir()`. - /// Avoid calling this query directly. - query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { - eval_always - desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } - } + /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. + query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { + eval_always + desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Computes the `DefId` of the corresponding const parameter in case the `key` is a - /// const argument and returns `None` otherwise. - /// - /// ```ignore (incomplete) - /// let a = foo::<7>(); - /// // ^ Calling `opt_const_param_of` for this argument, - /// - /// fn foo() - /// // ^ returns this `DefId`. - /// - /// fn bar() { - /// // ^ While calling `opt_const_param_of` for other bodies returns `None`. - /// } - /// ``` - // It looks like caching this query on disk actually slightly - // worsened performance in #74376. - // - // Once const generics are more prevalently used, we might want to - // consider only caching calls returning `Some`. - query opt_const_param_of(key: LocalDefId) -> Option { - desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) } - } + /// Computes the `DefId` of the corresponding const parameter in case the `key` is a + /// const argument and returns `None` otherwise. + /// + /// ```ignore (incomplete) + /// let a = foo::<7>(); + /// // ^ Calling `opt_const_param_of` for this argument, + /// + /// fn foo() + /// // ^ returns this `DefId`. + /// + /// fn bar() { + /// // ^ While calling `opt_const_param_of` for other bodies returns `None`. + /// } + /// ``` + // It looks like caching this query on disk actually slightly + // worsened performance in #74376. + // + // Once const generics are more prevalently used, we might want to + // consider only caching calls returning `Some`. + query opt_const_param_of(key: LocalDefId) -> Option { + desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Records the type of every item. - query type_of(key: DefId) -> Ty<'tcx> { - desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } + /// Records the type of every item. + query type_of(key: DefId) -> Ty<'tcx> { + desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } - query analysis(key: CrateNum) -> Result<(), ErrorReported> { - eval_always - desc { "running analysis passes on this crate" } - } + query analysis(key: CrateNum) -> Result<(), ErrorReported> { + eval_always + desc { "running analysis passes on this crate" } + } - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its - /// associated generics. - query generics_of(key: DefId) -> ty::Generics { - desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) - cache_on_disk_if { key.is_local() } - load_cached(tcx, id) { - let generics: Option = tcx.queries.on_disk_cache.as_ref() - .and_then(|c| c.try_load_query_result(tcx, id)); - generics - } + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its + /// associated generics. + query generics_of(key: DefId) -> ty::Generics { + desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + load_cached(tcx, id) { + let generics: Option = tcx.queries.on_disk_cache.as_ref() + .and_then(|c| c.try_load_query_result(tcx, id)); + generics } + } - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the - /// predicates (where-clauses) that must be proven true in order - /// to reference it. This is almost always the "predicates query" - /// that you want. - /// - /// `predicates_of` builds on `predicates_defined_on` -- in fact, - /// it is almost always the same as that query, except for the - /// case of traits. For traits, `predicates_of` contains - /// an additional `Self: Trait<...>` predicate that users don't - /// actually write. This reflects the fact that to invoke the - /// trait (e.g., via `Default::default`) you must supply types - /// that actually implement the trait. (However, this extra - /// predicate gets in the way of some checks, which are intended - /// to operate over only the actual where-clauses written by the - /// user.) - query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the + /// predicates (where-clauses) that must be proven true in order + /// to reference it. This is almost always the "predicates query" + /// that you want. + /// + /// `predicates_of` builds on `predicates_defined_on` -- in fact, + /// it is almost always the same as that query, except for the + /// case of traits. For traits, `predicates_of` contains + /// an additional `Self: Trait<...>` predicate that users don't + /// actually write. This reflects the fact that to invoke the + /// trait (e.g., via `Default::default`) you must supply types + /// that actually implement the trait. (However, this extra + /// predicate gets in the way of some checks, which are intended + /// to operate over only the actual where-clauses written by the + /// user.) + query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } - /// Returns the list of bounds that can be used for - /// `SelectionCandidate::ProjectionCandidate(_)` and - /// `ProjectionTyCandidate::TraitDef`. - /// Specifically this is the bounds written on the trait's type - /// definition, or those after the `impl` keyword - /// - /// ```ignore (incomplete) - /// type X: Bound + 'lt - /// // ^^^^^^^^^^^ - /// impl Debug + Display - /// // ^^^^^^^^^^^^^^^ - /// ``` - /// - /// `key` is the `DefId` of the associated type or opaque type. - /// - /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { - desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } - } + /// Returns the list of bounds that can be used for + /// `SelectionCandidate::ProjectionCandidate(_)` and + /// `ProjectionTyCandidate::TraitDef`. + /// Specifically this is the bounds written on the trait's type + /// definition, or those after the `impl` keyword + /// + /// ```ignore (incomplete) + /// type X: Bound + 'lt + /// // ^^^^^^^^^^^ + /// impl Debug + Display + /// // ^^^^^^^^^^^^^^^ + /// ``` + /// + /// `key` is the `DefId` of the associated type or opaque type. + /// + /// Bounds from the parent (e.g. with nested impl trait) are not included. + query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { + desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } + } - /// Elaborated version of the predicates from `explicit_item_bounds`. - /// - /// For example: - /// - /// ``` - /// trait MyTrait { - /// type MyAType: Eq + ?Sized; - /// } - /// ``` - /// - /// `explicit_item_bounds` returns `[::MyAType: Eq]`, - /// and `item_bounds` returns - /// ```text - /// [ - /// ::MyAType: Eq, - /// ::MyAType: PartialEq<::MyAType> - /// ] - /// ``` - /// - /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> &'tcx ty::List> { - desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } - } + /// Elaborated version of the predicates from `explicit_item_bounds`. + /// + /// For example: + /// + /// ``` + /// trait MyTrait { + /// type MyAType: Eq + ?Sized; + /// } + /// ``` + /// + /// `explicit_item_bounds` returns `[::MyAType: Eq]`, + /// and `item_bounds` returns + /// ```text + /// [ + /// ::MyAType: Eq, + /// ::MyAType: PartialEq<::MyAType> + /// ] + /// ``` + /// + /// Bounds from the parent (e.g. with nested impl trait) are not included. + query item_bounds(key: DefId) -> &'tcx ty::List> { + desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } + } - query projection_ty_from_predicates(key: (DefId, DefId)) -> Option> { - desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) } - } + query projection_ty_from_predicates(key: (DefId, DefId)) -> Option> { + desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) } + } - query native_libraries(_: CrateNum) -> Lrc> { - desc { "looking up the native libraries of a linked crate" } - } + query native_libraries(_: CrateNum) -> Lrc> { + desc { "looking up the native libraries of a linked crate" } + } - query lint_levels(_: CrateNum) -> LintLevelMap { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "computing the lint levels for items in this crate" } - } + query lint_levels(_: CrateNum) -> LintLevelMap { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "computing the lint levels for items in this crate" } + } - query parent_module_from_def_id(key: LocalDefId) -> LocalDefId { - eval_always - desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) } - } + query parent_module_from_def_id(key: LocalDefId) -> LocalDefId { + eval_always + desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Internal helper query. Use `tcx.expansion_that_defined` instead - query expn_that_defined(key: DefId) -> rustc_span::ExpnId { - desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) } - } + /// Internal helper query. Use `tcx.expansion_that_defined` instead + query expn_that_defined(key: DefId) -> rustc_span::ExpnId { + desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) } + } - query is_panic_runtime(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate is_panic_runtime" } - } + query is_panic_runtime(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate is_panic_runtime" } + } - /// Set of all the `DefId`s in this crate that have MIR associated with - /// them. This includes all the body owners, but also things like struct - /// constructors. - query mir_keys(_: CrateNum) -> FxHashSet { - storage(ArenaCacheSelector<'tcx>) - desc { "getting a list of all mir_keys" } - } + /// Set of all the `DefId`s in this crate that have MIR associated with + /// them. This includes all the body owners, but also things like struct + /// constructors. + query mir_keys(_: CrateNum) -> FxHashSet { + storage(ArenaCacheSelector<'tcx>) + desc { "getting a list of all mir_keys" } + } - /// Maps DefId's that have an associated `mir::Body` to the result - /// of the MIR const-checking pass. This is the set of qualifs in - /// the final value of a `const`. - query mir_const_qualif(key: DefId) -> mir::ConstQualifs { - desc { |tcx| "const checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } - query mir_const_qualif_const_arg( - key: (LocalDefId, DefId) - ) -> mir::ConstQualifs { - desc { - |tcx| "const checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } + /// Maps DefId's that have an associated `mir::Body` to the result + /// of the MIR const-checking pass. This is the set of qualifs in + /// the final value of a `const`. + query mir_const_qualif(key: DefId) -> mir::ConstQualifs { + desc { |tcx| "const checking `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } + query mir_const_qualif_const_arg( + key: (LocalDefId, DefId) + ) -> mir::ConstQualifs { + desc { + |tcx| "const checking the const argument `{}`", + tcx.def_path_str(key.0.to_def_id()) } + } - /// Fetch the MIR for a given `DefId` right after it's built - this includes - /// unreachable code. - query mir_built(key: ty::WithOptConstParam) -> &'tcx Steal> { - desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) } - } + /// Fetch the MIR for a given `DefId` right after it's built - this includes + /// unreachable code. + query mir_built(key: ty::WithOptConstParam) -> &'tcx Steal> { + desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) } + } - /// Fetch the MIR for a given `DefId` up till the point where it is - /// ready for const qualification. - /// - /// See the README for the `mir` module for details. - query mir_const(key: ty::WithOptConstParam) -> &'tcx Steal> { - desc { - |tcx| "processing MIR for {}`{}`", - if key.const_param_did.is_some() { "the const argument " } else { "" }, - tcx.def_path_str(key.did.to_def_id()), - } - no_hash - } + /// Fetch the MIR for a given `DefId` up till the point where it is + /// ready for const qualification. + /// + /// See the README for the `mir` module for details. + query mir_const(key: ty::WithOptConstParam) -> &'tcx Steal> { + desc { + |tcx| "processing MIR for {}`{}`", + if key.const_param_did.is_some() { "the const argument " } else { "" }, + tcx.def_path_str(key.did.to_def_id()), + } + no_hash + } - /// Try to build an abstract representation of the given constant. - query mir_abstract_const( - key: DefId - ) -> Result]>, ErrorReported> { - desc { - |tcx| "building an abstract representation for {}", tcx.def_path_str(key), - } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const( + key: DefId + ) -> Result]>, ErrorReported> { + desc { + |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } - /// Try to build an abstract representation of the given constant. - query mir_abstract_const_of_const_arg( - key: (LocalDefId, DefId) - ) -> Result]>, ErrorReported> { - desc { - |tcx| - "building an abstract representation for the const argument {}", - tcx.def_path_str(key.0.to_def_id()), - } + } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const_of_const_arg( + key: (LocalDefId, DefId) + ) -> Result]>, ErrorReported> { + desc { + |tcx| + "building an abstract representation for the const argument {}", + tcx.def_path_str(key.0.to_def_id()), } + } - query try_unify_abstract_consts(key: ( - (ty::WithOptConstParam, SubstsRef<'tcx>), - (ty::WithOptConstParam, SubstsRef<'tcx>) - )) -> bool { - desc { - |tcx| "trying to unify the generic constants {} and {}", - tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) - } + query try_unify_abstract_consts(key: ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>) + )) -> bool { + desc { + |tcx| "trying to unify the generic constants {} and {}", + tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) } + } - query mir_drops_elaborated_and_const_checked( - key: ty::WithOptConstParam - ) -> &'tcx Steal> { - no_hash - desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) } - } + query mir_drops_elaborated_and_const_checked( + key: ty::WithOptConstParam + ) -> &'tcx Steal> { + no_hash + desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) } + } - query mir_for_ctfe( - key: DefId - ) -> &'tcx mir::Body<'tcx> { - desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } + query mir_for_ctfe( + key: DefId + ) -> &'tcx mir::Body<'tcx> { + desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } - query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> { - desc { - |tcx| "MIR for CTFE of the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } + query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> { + desc { + |tcx| "MIR for CTFE of the const argument `{}`", + tcx.def_path_str(key.0.to_def_id()) } + } - query mir_promoted(key: ty::WithOptConstParam) -> - ( - &'tcx Steal>, - &'tcx Steal>> - ) { - no_hash - desc { - |tcx| "processing {}`{}`", - if key.const_param_did.is_some() { "the const argument " } else { "" }, - tcx.def_path_str(key.did.to_def_id()), - } + query mir_promoted(key: ty::WithOptConstParam) -> + ( + &'tcx Steal>, + &'tcx Steal>> + ) { + no_hash + desc { + |tcx| "processing {}`{}`", + if key.const_param_did.is_some() { "the const argument " } else { "" }, + tcx.def_path_str(key.did.to_def_id()), } + } - /// MIR after our optimization passes have run. This is MIR that is ready - /// for codegen. This is also the only query that can fetch non-local MIR, at present. - query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { - desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } + /// MIR after our optimization passes have run. This is MIR that is ready + /// for codegen. This is also the only query that can fetch non-local MIR, at present. + query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { + desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } - /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` - /// MIR pass (assuming the -Zinstrument-coverage option is enabled). - query coverageinfo(key: DefId) -> mir::CoverageInfo { - desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) - cache_on_disk_if { key.is_local() } - } + /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` + /// MIR pass (assuming the -Zinstrument-coverage option is enabled). + query coverageinfo(key: DefId) -> mir::CoverageInfo { + desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } - /// Returns the name of the file that contains the function body, if instrumented for coverage. - query covered_file_name(key: DefId) -> Option { - desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) - cache_on_disk_if { key.is_local() } - } + /// Returns the name of the file that contains the function body, if instrumented for coverage. + query covered_file_name(key: DefId) -> Option { + desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } - /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the - /// function was optimized out before codegen, and before being added to the Coverage Map. - query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> { - desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) - cache_on_disk_if { key.is_local() } - } + /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the + /// function was optimized out before codegen, and before being added to the Coverage Map. + query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> { + desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } - /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own - /// `DefId`. This function returns all promoteds in the specified body. The body references - /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because - /// after inlining a body may refer to promoteds from other bodies. In that case you still - /// need to use the `DefId` of the original body. - query promoted_mir(key: DefId) -> &'tcx IndexVec> { - desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } - query promoted_mir_of_const_arg( - key: (LocalDefId, DefId) - ) -> &'tcx IndexVec> { - desc { - |tcx| "optimizing promoted MIR for the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()), - } + /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own + /// `DefId`. This function returns all promoteds in the specified body. The body references + /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because + /// after inlining a body may refer to promoteds from other bodies. In that case you still + /// need to use the `DefId` of the original body. + query promoted_mir(key: DefId) -> &'tcx IndexVec> { + desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } + query promoted_mir_of_const_arg( + key: (LocalDefId, DefId) + ) -> &'tcx IndexVec> { + desc { + |tcx| "optimizing promoted MIR for the const argument `{}`", + tcx.def_path_str(key.0.to_def_id()), } + } - /// Erases regions from `ty` to yield a new type. - /// Normally you would just use `tcx.erase_regions(value)`, - /// however, which uses this query as a kind of cache. - query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { - // This query is not expected to have input -- as a result, it - // is not a good candidates for "replay" because it is essentially a - // pure function of its input (and hence the expectation is that - // no caller would be green **apart** from just these - // queries). Making it anonymous avoids hashing the result, which - // may save a bit of time. - anon - desc { "erasing regions from `{:?}`", ty } - } + /// Erases regions from `ty` to yield a new type. + /// Normally you would just use `tcx.erase_regions(value)`, + /// however, which uses this query as a kind of cache. + query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { + // This query is not expected to have input -- as a result, it + // is not a good candidates for "replay" because it is essentially a + // pure function of its input (and hence the expectation is that + // no caller would be green **apart** from just these + // queries). Making it anonymous avoids hashing the result, which + // may save a bit of time. + anon + desc { "erasing regions from `{:?}`", ty } + } - query wasm_import_module_map(_: CrateNum) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) - desc { "wasm import module map" } - } + query wasm_import_module_map(_: CrateNum) -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "wasm import module map" } + } - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the - /// predicates (where-clauses) directly defined on it. This is - /// equal to the `explicit_predicates_of` predicates plus the - /// `inferred_outlives_of` predicates. - query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } - } + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the + /// predicates (where-clauses) directly defined on it. This is + /// equal to the `explicit_predicates_of` predicates plus the + /// `inferred_outlives_of` predicates. + query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } + } - /// Returns everything that looks like a predicate written explicitly - /// by the user on a trait item. - /// - /// Traits are unusual, because predicates on associated types are - /// converted into bounds on that type for backwards compatibility: - /// - /// trait X where Self::U: Copy { type U; } - /// - /// becomes - /// - /// trait X { type U: Copy; } - /// - /// `explicit_predicates_of` and `explicit_item_bounds` will then take - /// the appropriate subsets of the predicates here. - query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) } - } + /// Returns everything that looks like a predicate written explicitly + /// by the user on a trait item. + /// + /// Traits are unusual, because predicates on associated types are + /// converted into bounds on that type for backwards compatibility: + /// + /// trait X where Self::U: Copy { type U; } + /// + /// becomes + /// + /// trait X { type U: Copy; } + /// + /// `explicit_predicates_of` and `explicit_item_bounds` will then take + /// the appropriate subsets of the predicates here. + query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Returns the predicates written explicitly by the user. - query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } - } + /// Returns the predicates written explicitly by the user. + query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } + } - /// Returns the inferred outlives predicates (e.g., for `struct - /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { - desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } - } + /// Returns the inferred outlives predicates (e.g., for `struct + /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). + query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { + desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } + } - /// Maps from the `DefId` of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } - } + /// Maps from the `DefId` of a trait to the list of + /// super-predicates. This is a subset of the full list of + /// predicates. We store these in a separate map because we must + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } + } - /// To avoid cycles within the predicates of a single item we compute - /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the bounds for type parameter `{}`", { - let id = tcx.hir().local_def_id_to_hir_id(key.1); - tcx.hir().ty_param_name(id) - }} - } + /// To avoid cycles within the predicates of a single item we compute + /// per-type-parameter predicates for resolving `T::AssocTy`. + query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the bounds for type parameter `{}`", { + let id = tcx.hir().local_def_id_to_hir_id(key.1); + tcx.hir().ty_param_name(id) + }} + } - query trait_def(key: DefId) -> ty::TraitDef { - desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) - } - query adt_def(key: DefId) -> &'tcx ty::AdtDef { - desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) } - } - query adt_destructor(key: DefId) -> Option { - desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) } - } + query trait_def(key: DefId) -> ty::TraitDef { + desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + } + query adt_def(key: DefId) -> &'tcx ty::AdtDef { + desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) } + } + query adt_destructor(key: DefId) -> Option { + desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) } + } - // The cycle error here should be reported as an error by `check_representable`. - // We consider the type as Sized in the meanwhile to avoid - // further errors (done in impl Value for AdtSizedConstraint). - // Use `cycle_delay_bug` to delay the cycle error here to be emitted later - // in case we accidentally otherwise don't emit an error. - query adt_sized_constraint( - key: DefId - ) -> AdtSizedConstraint<'tcx> { - desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } - cycle_delay_bug - } + // The cycle error here should be reported as an error by `check_representable`. + // We consider the type as Sized in the meanwhile to avoid + // further errors (done in impl Value for AdtSizedConstraint). + // Use `cycle_delay_bug` to delay the cycle error here to be emitted later + // in case we accidentally otherwise don't emit an error. + query adt_sized_constraint( + key: DefId + ) -> AdtSizedConstraint<'tcx> { + desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } + cycle_delay_bug + } - query adt_dtorck_constraint( - key: DefId - ) -> Result, NoSolution> { - desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } - } + query adt_dtorck_constraint( + key: DefId + ) -> Result, NoSolution> { + desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } + } - /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate - /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might - /// not have the feature gate active). - /// - /// **Do not call this function manually.** It is only meant to cache the base data for the - /// `is_const_fn` function. - query is_const_fn_raw(key: DefId) -> bool { - desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } - } + /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate + /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might + /// not have the feature gate active). + /// + /// **Do not call this function manually.** It is only meant to cache the base data for the + /// `is_const_fn` function. + query is_const_fn_raw(key: DefId) -> bool { + desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } + } - /// Returns `true` if this is a const `impl`. **Do not call this function manually.** - /// - /// This query caches the base data for the `is_const_impl` helper function, which also - /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`). - query is_const_impl_raw(key: DefId) -> bool { - desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) } - } + /// Returns `true` if this is a const `impl`. **Do not call this function manually.** + /// + /// This query caches the base data for the `is_const_impl` helper function, which also + /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`). + query is_const_impl_raw(key: DefId) -> bool { + desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) } + } - query asyncness(key: DefId) -> hir::IsAsync { - desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } - } + query asyncness(key: DefId) -> hir::IsAsync { + desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } + } - /// Returns `true` if calls to the function may be promoted. - /// - /// This is either because the function is e.g., a tuple-struct or tuple-variant - /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should - /// be removed in the future in favour of some form of check which figures out whether the - /// function does not inspect the bits of any of its arguments (so is essentially just a - /// constructor function). - query is_promotable_const_fn(key: DefId) -> bool { - desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } - } + /// Returns `true` if calls to the function may be promoted. + /// + /// This is either because the function is e.g., a tuple-struct or tuple-variant + /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should + /// be removed in the future in favour of some form of check which figures out whether the + /// function does not inspect the bits of any of its arguments (so is essentially just a + /// constructor function). + query is_promotable_const_fn(key: DefId) -> bool { + desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } + } - /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). - query is_foreign_item(key: DefId) -> bool { - desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } - } + /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). + query is_foreign_item(key: DefId) -> bool { + desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } + } - /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item. - query static_mutability(def_id: DefId) -> Option { - desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) } - } + /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item. + query static_mutability(def_id: DefId) -> Option { + desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) } + } - /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. - query generator_kind(def_id: DefId) -> Option { - desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } - } + /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. + query generator_kind(def_id: DefId) -> Option { + desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } + } - /// Gets a map with the variance of every item; use `item_variance` instead. - query crate_variances(_: CrateNum) -> ty::CrateVariancesMap<'tcx> { - storage(ArenaCacheSelector<'tcx>) - desc { "computing the variances for items in this crate" } - } + /// Gets a map with the variance of every item; use `item_variance` instead. + query crate_variances(_: CrateNum) -> ty::CrateVariancesMap<'tcx> { + storage(ArenaCacheSelector<'tcx>) + desc { "computing the variances for items in this crate" } + } - /// Maps from the `DefId` of a type or region parameter to its (inferred) variance. - query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { - desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) } - } + /// Maps from the `DefId` of a type or region parameter to its (inferred) variance. + query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { + desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) } + } - /// Maps from thee `DefId` of a type to its (inferred) outlives. - query inferred_outlives_crate(_: CrateNum) - -> ty::CratePredicatesMap<'tcx> { - storage(ArenaCacheSelector<'tcx>) - desc { "computing the inferred outlives predicates for items in this crate" } - } - - /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. - query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { - desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } - } + /// Maps from thee `DefId` of a type to its (inferred) outlives. + query inferred_outlives_crate(_: CrateNum) + -> ty::CratePredicatesMap<'tcx> { + storage(ArenaCacheSelector<'tcx>) + desc { "computing the inferred outlives predicates for items in this crate" } + } - /// Maps from a trait item to the trait item "descriptor". - query associated_item(key: DefId) -> ty::AssocItem { - desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) - } + /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. + query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { + desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } + } - /// Collects the associated items defined on a trait or impl. - query associated_items(key: DefId) -> ty::AssociatedItems<'tcx> { - storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } - } + /// Maps from a trait item to the trait item "descriptor". + query associated_item(key: DefId) -> ty::AssocItem { + desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + } - /// Given an `impl_id`, return the trait it implements. - /// Return `None` if this is an inherent impl. - query impl_trait_ref(impl_id: DefId) -> Option> { - desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } - } - query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { - desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } - } + /// Collects the associated items defined on a trait or impl. + query associated_items(key: DefId) -> ty::AssociatedItems<'tcx> { + storage(ArenaCacheSelector<'tcx>) + desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } + } - query issue33140_self_ty(key: DefId) -> Option> { - desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } - } - - /// Maps a `DefId` of a type to a list of its inherent impls. - /// Contains implementations of methods that are inherent to a type. - /// Methods in these implementations don't need to be exported. - query inherent_impls(key: DefId) -> &'tcx [DefId] { - desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } - eval_always - } - - /// The result of unsafety-checking this `LocalDefId`. - query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult { - desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if { true } - } - query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult { - desc { - |tcx| "unsafety-checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } + /// Given an `impl_id`, return the trait it implements. + /// Return `None` if this is an inherent impl. + query impl_trait_ref(impl_id: DefId) -> Option> { + desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } + } + query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { + desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } + } - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error. - /// - /// Unsafety checking is executed for each method separately, but we only want - /// to emit this error once per derive. As there are some impls with multiple - /// methods, we use a query for deduplication. - query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } - } + query issue33140_self_ty(key: DefId) -> Option> { + desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } + } - /// The signature of functions. - query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { - desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } - } - - query lint_mod(key: LocalDefId) -> () { - desc { |tcx| "linting {}", describe_as_module(key, tcx) } - } + /// Maps a `DefId` of a type to a list of its inherent impls. + /// Contains implementations of methods that are inherent to a type. + /// Methods in these implementations don't need to be exported. + query inherent_impls(key: DefId) -> &'tcx [DefId] { + desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } + eval_always + } - /// Checks the attributes in the module. - query check_mod_attrs(key: LocalDefId) -> () { - desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) } + /// The result of unsafety-checking this `LocalDefId`. + query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult { + desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } + } + query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult { + desc { + |tcx| "unsafety-checking the const argument `{}`", + tcx.def_path_str(key.0.to_def_id()) } + } - query check_mod_unstable_api_usage(key: LocalDefId) -> () { - desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } - } + /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error. + /// + /// Unsafety checking is executed for each method separately, but we only want + /// to emit this error once per derive. As there are some impls with multiple + /// methods, we use a query for deduplication. + query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { + desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } + } - /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`). - query check_mod_const_bodies(key: LocalDefId) -> () { - desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) } - } + /// The signature of functions. + query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { + desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } + } - /// Checks the loops in the module. - query check_mod_loops(key: LocalDefId) -> () { - desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } - } + query lint_mod(key: LocalDefId) -> () { + desc { |tcx| "linting {}", describe_as_module(key, tcx) } + } - query check_mod_naked_functions(key: LocalDefId) -> () { - desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } - } + /// Checks the attributes in the module. + query check_mod_attrs(key: LocalDefId) -> () { + desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) } + } - query check_mod_item_types(key: LocalDefId) -> () { - desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } - } + query check_mod_unstable_api_usage(key: LocalDefId) -> () { + desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } + } - query check_mod_privacy(key: LocalDefId) -> () { - desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } - } + /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`). + query check_mod_const_bodies(key: LocalDefId) -> () { + desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) } + } - query check_mod_intrinsics(key: LocalDefId) -> () { - desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) } - } + /// Checks the loops in the module. + query check_mod_loops(key: LocalDefId) -> () { + desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } + } - query check_mod_liveness(key: LocalDefId) -> () { - desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } - } + query check_mod_naked_functions(key: LocalDefId) -> () { + desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } + } - query check_mod_impl_wf(key: LocalDefId) -> () { - desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } - } + query check_mod_item_types(key: LocalDefId) -> () { + desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } + } - query collect_mod_item_types(key: LocalDefId) -> () { - desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } - } + query check_mod_privacy(key: LocalDefId) -> () { + desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } + } - /// Caches `CoerceUnsized` kinds for impls on custom types. - query coerce_unsized_info(key: DefId) - -> ty::adjustment::CoerceUnsizedInfo { - desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } - } - - query typeck_item_bodies(_: CrateNum) -> () { - desc { "type-checking all item bodies" } - } + query check_mod_intrinsics(key: LocalDefId) -> () { + desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) } + } - query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { - desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if { true } - } - query typeck_const_arg( - key: (LocalDefId, DefId) - ) -> &'tcx ty::TypeckResults<'tcx> { - desc { - |tcx| "type-checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()), - } - } - query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { - desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if { true } - load_cached(tcx, id) { - let typeck_results: Option> = tcx - .queries.on_disk_cache.as_ref() - .and_then(|c| c.try_load_query_result(tcx, id)); - - typeck_results.map(|x| &*tcx.arena.alloc(x)) - } - } - - query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet { - desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if { true } - } - - query has_typeck_results(def_id: DefId) -> bool { - desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) } - } + query check_mod_liveness(key: LocalDefId) -> () { + desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } + } - query coherent_trait(def_id: DefId) -> () { - desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } - } - - /// Borrow-checks the function body. If this is a closure, returns - /// additional requirements that the closure's creator must verify. - query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { - desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if(tcx, opt_result) { - tcx.is_closure(key.to_def_id()) - || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty()) - } - } - query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { - desc { - |tcx| "borrow-checking the const argument`{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } - - /// Gets a complete map from all types to their inherent impls. - /// Not meant to be used directly outside of coherence. - /// (Defined only for `LOCAL_CRATE`.) - query crate_inherent_impls(k: CrateNum) - -> CrateInherentImpls { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "all inherent impls defined in crate `{:?}`", k } - } + query check_mod_impl_wf(key: LocalDefId) -> () { + desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } + } - /// Checks all types in the crate for overlap in their inherent impls. Reports errors. - /// Not meant to be used directly outside of coherence. - /// (Defined only for `LOCAL_CRATE`.) - query crate_inherent_impls_overlap_check(_: CrateNum) - -> () { - eval_always - desc { "check for overlap between inherent impls defined in this crate" } - } - - /// Check whether the function has any recursion that could cause the inliner to trigger - /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the - /// current function, just all intermediate functions. - query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { - fatal_cycle - desc { |tcx| - "computing if `{}` (transitively) calls `{}`", - key.0, - tcx.def_path_str(key.1.to_def_id()), - } - } + query collect_mod_item_types(key: LocalDefId) -> () { + desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } + } - /// Obtain all the calls into other local functions - query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] { - fatal_cycle - desc { |tcx| - "computing all local function calls in `{}`", - tcx.def_path_str(key.def_id()), - } + /// Caches `CoerceUnsized` kinds for impls on custom types. + query coerce_unsized_info(key: DefId) + -> ty::adjustment::CoerceUnsizedInfo { + desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } } - /// Evaluates a constant and returns the computed allocation. - /// - /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. - query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> EvalToAllocationRawResult<'tcx> { - desc { |tcx| - "const-evaluating + checking `{}`", - key.value.display(tcx) - } - cache_on_disk_if { true } - } + query typeck_item_bodies(_: CrateNum) -> () { + desc { "type-checking all item bodies" } + } - /// Evaluates const items or anonymous constants - /// (such as enum variant explicit discriminants or array lengths) - /// into a representation suitable for the type system and const generics. - /// - /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, - /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> EvalToConstValueResult<'tcx> { - desc { |tcx| - "simplifying constant for the type system `{}`", - key.value.display(tcx) - } - cache_on_disk_if { true } + query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { + desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } + } + query typeck_const_arg( + key: (LocalDefId, DefId) + ) -> &'tcx ty::TypeckResults<'tcx> { + desc { + |tcx| "type-checking the const argument `{}`", + tcx.def_path_str(key.0.to_def_id()), } + } + query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { + desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } + load_cached(tcx, id) { + let typeck_results: Option> = tcx + .queries.on_disk_cache.as_ref() + .and_then(|c| c.try_load_query_result(tcx, id)); - /// Destructure a constant ADT or array into its variant index and its - /// field values. - query destructure_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> - ) -> mir::DestructuredConst<'tcx> { - desc { "destructure constant" } + typeck_results.map(|x| &*tcx.arena.alloc(x)) } + } - /// Dereference a constant reference or raw pointer and turn the result into a constant - /// again. - query deref_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> - ) -> &'tcx ty::Const<'tcx> { - desc { "deref constant" } - } + query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet { + desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } + } - query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { - desc { "get a &core::panic::Location referring to a span" } - } + query has_typeck_results(def_id: DefId) -> bool { + desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) } + } - query lit_to_const( - key: LitToConstInput<'tcx> - ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { - desc { "converting literal to const" } - } - - query check_match(key: DefId) { - desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } - } + query coherent_trait(def_id: DefId) -> () { + desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } + } - /// Performs part of the privacy check and computes "access levels". - query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels { - eval_always - desc { "privacy access levels" } + /// Borrow-checks the function body. If this is a closure, returns + /// additional requirements that the closure's creator must verify. + query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { + desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if(tcx, opt_result) { + tcx.is_closure(key.to_def_id()) + || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty()) } - query check_private_in_public(_: CrateNum) -> () { - eval_always - desc { "checking for private elements in public interfaces" } - } - - query reachable_set(_: CrateNum) -> FxHashSet { - storage(ArenaCacheSelector<'tcx>) - desc { "reachability" } + } + query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { + desc { + |tcx| "borrow-checking the const argument`{}`", + tcx.def_path_str(key.0.to_def_id()) } + } - /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; - /// in the case of closures, this will be redirected to the enclosing function. - query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree { - desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) } - } + /// Gets a complete map from all types to their inherent impls. + /// Not meant to be used directly outside of coherence. + /// (Defined only for `LOCAL_CRATE`.) + query crate_inherent_impls(k: CrateNum) + -> CrateInherentImpls { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "all inherent impls defined in crate `{:?}`", k } + } - query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> { - storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } - } + /// Checks all types in the crate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for `LOCAL_CRATE`.) + query crate_inherent_impls_overlap_check(_: CrateNum) + -> () { + eval_always + desc { "check for overlap between inherent impls defined in this crate" } + } - /// The `symbol_name` query provides the symbol name for calling a - /// given instance from the local crate. In particular, it will also - /// look up the correct symbol name of instances from upstream crates. - query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName<'tcx> { - desc { "computing the symbol for `{}`", key } - cache_on_disk_if { true } + /// Check whether the function has any recursion that could cause the inliner to trigger + /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the + /// current function, just all intermediate functions. + query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { + fatal_cycle + desc { |tcx| + "computing if `{}` (transitively) calls `{}`", + key.0, + tcx.def_path_str(key.1.to_def_id()), } + } - query opt_def_kind(def_id: DefId) -> Option { - desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } + /// Obtain all the calls into other local functions + query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] { + fatal_cycle + desc { |tcx| + "computing all local function calls in `{}`", + tcx.def_path_str(key.def_id()), } + } - query def_span(def_id: DefId) -> Span { - desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } - // FIXME(mw): DefSpans are not really inputs since they are derived from - // HIR. But at the moment HIR hashing still contains some hacks that allow - // to make type debuginfo to be source location independent. Declaring - // DefSpan an input makes sure that changes to these are always detected - // regardless of HIR hashing. - eval_always + /// Evaluates a constant and returns the computed allocation. + /// + /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToAllocationRawResult<'tcx> { + desc { |tcx| + "const-evaluating + checking `{}`", + key.value.display(tcx) } + cache_on_disk_if { true } + } - query def_ident_span(def_id: DefId) -> Option { - desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) } - } + /// Evaluates const items or anonymous constants + /// (such as enum variant explicit discriminants or array lengths) + /// into a representation suitable for the type system and const generics. + /// + /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, + /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. + query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToConstValueResult<'tcx> { + desc { |tcx| + "simplifying constant for the type system `{}`", + key.value.display(tcx) + } + cache_on_disk_if { true } + } - query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> { - desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) } - } + /// Destructure a constant ADT or array into its variant index and its + /// field values. + query destructure_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> mir::DestructuredConst<'tcx> { + desc { "destructure constant" } + } - query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> { - desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) } - } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> &'tcx ty::Const<'tcx> { + desc { "deref constant" } + } - query lookup_deprecation_entry(def_id: DefId) -> Option { - desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) } - } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { + desc { "get a &core::panic::Location referring to a span" } + } - query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { - desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } - } - - query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { - desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } - storage(ArenaCacheSelector<'tcx>) - cache_on_disk_if { true } - } + query lit_to_const( + key: LitToConstInput<'tcx> + ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { + desc { "converting literal to const" } + } - query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] { - desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } - } - /// Gets the rendered value of the specified constant or associated constant. - /// Used by rustdoc. - query rendered_const(def_id: DefId) -> String { - desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } - } - query impl_parent(def_id: DefId) -> Option { - desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } - } + query check_match(key: DefId) { + desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } - /// Given an `associated_item`, find the trait it belongs to. - /// Return `None` if the `DefId` is not an associated item. - query trait_of_item(associated_item: DefId) -> Option { - desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } - } + /// Performs part of the privacy check and computes "access levels". + query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels { + eval_always + desc { "privacy access levels" } + } + query check_private_in_public(_: CrateNum) -> () { + eval_always + desc { "checking for private elements in public interfaces" } + } - query is_ctfe_mir_available(key: DefId) -> bool { - desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) } - } - query is_mir_available(key: DefId) -> bool { - desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } - } + query reachable_set(_: CrateNum) -> FxHashSet { + storage(ArenaCacheSelector<'tcx>) + desc { "reachability" } + } - query vtable_methods(key: ty::PolyTraitRef<'tcx>) - -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { - desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } - } + /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; + /// in the case of closures, this will be redirected to the enclosing function. + query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree { + desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) } + } - query codegen_fulfill_obligation( - key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Result, ErrorReported> { - cache_on_disk_if { true } - desc { |tcx| - "checking if `{}` fulfills its obligations", - tcx.def_path_str(key.1.def_id()) - } - } + query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> { + storage(ArenaCacheSelector<'tcx>) + desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } + } - /// Return all `impl` blocks in the current crate. - /// - /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. - /// Passing in any other crate will cause an ICE. - /// - /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE - query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap> { - desc { "local trait impls" } - } + /// The `symbol_name` query provides the symbol name for calling a + /// given instance from the local crate. In particular, it will also + /// look up the correct symbol name of instances from upstream crates. + query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName<'tcx> { + desc { "computing the symbol for `{}`", key } + cache_on_disk_if { true } + } - /// Given a trait `trait_id`, return all known `impl` blocks. - query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { - storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) } - } + query opt_def_kind(def_id: DefId) -> Option { + desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } + } - query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { - storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } - cache_on_disk_if { true } - } - query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { - desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) } - } + query def_span(def_id: DefId) -> Span { + desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } + // FIXME(mw): DefSpans are not really inputs since they are derived from + // HIR. But at the moment HIR hashing still contains some hacks that allow + // to make type debuginfo to be source location independent. Declaring + // DefSpan an input makes sure that changes to these are always detected + // regardless of HIR hashing. + eval_always + } - /// Gets the ParameterEnvironment for a given item; this environment - /// will be in "user-facing" mode, meaning that it is suitable for - /// type-checking etc, and it does not normalize specializable - /// associated types. This is almost always what you want, - /// unless you are doing MIR optimizations, in which case you - /// might want to use `reveal_all()` method to change modes. - query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { - desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } - } + query def_ident_span(def_id: DefId) -> Option { + desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) } + } - /// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode. - /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`, - /// as this method is more efficient. - query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> { - desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) } - } + query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> { + desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) } + } - /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, - /// `ty.is_copy()`, etc, since that will prune the environment where possible. - query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - desc { "computing whether `{}` is `Copy`", env.value } - } - /// Query backing `TyS::is_sized`. - query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - desc { "computing whether `{}` is `Sized`", env.value } - } - /// Query backing `TyS::is_freeze`. - query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - desc { "computing whether `{}` is freeze", env.value } - } - /// Query backing `TyS::needs_drop`. - query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - desc { "computing whether `{}` needs drop", env.value } - } + query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> { + desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) } + } - /// Query backing `TyS::is_structural_eq_shallow`. - /// - /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types - /// correctly. - query has_structural_eq_impls(ty: Ty<'tcx>) -> bool { - desc { - "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`", - ty - } - } + query lookup_deprecation_entry(def_id: DefId) -> Option { + desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) } + } - /// A list of types where the ADT requires drop if and only if any of - /// those types require drop. If the ADT is known to always need drop - /// then `Err(AlwaysRequiresDrop)` is returned. - query adt_drop_tys(def_id: DefId) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> { - desc { |tcx| "computing when `{}` needs drop", tcx.def_path_str(def_id) } - cache_on_disk_if { true } - } + query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { + desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } + } - query layout_raw( - env: ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Result<&'tcx rustc_target::abi::Layout, ty::layout::LayoutError<'tcx>> { - desc { "computing layout of `{}`", env.value } - } + query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { + desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { true } + } - query dylib_dependency_formats(_: CrateNum) - -> &'tcx [(CrateNum, LinkagePreference)] { - desc { "dylib dependency formats of crate" } - } + query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] { + desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } + } + /// Gets the rendered value of the specified constant or associated constant. + /// Used by rustdoc. + query rendered_const(def_id: DefId) -> String { + desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } + } + query impl_parent(def_id: DefId) -> Option { + desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } + } - query dependency_formats(_: CrateNum) - -> Lrc - { - desc { "get the linkage format of all dependencies" } - } + /// Given an `associated_item`, find the trait it belongs to. + /// Return `None` if the `DefId` is not an associated item. + query trait_of_item(associated_item: DefId) -> Option { + desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } + } - query is_compiler_builtins(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate is_compiler_builtins" } - } - query has_global_allocator(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate has_global_allocator" } - } - query has_panic_handler(_: CrateNum) -> bool { - fatal_cycle - desc { "checking if the crate has_panic_handler" } - } - query is_profiler_runtime(_: CrateNum) -> bool { - fatal_cycle - desc { "query a crate is `#![profiler_runtime]`" } - } - query panic_strategy(_: CrateNum) -> PanicStrategy { - fatal_cycle - desc { "query a crate's configured panic strategy" } - } - query is_no_builtins(_: CrateNum) -> bool { - fatal_cycle - desc { "test whether a crate has `#![no_builtins]`" } - } - query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { - fatal_cycle - desc { "query a crate's symbol mangling version" } - } + query is_ctfe_mir_available(key: DefId) -> bool { + desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) } + } + query is_mir_available(key: DefId) -> bool { + desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } + } - query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> { - eval_always - desc { "getting crate's ExternCrateData" } - } + query vtable_methods(key: ty::PolyTraitRef<'tcx>) + -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { + desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } + } - query specializes(_: (DefId, DefId)) -> bool { - desc { "computing whether impls specialize one another" } - } - query in_scope_traits_map(_: LocalDefId) - -> Option<&'tcx FxHashMap>> { - eval_always - desc { "traits in scope at a block" } + query codegen_fulfill_obligation( + key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) + ) -> Result, ErrorReported> { + cache_on_disk_if { true } + desc { |tcx| + "checking if `{}` fulfills its obligations", + tcx.def_path_str(key.1.def_id()) } + } - query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { - desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) } - eval_always - } + /// Return all `impl` blocks in the current crate. + /// + /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. + /// Passing in any other crate will cause an ICE. + /// + /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE + query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap> { + desc { "local trait impls" } + } - query impl_defaultness(def_id: DefId) -> hir::Defaultness { - desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } - } + /// Given a trait `trait_id`, return all known `impl` blocks. + query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { + storage(ArenaCacheSelector<'tcx>) + desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) } + } - query check_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } - } - query check_trait_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } - } - query check_impl_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } - } + query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { + storage(ArenaCacheSelector<'tcx>) + desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } + cache_on_disk_if { true } + } + query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { + desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) } + } + + /// Gets the ParameterEnvironment for a given item; this environment + /// will be in "user-facing" mode, meaning that it is suitable for + /// type-checking etc, and it does not normalize specializable + /// associated types. This is almost always what you want, + /// unless you are doing MIR optimizations, in which case you + /// might want to use `reveal_all()` method to change modes. + query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { + desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } + } - // The `DefId`s of all non-generic functions and statics in the given crate - // that can be reached from outside the crate. - // - // We expect this items to be available for being linked to. - // - // This query can also be called for `LOCAL_CRATE`. In this case it will - // compute which items will be reachable to other crates, taking into account - // the kind of crate that is currently compiled. Crates with only a - // C interface have fewer reachable things. - // - // Does not include external symbols that don't have a corresponding DefId, - // like the compiler-generated `main` function and so on. - query reachable_non_generics(_: CrateNum) - -> DefIdMap { - storage(ArenaCacheSelector<'tcx>) - desc { "looking up the exported symbols of a crate" } + /// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode. + /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`, + /// as this method is more efficient. + query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> { + desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) } + } + + /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, + /// `ty.is_copy()`, etc, since that will prune the environment where possible. + query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is `Copy`", env.value } + } + /// Query backing `TyS::is_sized`. + query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is `Sized`", env.value } + } + /// Query backing `TyS::is_freeze`. + query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is freeze", env.value } + } + /// Query backing `TyS::needs_drop`. + query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` needs drop", env.value } + } + + /// Query backing `TyS::is_structural_eq_shallow`. + /// + /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types + /// correctly. + query has_structural_eq_impls(ty: Ty<'tcx>) -> bool { + desc { + "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`", + ty } - query is_reachable_non_generic(def_id: DefId) -> bool { - desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) } + } + + /// A list of types where the ADT requires drop if and only if any of + /// those types require drop. If the ADT is known to always need drop + /// then `Err(AlwaysRequiresDrop)` is returned. + query adt_drop_tys(def_id: DefId) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> { + desc { |tcx| "computing when `{}` needs drop", tcx.def_path_str(def_id) } + cache_on_disk_if { true } + } + + query layout_raw( + env: ty::ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> Result<&'tcx rustc_target::abi::Layout, ty::layout::LayoutError<'tcx>> { + desc { "computing layout of `{}`", env.value } + } + + query dylib_dependency_formats(_: CrateNum) + -> &'tcx [(CrateNum, LinkagePreference)] { + desc { "dylib dependency formats of crate" } + } + + query dependency_formats(_: CrateNum) + -> Lrc + { + desc { "get the linkage format of all dependencies" } + } + + query is_compiler_builtins(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate is_compiler_builtins" } + } + query has_global_allocator(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate has_global_allocator" } + } + query has_panic_handler(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate has_panic_handler" } + } + query is_profiler_runtime(_: CrateNum) -> bool { + fatal_cycle + desc { "query a crate is `#![profiler_runtime]`" } + } + query panic_strategy(_: CrateNum) -> PanicStrategy { + fatal_cycle + desc { "query a crate's configured panic strategy" } + } + query is_no_builtins(_: CrateNum) -> bool { + fatal_cycle + desc { "test whether a crate has `#![no_builtins]`" } + } + query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { + fatal_cycle + desc { "query a crate's symbol mangling version" } + } + + query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> { + eval_always + desc { "getting crate's ExternCrateData" } + } + + query specializes(_: (DefId, DefId)) -> bool { + desc { "computing whether impls specialize one another" } + } + query in_scope_traits_map(_: LocalDefId) + -> Option<&'tcx FxHashMap>> { + eval_always + desc { "traits in scope at a block" } + } + + query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { + desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) } + eval_always + } + + query impl_defaultness(def_id: DefId) -> hir::Defaultness { + desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } + } + + query check_item_well_formed(key: LocalDefId) -> () { + desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } + } + query check_trait_item_well_formed(key: LocalDefId) -> () { + desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } + } + query check_impl_item_well_formed(key: LocalDefId) -> () { + desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } + } + + // The `DefId`s of all non-generic functions and statics in the given crate + // that can be reached from outside the crate. + // + // We expect this items to be available for being linked to. + // + // This query can also be called for `LOCAL_CRATE`. In this case it will + // compute which items will be reachable to other crates, taking into account + // the kind of crate that is currently compiled. Crates with only a + // C interface have fewer reachable things. + // + // Does not include external symbols that don't have a corresponding DefId, + // like the compiler-generated `main` function and so on. + query reachable_non_generics(_: CrateNum) + -> DefIdMap { + storage(ArenaCacheSelector<'tcx>) + desc { "looking up the exported symbols of a crate" } + } + query is_reachable_non_generic(def_id: DefId) -> bool { + desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) } + } + query is_unreachable_local_definition(def_id: DefId) -> bool { + desc { |tcx| + "checking whether `{}` is reachable from outside the crate", + tcx.def_path_str(def_id), } - query is_unreachable_local_definition(def_id: DefId) -> bool { + } + + /// The entire set of monomorphizations the local crate can safely link + /// to because they are exported from upstream crates. Do not depend on + /// this directly, as its value changes anytime a monomorphization gets + /// added or removed in any upstream crate. Instead use the narrower + /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even + /// better, `Instance::upstream_monomorphization()`. + query upstream_monomorphizations( + k: CrateNum + ) -> DefIdMap, CrateNum>> { + storage(ArenaCacheSelector<'tcx>) + desc { "collecting available upstream monomorphizations `{:?}`", k } + } + + /// Returns the set of upstream monomorphizations available for the + /// generic function identified by the given `def_id`. The query makes + /// sure to make a stable selection if the same monomorphization is + /// available in multiple upstream crates. + /// + /// You likely want to call `Instance::upstream_monomorphization()` + /// instead of invoking this query directly. + query upstream_monomorphizations_for(def_id: DefId) + -> Option<&'tcx FxHashMap, CrateNum>> { desc { |tcx| - "checking whether `{}` is reachable from outside the crate", + "collecting available upstream monomorphizations for `{}`", tcx.def_path_str(def_id), } } - /// The entire set of monomorphizations the local crate can safely link - /// to because they are exported from upstream crates. Do not depend on - /// this directly, as its value changes anytime a monomorphization gets - /// added or removed in any upstream crate. Instead use the narrower - /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even - /// better, `Instance::upstream_monomorphization()`. - query upstream_monomorphizations( - k: CrateNum - ) -> DefIdMap, CrateNum>> { - storage(ArenaCacheSelector<'tcx>) - desc { "collecting available upstream monomorphizations `{:?}`", k } - } - - /// Returns the set of upstream monomorphizations available for the - /// generic function identified by the given `def_id`. The query makes - /// sure to make a stable selection if the same monomorphization is - /// available in multiple upstream crates. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - query upstream_monomorphizations_for(def_id: DefId) - -> Option<&'tcx FxHashMap, CrateNum>> { - desc { |tcx| - "collecting available upstream monomorphizations for `{}`", - tcx.def_path_str(def_id), - } - } - - /// Returns the upstream crate that exports drop-glue for the given - /// type (`substs` is expected to be a single-item list containing the - /// type one wants drop-glue for). - /// - /// This is a subset of `upstream_monomorphizations_for` in order to - /// increase dep-tracking granularity. Otherwise adding or removing any - /// type with drop-glue in any upstream crate would invalidate all - /// functions calling drop-glue of an upstream type. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - /// - /// NOTE: This query could easily be extended to also support other - /// common functions that have are large set of monomorphizations - /// (like `Clone::clone` for example). - query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option { - desc { "available upstream drop-glue for `{:?}`", substs } - } + /// Returns the upstream crate that exports drop-glue for the given + /// type (`substs` is expected to be a single-item list containing the + /// type one wants drop-glue for). + /// + /// This is a subset of `upstream_monomorphizations_for` in order to + /// increase dep-tracking granularity. Otherwise adding or removing any + /// type with drop-glue in any upstream crate would invalidate all + /// functions calling drop-glue of an upstream type. + /// + /// You likely want to call `Instance::upstream_monomorphization()` + /// instead of invoking this query directly. + /// + /// NOTE: This query could easily be extended to also support other + /// common functions that have are large set of monomorphizations + /// (like `Clone::clone` for example). + query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option { + desc { "available upstream drop-glue for `{:?}`", substs } + } - query foreign_modules(_: CrateNum) -> Lrc> { - desc { "looking up the foreign modules of a linked crate" } - } + query foreign_modules(_: CrateNum) -> Lrc> { + desc { "looking up the foreign modules of a linked crate" } + } - /// Identifies the entry-point (e.g., the `main` function) for a given - /// crate, returning `None` if there is no entry point (such as for library crates). - query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> { - desc { "looking up the entry function of a crate" } - } - query plugin_registrar_fn(_: CrateNum) -> Option { - desc { "looking up the plugin registrar for a crate" } - } - query proc_macro_decls_static(_: CrateNum) -> Option { - desc { "looking up the derive registrar for a crate" } - } - query crate_disambiguator(_: CrateNum) -> CrateDisambiguator { - eval_always - desc { "looking up the disambiguator a crate" } - } - // The macro which defines `rustc_metadata::provide_extern` depends on this query's name. - // Changing the name should cause a compiler error, but in case that changes, be aware. - query crate_hash(_: CrateNum) -> Svh { - eval_always - desc { "looking up the hash a crate" } - } - query crate_host_hash(_: CrateNum) -> Option { - eval_always - desc { "looking up the hash of a host version of a crate" } - } - query original_crate_name(_: CrateNum) -> Symbol { - eval_always - desc { "looking up the original name a crate" } - } - query extra_filename(_: CrateNum) -> String { - eval_always - desc { "looking up the extra filename for a crate" } - } - query crate_extern_paths(_: CrateNum) -> Vec { - eval_always - desc { "looking up the paths for extern crates" } - } + /// Identifies the entry-point (e.g., the `main` function) for a given + /// crate, returning `None` if there is no entry point (such as for library crates). + query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> { + desc { "looking up the entry function of a crate" } + } + query plugin_registrar_fn(_: CrateNum) -> Option { + desc { "looking up the plugin registrar for a crate" } + } + query proc_macro_decls_static(_: CrateNum) -> Option { + desc { "looking up the derive registrar for a crate" } + } + query crate_disambiguator(_: CrateNum) -> CrateDisambiguator { + eval_always + desc { "looking up the disambiguator a crate" } + } + // The macro which defines `rustc_metadata::provide_extern` depends on this query's name. + // Changing the name should cause a compiler error, but in case that changes, be aware. + query crate_hash(_: CrateNum) -> Svh { + eval_always + desc { "looking up the hash a crate" } + } + query crate_host_hash(_: CrateNum) -> Option { + eval_always + desc { "looking up the hash of a host version of a crate" } + } + query original_crate_name(_: CrateNum) -> Symbol { + eval_always + desc { "looking up the original name a crate" } + } + query extra_filename(_: CrateNum) -> String { + eval_always + desc { "looking up the extra filename for a crate" } + } + query crate_extern_paths(_: CrateNum) -> Vec { + eval_always + desc { "looking up the paths for extern crates" } + } - /// Given a crate and a trait, look up all impls of that trait in the crate. - /// Return `(impl_id, self_ty)`. - query implementations_of_trait(_: (CrateNum, DefId)) - -> &'tcx [(DefId, Option)] { - desc { "looking up implementations of a trait in a crate" } - } + /// Given a crate and a trait, look up all impls of that trait in the crate. + /// Return `(impl_id, self_ty)`. + query implementations_of_trait(_: (CrateNum, DefId)) + -> &'tcx [(DefId, Option)] { + desc { "looking up implementations of a trait in a crate" } + } - /// Given a crate, look up all trait impls in that crate. - /// Return `(impl_id, self_ty)`. - query all_trait_implementations(_: CrateNum) - -> &'tcx [(DefId, Option)] { - desc { "looking up all (?) trait implementations" } - } + /// Given a crate, look up all trait impls in that crate. + /// Return `(impl_id, self_ty)`. + query all_trait_implementations(_: CrateNum) + -> &'tcx [(DefId, Option)] { + desc { "looking up all (?) trait implementations" } + } - query is_dllimport_foreign_item(def_id: DefId) -> bool { - desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } - } - query is_statically_included_foreign_item(def_id: DefId) -> bool { - desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) } - } - query native_library_kind(def_id: DefId) - -> Option { - desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) } - } + query is_dllimport_foreign_item(def_id: DefId) -> bool { + desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } + } + query is_statically_included_foreign_item(def_id: DefId) -> bool { + desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) } + } + query native_library_kind(def_id: DefId) + -> Option { + desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) } + } - query link_args(_: CrateNum) -> Lrc> { - eval_always - desc { "looking up link arguments for a crate" } - } + query link_args(_: CrateNum) -> Lrc> { + eval_always + desc { "looking up link arguments for a crate" } + } - /// Lifetime resolution. See `middle::resolve_lifetimes`. - query resolve_lifetimes(_: CrateNum) -> ResolveLifetimes { - storage(ArenaCacheSelector<'tcx>) - desc { "resolving lifetimes" } - } - query named_region_map(_: LocalDefId) -> - Option<&'tcx FxHashMap> { - desc { "looking up a named region" } - } - query is_late_bound_map(_: LocalDefId) -> - Option<(LocalDefId, &'tcx FxHashSet)> { - desc { "testing if a region is late bound" } - } - query object_lifetime_defaults_map(_: LocalDefId) - -> Option<&'tcx FxHashMap>> { - desc { "looking up lifetime defaults for a region" } - } + /// Lifetime resolution. See `middle::resolve_lifetimes`. + query resolve_lifetimes(_: CrateNum) -> ResolveLifetimes { + storage(ArenaCacheSelector<'tcx>) + desc { "resolving lifetimes" } + } + query named_region_map(_: LocalDefId) -> + Option<&'tcx FxHashMap> { + desc { "looking up a named region" } + } + query is_late_bound_map(_: LocalDefId) -> + Option<(LocalDefId, &'tcx FxHashSet)> { + desc { "testing if a region is late bound" } + } + query object_lifetime_defaults_map(_: LocalDefId) + -> Option<&'tcx FxHashMap>> { + desc { "looking up lifetime defaults for a region" } + } - query visibility(def_id: DefId) -> ty::Visibility { - eval_always - desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } - } + query visibility(def_id: DefId) -> ty::Visibility { + eval_always + desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } + } - /// Computes the set of modules from which this type is visibly uninhabited. - /// To check whether a type is uninhabited at all (not just from a given module), you could - /// check whether the forest is empty. - query type_uninhabited_from( - key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> ty::inhabitedness::DefIdForest { - desc { "computing the inhabitedness of `{:?}`", key } - } + /// Computes the set of modules from which this type is visibly uninhabited. + /// To check whether a type is uninhabited at all (not just from a given module), you could + /// check whether the forest is empty. + query type_uninhabited_from( + key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> ty::inhabitedness::DefIdForest { + desc { "computing the inhabitedness of `{:?}`", key } + } - query dep_kind(_: CrateNum) -> CrateDepKind { - eval_always - desc { "fetching what a dependency looks like" } - } - query crate_name(_: CrateNum) -> Symbol { - eval_always - desc { "fetching what a crate is named" } - } - query item_children(def_id: DefId) -> &'tcx [Export] { - desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) } - } - query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option { - desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) } - } + query dep_kind(_: CrateNum) -> CrateDepKind { + eval_always + desc { "fetching what a dependency looks like" } + } + query crate_name(_: CrateNum) -> Symbol { + eval_always + desc { "fetching what a crate is named" } + } + query item_children(def_id: DefId) -> &'tcx [Export] { + desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) } + } + query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option { + desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) } + } - query get_lib_features(_: CrateNum) -> LibFeatures { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "calculating the lib features map" } - } - query defined_lib_features(_: CrateNum) - -> &'tcx [(Symbol, Option)] { - desc { "calculating the lib features defined in a crate" } - } - /// Returns the lang items defined in another crate by loading it from metadata. - // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid - // of that argument? - query get_lang_items(_: CrateNum) -> LanguageItems { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "calculating the lang items map" } - } + query get_lib_features(_: CrateNum) -> LibFeatures { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "calculating the lib features map" } + } + query defined_lib_features(_: CrateNum) + -> &'tcx [(Symbol, Option)] { + desc { "calculating the lib features defined in a crate" } + } + /// Returns the lang items defined in another crate by loading it from metadata. + // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid + // of that argument? + query get_lang_items(_: CrateNum) -> LanguageItems { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "calculating the lang items map" } + } - /// Returns all diagnostic items defined in all crates. - query all_diagnostic_items(_: CrateNum) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "calculating the diagnostic items map" } - } + /// Returns all diagnostic items defined in all crates. + query all_diagnostic_items(_: CrateNum) -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "calculating the diagnostic items map" } + } - /// Returns the lang items defined in another crate by loading it from metadata. - query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { - desc { "calculating the lang items defined in a crate" } - } + /// Returns the lang items defined in another crate by loading it from metadata. + query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { + desc { "calculating the lang items defined in a crate" } + } - /// Returns the diagnostic items defined in a crate. - query diagnostic_items(_: CrateNum) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) - desc { "calculating the diagnostic items map in a crate" } - } + /// Returns the diagnostic items defined in a crate. + query diagnostic_items(_: CrateNum) -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating the diagnostic items map in a crate" } + } - query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { - desc { "calculating the missing lang items in a crate" } - } - query visible_parent_map(_: CrateNum) - -> DefIdMap { - storage(ArenaCacheSelector<'tcx>) - desc { "calculating the visible parent map" } - } - query trimmed_def_paths(_: CrateNum) - -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) - desc { "calculating trimmed def paths" } - } - query missing_extern_crate_item(_: CrateNum) -> bool { - eval_always - desc { "seeing if we're missing an `extern crate` item for this crate" } - } - query used_crate_source(_: CrateNum) -> Lrc { - eval_always - desc { "looking at the source for a crate" } - } - query postorder_cnums(_: CrateNum) -> &'tcx [CrateNum] { - eval_always - desc { "generating a postorder list of CrateNums" } - } + query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { + desc { "calculating the missing lang items in a crate" } + } + query visible_parent_map(_: CrateNum) + -> DefIdMap { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating the visible parent map" } + } + query trimmed_def_paths(_: CrateNum) + -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating trimmed def paths" } + } + query missing_extern_crate_item(_: CrateNum) -> bool { + eval_always + desc { "seeing if we're missing an `extern crate` item for this crate" } + } + query used_crate_source(_: CrateNum) -> Lrc { + eval_always + desc { "looking at the source for a crate" } + } + query postorder_cnums(_: CrateNum) -> &'tcx [CrateNum] { + eval_always + desc { "generating a postorder list of CrateNums" } + } - query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap> { - desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } - eval_always - } - query maybe_unused_trait_import(def_id: LocalDefId) -> bool { - eval_always - desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) } - } - query maybe_unused_extern_crates(_: CrateNum) - -> &'tcx [(LocalDefId, Span)] { - eval_always - desc { "looking up all possibly unused extern crates" } - } - query names_imported_by_glob_use(def_id: LocalDefId) - -> &'tcx FxHashSet { - eval_always - desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) } - } + query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap> { + desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } + eval_always + } + query maybe_unused_trait_import(def_id: LocalDefId) -> bool { + eval_always + desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) } + } + query maybe_unused_extern_crates(_: CrateNum) + -> &'tcx [(LocalDefId, Span)] { + eval_always + desc { "looking up all possibly unused extern crates" } + } + query names_imported_by_glob_use(def_id: LocalDefId) + -> &'tcx FxHashSet { + eval_always + desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) } + } - query stability_index(_: CrateNum) -> stability::Index<'tcx> { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "calculating the stability index for the local crate" } - } - query all_crate_nums(_: CrateNum) -> &'tcx [CrateNum] { - eval_always - desc { "fetching all foreign CrateNum instances" } - } + query stability_index(_: CrateNum) -> stability::Index<'tcx> { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "calculating the stability index for the local crate" } + } + query all_crate_nums(_: CrateNum) -> &'tcx [CrateNum] { + eval_always + desc { "fetching all foreign CrateNum instances" } + } - /// A vector of every trait accessible in the whole crate - /// (i.e., including those from subcrates). This is used only for - /// error reporting. - query all_traits(_: CrateNum) -> &'tcx [DefId] { - desc { "fetching all foreign and local traits" } - } + /// A vector of every trait accessible in the whole crate + /// (i.e., including those from subcrates). This is used only for + /// error reporting. + query all_traits(_: CrateNum) -> &'tcx [DefId] { + desc { "fetching all foreign and local traits" } + } - /// The list of symbols exported from the given crate. - /// - /// - All names contained in `exported_symbols(cnum)` are guaranteed to - /// correspond to a publicly visible symbol in `cnum` machine code. - /// - The `exported_symbols` sets of different crates do not intersect. - query exported_symbols(_: CrateNum) - -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { - desc { "exported_symbols" } - } + /// The list of symbols exported from the given crate. + /// + /// - All names contained in `exported_symbols(cnum)` are guaranteed to + /// correspond to a publicly visible symbol in `cnum` machine code. + /// - The `exported_symbols` sets of different crates do not intersect. + query exported_symbols(_: CrateNum) + -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { + desc { "exported_symbols" } + } - query collect_and_partition_mono_items(_: CrateNum) - -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { - eval_always - desc { "collect_and_partition_mono_items" } - } - query is_codegened_item(def_id: DefId) -> bool { - desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) } - } - query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { - desc { "codegen_unit" } - } - query unused_generic_params(key: DefId) -> FiniteBitSet { - cache_on_disk_if { key.is_local() } - desc { - |tcx| "determining which generic parameters are unused by `{}`", - tcx.def_path_str(key) - } - } - query backend_optimization_level(_: CrateNum) -> OptLevel { - desc { "optimization level used by backend" } + query collect_and_partition_mono_items(_: CrateNum) + -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { + eval_always + desc { "collect_and_partition_mono_items" } + } + query is_codegened_item(def_id: DefId) -> bool { + desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) } + } + query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { + desc { "codegen_unit" } + } + query unused_generic_params(key: DefId) -> FiniteBitSet { + cache_on_disk_if { key.is_local() } + desc { + |tcx| "determining which generic parameters are unused by `{}`", + tcx.def_path_str(key) } + } + query backend_optimization_level(_: CrateNum) -> OptLevel { + desc { "optimization level used by backend" } + } - query output_filenames(_: CrateNum) -> Arc { - eval_always - desc { "output_filenames" } - } + query output_filenames(_: CrateNum) -> Arc { + eval_always + desc { "output_filenames" } + } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_projection_ty( - goal: CanonicalProjectionGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, - NoSolution, - > { - desc { "normalizing `{:?}`", goal } - } + /// Do not call this query directly: invoke `normalize` instead. + query normalize_projection_ty( + goal: CanonicalProjectionGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{:?}`", goal } + } - /// Do not call this query directly: invoke `normalize_erasing_regions` instead. - query normalize_generic_arg_after_erasing_regions( - goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> - ) -> GenericArg<'tcx> { - desc { "normalizing `{}`", goal.value } - } + /// Do not call this query directly: invoke `normalize_erasing_regions` instead. + query normalize_generic_arg_after_erasing_regions( + goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> + ) -> GenericArg<'tcx> { + desc { "normalizing `{}`", goal.value } + } - query implied_outlives_bounds( - goal: CanonicalTyGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, - NoSolution, - > { - desc { "computing implied outlives bounds for `{:?}`", goal } - } + query implied_outlives_bounds( + goal: CanonicalTyGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, + NoSolution, + > { + desc { "computing implied outlives bounds for `{:?}`", goal } + } - /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. - query dropck_outlives( - goal: CanonicalTyGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, - NoSolution, - > { - desc { "computing dropck types for `{:?}`", goal } - } + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. + query dropck_outlives( + goal: CanonicalTyGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, + NoSolution, + > { + desc { "computing dropck types for `{:?}`", goal } + } - /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or - /// `infcx.predicate_must_hold()` instead. - query evaluate_obligation( - goal: CanonicalPredicateGoal<'tcx> - ) -> Result { - desc { "evaluating trait selection obligation `{}`", goal.value.value } - } + /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or + /// `infcx.predicate_must_hold()` instead. + query evaluate_obligation( + goal: CanonicalPredicateGoal<'tcx> + ) -> Result { + desc { "evaluating trait selection obligation `{}`", goal.value.value } + } - query evaluate_goal( - goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution - > { - desc { "evaluating trait selection obligation `{}`", goal.value } - } + query evaluate_goal( + goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, + NoSolution + > { + desc { "evaluating trait selection obligation `{}`", goal.value } + } - query type_implements_trait( - key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, ) - ) -> bool { - desc { "evaluating `type_implements_trait` `{:?}`", key } - } + query type_implements_trait( + key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, ) + ) -> bool { + desc { "evaluating `type_implements_trait` `{:?}`", key } + } - /// Do not call this query directly: part of the `Eq` type-op - query type_op_ascribe_user_type( - goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } - } + /// Do not call this query directly: part of the `Eq` type-op + query type_op_ascribe_user_type( + goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, + NoSolution, + > { + desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } + } - /// Do not call this query directly: part of the `Eq` type-op - query type_op_eq( - goal: CanonicalTypeOpEqGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - desc { "evaluating `type_op_eq` `{:?}`", goal } - } + /// Do not call this query directly: part of the `Eq` type-op + query type_op_eq( + goal: CanonicalTypeOpEqGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, + NoSolution, + > { + desc { "evaluating `type_op_eq` `{:?}`", goal } + } - /// Do not call this query directly: part of the `Subtype` type-op - query type_op_subtype( - goal: CanonicalTypeOpSubtypeGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - desc { "evaluating `type_op_subtype` `{:?}`", goal } - } + /// Do not call this query directly: part of the `Subtype` type-op + query type_op_subtype( + goal: CanonicalTypeOpSubtypeGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, + NoSolution, + > { + desc { "evaluating `type_op_subtype` `{:?}`", goal } + } - /// Do not call this query directly: part of the `ProvePredicate` type-op - query type_op_prove_predicate( - goal: CanonicalTypeOpProvePredicateGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution, - > { - desc { "evaluating `type_op_prove_predicate` `{:?}`", goal } - } + /// Do not call this query directly: part of the `ProvePredicate` type-op + query type_op_prove_predicate( + goal: CanonicalTypeOpProvePredicateGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, + NoSolution, + > { + desc { "evaluating `type_op_prove_predicate` `{:?}`", goal } + } - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_ty( - goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>, - NoSolution, - > { - desc { "normalizing `{:?}`", goal } - } + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_ty( + goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{:?}`", goal } + } - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_predicate( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>, - NoSolution, - > { - desc { "normalizing `{:?}`", goal } - } + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_predicate( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{:?}`", goal } + } - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_poly_fn_sig( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>, - NoSolution, - > { - desc { "normalizing `{:?}`", goal } - } + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_poly_fn_sig( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{:?}`", goal } + } - /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_fn_sig( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>, - NoSolution, - > { - desc { "normalizing `{:?}`", goal } - } + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_fn_sig( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{:?}`", goal } + } - query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { - desc { |tcx| - "impossible substituted predicates:`{}`", - tcx.def_path_str(key.0) - } + query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { + desc { |tcx| + "impossible substituted predicates:`{}`", + tcx.def_path_str(key.0) } + } - query method_autoderef_steps( - goal: CanonicalTyGoal<'tcx> - ) -> MethodAutoderefStepsResult<'tcx> { - desc { "computing autoderef types for `{:?}`", goal } - } + query method_autoderef_steps( + goal: CanonicalTyGoal<'tcx> + ) -> MethodAutoderefStepsResult<'tcx> { + desc { "computing autoderef types for `{:?}`", goal } + } - query supported_target_features(_: CrateNum) -> FxHashMap> { - storage(ArenaCacheSelector<'tcx>) - eval_always - desc { "looking up supported target features" } - } + query supported_target_features(_: CrateNum) -> FxHashMap> { + storage(ArenaCacheSelector<'tcx>) + eval_always + desc { "looking up supported target features" } + } - /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. - query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) - -> usize { - desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } - } + /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) + -> usize { + desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } + } - query features_query(_: CrateNum) -> &'tcx rustc_feature::Features { - eval_always - desc { "looking up enabled feature gates" } - } + query features_query(_: CrateNum) -> &'tcx rustc_feature::Features { + eval_always + desc { "looking up enabled feature gates" } + } - /// Attempt to resolve the given `DefId` to an `Instance`, for the - /// given generics args (`SubstsRef`), returning one of: - /// * `Ok(Some(instance))` on success - /// * `Ok(None)` when the `SubstsRef` are still too generic, - /// and therefore don't allow finding the final `Instance` - /// * `Err(ErrorReported)` when the `Instance` resolution process - /// couldn't complete due to errors elsewhere - this is distinct - /// from `Ok(None)` to avoid misleading diagnostics when an error - /// has already been/will be emitted, for the original cause - query resolve_instance( - key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)> - ) -> Result>, ErrorReported> { - desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } - } + /// Attempt to resolve the given `DefId` to an `Instance`, for the + /// given generics args (`SubstsRef`), returning one of: + /// * `Ok(Some(instance))` on success + /// * `Ok(None)` when the `SubstsRef` are still too generic, + /// and therefore don't allow finding the final `Instance` + /// * `Err(ErrorReported)` when the `Instance` resolution process + /// couldn't complete due to errors elsewhere - this is distinct + /// from `Ok(None)` to avoid misleading diagnostics when an error + /// has already been/will be emitted, for the original cause + query resolve_instance( + key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)> + ) -> Result>, ErrorReported> { + desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } + } - query resolve_instance_of_const_arg( - key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)> - ) -> Result>, ErrorReported> { - desc { - "resolving instance of the const argument `{}`", - ty::Instance::new(key.value.0.to_def_id(), key.value.2), - } + query resolve_instance_of_const_arg( + key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)> + ) -> Result>, ErrorReported> { + desc { + "resolving instance of the const argument `{}`", + ty::Instance::new(key.value.0.to_def_id(), key.value.2), } + } - query normalize_opaque_types(key: &'tcx ty::List>) -> &'tcx ty::List> { - desc { "normalizing opaque types in {:?}", key } - } + query normalize_opaque_types(key: &'tcx ty::List>) -> &'tcx ty::List> { + desc { "normalizing opaque types in {:?}", key } + } } From 82010e86d388f2250e98cb8859fa272d294ae3b5 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 28 Jan 2021 15:51:54 -0800 Subject: [PATCH 07/19] rustdoc: Note why `rustdoc::html::markdown` is public Almost all of the modules are crate-private, except for `rustdoc::json::types`, which I believe is intended to be for public use; and `rustdoc::html::markdown`, which is used externally by the error-index generator and so has to be public. --- src/librustdoc/html/mod.rs | 1 + src/librustdoc/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs index 403a9303c3ff0..4318be898ceb4 100644 --- a/src/librustdoc/html/mod.rs +++ b/src/librustdoc/html/mod.rs @@ -2,6 +2,7 @@ crate mod escape; crate mod format; crate mod highlight; crate mod layout; +// used by the error-index generator, so it needs to be public pub mod markdown; crate mod render; crate mod sources; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c61cbf78f771a..53f891251f500 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -83,7 +83,8 @@ mod doctree; mod error; mod doctest; mod fold; -crate mod formats; +mod formats; +// used by the error-index generator, so it needs to be public pub mod html; mod json; mod markdown; From bf4bdd95c3843ef1922e62ef5ace146dae8f43a7 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Mon, 28 Dec 2020 06:42:21 -0500 Subject: [PATCH 08/19] Add lint for 2229 migrations --- compiler/rustc_lint_defs/src/builtin.rs | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a8bf1ce51bb74..f1e5a4d47c787 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2968,6 +2968,7 @@ declare_lint_pass! { UNSUPPORTED_NAKED_FUNCTIONS, MISSING_ABI, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, + DISJOINT_CAPTURE_DROP_REORDER, ] } @@ -2994,6 +2995,51 @@ declare_lint! { "detects doc comments that aren't used by rustdoc" } +declare_lint! { + /// The `disjoint_capture_drop_reorder` lint detects variables that aren't completely + /// captured when the feature `capture_disjoint_fields` is enabled and it affects the Drop + /// order of at least one path starting at this variable. + /// + /// ### Example + /// + /// ```rust + /// # #![deny(disjoint_capture_drop_reorder)] + /// # #![allow(unused)] + /// struct FancyInteger(i32); + /// + /// impl Drop for FancyInteger { + /// fn drop(&mut self) { + /// println!("Just dropped {}", self.0); + /// } + /// } + /// + /// struct Point { x: FancyInteger, y: FancyInteger } + /// + /// fn main() { + /// let p = Point { x: FancyInteger(10), y: FancyInteger(20) }; + /// + /// let c = || { + /// let x = p.x; + /// }; + /// + /// c(); + /// + /// // ... More code ... + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the above example `p.y` will be dropped at the end of `f` instead of with `c` if + /// the feature `capture_disjoint_fields` is enabled. + pub DISJOINT_CAPTURE_DROP_REORDER, + Allow, + "Drop reorder because of `capture_disjoint_fields`" + +} + declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); declare_lint! { From 99893346e85de78cb9cb021f831a2fe0b7dd1470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 1 Feb 2021 09:44:10 +0200 Subject: [PATCH 09/19] Add SAFETY comment for the `TrustedRandomAccess` impl of `iter::Fuse` --- library/core/src/iter/adapters/fuse.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index ae07406531593..fc5fbd60b64d8 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -184,6 +184,11 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] +// SAFETY: `TrustedRandomAccess` requires that `size_hint()` must be exact and cheap to call, and +// `Iterator::__iterator_get_unchecked()` must be implemented accordingly. +// +// This is safe to implement as `Fuse` is just forwarding these to the wrapped iterator `I`, which +// preserves these properties. unsafe impl TrustedRandomAccess for Fuse where I: TrustedRandomAccess, From 12b605af88e8935b7417234861ef8fa8e6131fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 31 Jan 2021 18:53:11 +0200 Subject: [PATCH 10/19] Implement `TrustedLen` for `iter::Fuse` --- library/core/src/iter/adapters/fuse.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index fc5fbd60b64d8..7a852c2cb9da5 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,6 +1,8 @@ use crate::intrinsics; use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter}; -use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedRandomAccess}; +use crate::iter::{ + DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, +}; use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator @@ -182,6 +184,12 @@ where } } +#[unstable(feature = "trusted_len", issue = "37572")] +// SAFETY: `TrustedLen` requires that an accurate length is reported via `size_hint()`. As `Fuse` +// is just forwarding this to the wrapped iterator `I` this property is preserved and it is safe to +// implement `TrustedLen` here. +unsafe impl TrustedLen for Fuse where I: TrustedLen {} + #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] // SAFETY: `TrustedRandomAccess` requires that `size_hint()` must be exact and cheap to call, and From 8e34522309cb6907da0a6ae593894f2b1d847ee6 Mon Sep 17 00:00:00 2001 From: LingMan Date: Wed, 20 Jan 2021 02:48:48 +0100 Subject: [PATCH 11/19] Remove unneeded `mut` variable `arg_elide` gets initialized, immediately cloned, and only written to after that. The last reading access was removed back in https://github.com/rust-lang/rust/commit/7704762604a8bf4504a06e8c9713bc7c158d362a --- compiler/rustc_resolve/src/late/lifetimes.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 95ac2a31dd321..004c06029ffba 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -2083,18 +2083,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { output: Option<&'tcx hir::Ty<'tcx>>, ) { debug!("visit_fn_like_elision: enter"); - let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); - let arg_scope = Scope::Elision { elide: arg_elide.clone(), s: self.scope }; + let arg_scope = Scope::Elision { elide: Elide::FreshLateAnon(Cell::new(0)), s: self.scope }; self.with(arg_scope, |_, this| { for input in inputs { this.visit_ty(input); } - match *this.scope { - Scope::Elision { ref elide, .. } => { - arg_elide = elide.clone(); - } - _ => bug!(), - } }); let output = match output { From 899b0dd1d1ed414f216c04b02d1b38a37a1a0f1b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 1 Feb 2021 17:21:49 +0100 Subject: [PATCH 12/19] Fix overflowing text on mobile when sidebar is displayed --- src/librustdoc/html/static/rustdoc.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8dad26dced956..f7b626cd6b985 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1489,6 +1489,14 @@ h4 > .notable-traits { background-color: rgba(0,0,0,0); height: 100%; } + /* + This allows to prevent the version text to overflow the sidebar title on mobile mode when the + sidebar is displayed (after clicking on the "hamburger" button). + */ + .sidebar.mobile > div.version { + overflow: hidden; + max-height: 33px; + } .sidebar { width: calc(100% + 30px); } From 7f8530f16b8cc908cb77970967addf39ae1a975d Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 1 Feb 2021 20:05:43 +0000 Subject: [PATCH 13/19] more things are const evaluatable *sparkles* --- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/traits/const_evaluatable.rs | 31 +++++++++++++------ .../src/traits/object_safety.rs | 4 +-- .../nested_uneval_unification-1.rs | 1 - .../subexprs_are_const_evalutable.rs | 17 ++++++++++ 5 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 3fade2c443726..631dcb60594f1 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -132,7 +132,7 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow { - const_evaluatable::walk_abstract_const(tcx, ct, |node| match node { + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() { ACNode::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); self.visit_const(leaf) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b587ed6487e3c..3facdd5f84c29 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -50,11 +50,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if b_def == def && b_substs == substs { debug!("is_const_evaluatable: caller_bound ~~> ok"); return Ok(()); - } else if AbstractConst::new(tcx, b_def, b_substs)? - .map_or(false, |b_ct| try_unify(tcx, ct, b_ct)) - { - debug!("is_const_evaluatable: abstract_const ~~> ok"); - return Ok(()); + } + + if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? { + // Try to unify with each subtree in the AbstractConst to allow for + // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` + // predicate for `(N + 1) * 2` + let result = + walk_abstract_const(tcx, b_ct, |b_ct| { + match try_unify(tcx, ct, b_ct) { + true => ControlFlow::BREAK, + false => ControlFlow::CONTINUE, + } + }); + + if let ControlFlow::Break(()) = result { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); + } } } _ => {} // don't care @@ -78,7 +91,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::(tcx, ct, |node| match node { + walk_abstract_const::(tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { @@ -580,15 +593,15 @@ pub fn walk_abstract_const<'tcx, R, F>( mut f: F, ) -> ControlFlow where - F: FnMut(Node<'tcx>) -> ControlFlow, + F: FnMut(AbstractConst<'tcx>) -> ControlFlow, { fn recurse<'tcx, R>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow, + f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow, ) -> ControlFlow { + f(ct)?; let root = ct.root(); - f(root)?; match root { Node::Leaf(_) => ControlFlow::CONTINUE, Node::Binop(_, l, r) => { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index a9723611f8113..3852005ee3f35 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -828,7 +828,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // constants which are not considered const evaluatable. use rustc_middle::mir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node { + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) @@ -849,7 +849,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // take a `ty::Const` instead. use rustc_middle::mir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node { + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs index 1428f774b0d70..4d0b87efc77c3 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs @@ -21,7 +21,6 @@ where fn substs3() -> Substs1<{ (L - 1) * 2 }> where - [(); (L - 1)]: , [(); (L - 1) * 2 + 1]: , { substs2::<{ L - 1 }>() diff --git a/src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs b/src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs new file mode 100644 index 0000000000000..11c0760cdfe05 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn make_array() -> [(); M + 1] { + [(); M + 1] +} + +fn foo() -> [(); (N * 2) + 1] { + make_array::<{ N * 2 }>() +} + +fn main() { + assert_eq!(foo::<10>(), [(); 10 * 2 + 1]) +} + +// Tests that N * 2 is considered const_evalutable by appearing as part of the (N * 2) + 1 const From d3e85014a712e2b41ac44d71ddee3d55711a8d44 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 21 Nov 2020 04:23:42 -0500 Subject: [PATCH 14/19] Process mentioned upvars for analysis first pass after ExprUseVisitor - This allows us add fake information after handling migrations if needed. - Capture analysis also priortizes what we see earlier, which means fake information should go in last. --- compiler/rustc_typeck/src/check/upvar.rs | 107 ++++++++++-------- .../escape-upvar-nested.stderr | 8 +- .../escape-upvar-ref.stderr | 4 +- 3 files changed, 68 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index f039445bf7780..56b91ee4bcbd3 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -40,7 +40,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts}; use rustc_span::sym; use rustc_span::{MultiSpan, Span, Symbol}; @@ -55,6 +55,11 @@ enum PlaceAncestryRelation { Divergent, } +/// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo` +/// during capture analysis. Information in this map feeds into the minimum capture +/// analysis pass. +type InferredCaptureInformation<'tcx> = FxIndexMap, ty::CaptureInfo<'tcx>>; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { InferBorrowKindVisitor { fcx: self }.visit_body(body); @@ -124,28 +129,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let local_def_id = closure_def_id.expect_local(); - let mut capture_information: FxIndexMap, ty::CaptureInfo<'tcx>> = - Default::default(); - if !self.tcx.features().capture_disjoint_fields { - if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - for (&var_hir_id, _) in upvars.iter() { - let place = self.place_for_root_variable(local_def_id, var_hir_id); - - debug!("seed place {:?}", place); - - let upvar_id = ty::UpvarId::new(var_hir_id, local_def_id); - let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span); - let info = ty::CaptureInfo { - capture_kind_expr_id: None, - path_expr_id: None, - capture_kind, - }; - - capture_information.insert(place, info); - } - } - } - let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id()); assert_eq!(body_owner_def_id.to_def_id(), closure_def_id); let mut delegate = InferBorrowKind { @@ -155,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_clause, current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM, current_origin: None, - capture_information, + capture_information: Default::default(), }; euv::ExprUseVisitor::new( &mut delegate, @@ -172,6 +155,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span); + self.compute_min_captures(closure_def_id, delegate.capture_information); + + // We now fake capture information for all variables that are mentioned within the closure + // We do this after handling migrations so that min_captures computes before + if !self.tcx.features().capture_disjoint_fields { + let mut capture_information: InferredCaptureInformation<'tcx> = Default::default(); + + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { + for var_hir_id in upvars.keys() { + let place = self.place_for_root_variable(local_def_id, *var_hir_id); + + debug!("seed place {:?}", place); + + let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id); + let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span); + let fake_info = ty::CaptureInfo { + capture_kind_expr_id: None, + path_expr_id: None, + capture_kind, + }; + + capture_information.insert(place, fake_info); + } + } + + // This will update the min captures based on this new fake information. + self.compute_min_captures(closure_def_id, capture_information); + } + if let Some(closure_substs) = infer_kind { // Unify the (as yet unbound) type variable in the closure // substs with the kind we inferred. @@ -197,7 +209,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - self.compute_min_captures(closure_def_id, delegate); self.log_closure_min_capture_info(closure_def_id, span); self.min_captures_to_closure_captures_bridge(closure_def_id); @@ -344,6 +355,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Places (and corresponding capture kind) that we need to keep track of to support all /// the required captured paths. /// + /// + /// Note: If this function is called multiple times for the same closure, it will update + /// the existing min_capture map that is stored in TypeckResults. + /// /// Eg: /// ```rust,no_run /// struct Point { x: i32, y: i32 } @@ -408,11 +423,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn compute_min_captures( &self, closure_def_id: DefId, - inferred_info: InferBorrowKind<'_, 'tcx>, + capture_information: InferredCaptureInformation<'tcx>, ) { - let mut root_var_min_capture_list: ty::RootVariableMinCaptureList<'_> = Default::default(); + if capture_information.is_empty() { + return; + } + + let mut typeck_results = self.typeck_results.borrow_mut(); - for (place, capture_info) in inferred_info.capture_information.into_iter() { + let mut root_var_min_capture_list = + typeck_results.closure_min_captures.remove(&closure_def_id).unwrap_or_default(); + + for (place, capture_info) in capture_information.into_iter() { let var_hir_id = match place.base { PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, base => bug!("Expected upvar, found={:?}", base), @@ -422,7 +444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) { None => { - let mutability = self.determine_capture_mutability(&place); + let mutability = self.determine_capture_mutability(&typeck_results, &place); let min_cap_list = vec![ty::CapturedPlace { place, info: capture_info, mutability }]; root_var_min_capture_list.insert(var_hir_id, min_cap_list); @@ -487,7 +509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only need to insert when we don't have an ancestor in the existing min capture list if !ancestor_found { - let mutability = self.determine_capture_mutability(&place); + let mutability = self.determine_capture_mutability(&typeck_results, &place); let captured_place = ty::CapturedPlace { place, info: updated_capture_info, mutability }; min_cap_list.push(captured_place); @@ -495,13 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); - - if !root_var_min_capture_list.is_empty() { - self.typeck_results - .borrow_mut() - .closure_min_captures - .insert(closure_def_id, root_var_min_capture_list); - } + typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list); } fn init_capture_kind( @@ -613,18 +629,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// A captured place is mutable if /// 1. Projections don't include a Deref of an immut-borrow, **and** /// 2. PlaceBase is mut or projections include a Deref of a mut-borrow. - fn determine_capture_mutability(&self, place: &Place<'tcx>) -> hir::Mutability { + fn determine_capture_mutability( + &self, + typeck_results: &'a TypeckResults<'tcx>, + place: &Place<'tcx>, + ) -> hir::Mutability { let var_hir_id = match place.base { PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, _ => unreachable!(), }; - let bm = *self - .typeck_results - .borrow() - .pat_binding_modes() - .get(var_hir_id) - .expect("missing binding mode"); + let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode"); let mut is_mutbl = match bm { ty::BindByValue(mutability) => mutability, @@ -698,9 +713,11 @@ struct InferBorrowKind<'a, 'tcx> { /// /// For closure `fix_s`, (at a high level) the map contains /// + /// ``` /// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow } /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow } - capture_information: FxIndexMap, ty::CaptureInfo<'tcx>>, + /// ``` + capture_information: InferredCaptureInformation<'tcx>, } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 1a8258376142a..e1b446fc61f61 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -7,10 +7,10 @@ LL | let mut closure1 = || p = &y; = note: defining type: test::{closure#0}::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), - (&'_#1r i32, &'_#2r mut &'_#3r i32), + (&'_#1r mut &'_#2r i32, &'_#3r i32), ] = note: number of external vids: 4 - = note: where '_#1r: '_#3r + = note: where '_#3r: '_#2r note: external requirements --> $DIR/escape-upvar-nested.rs:20:27 @@ -25,10 +25,10 @@ LL | | }; = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), - (&'_#1r i32, &'_#2r mut &'_#3r i32), + (&'_#1r mut &'_#2r i32, &'_#3r i32), ] = note: number of external vids: 4 - = note: where '_#1r: '_#3r + = note: where '_#3r: '_#2r note: no external requirements --> $DIR/escape-upvar-nested.rs:13:1 diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index 29fd796882b6a..0ea1076c32ef4 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -7,10 +7,10 @@ LL | let mut closure = || p = &y; = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), - (&'_#1r i32, &'_#2r mut &'_#3r i32), + (&'_#1r mut &'_#2r i32, &'_#3r i32), ] = note: number of external vids: 4 - = note: where '_#1r: '_#3r + = note: where '_#3r: '_#2r note: no external requirements --> $DIR/escape-upvar-ref.rs:17:1 From cc5e6db5f2d25fb1c0371455574db7aecbe0ba0c Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Tue, 15 Dec 2020 03:38:15 -0500 Subject: [PATCH 15/19] Migrations first pass --- compiler/rustc_typeck/src/check/upvar.rs | 132 ++++++++++++++++++- compiler/rustc_typeck/src/check/writeback.rs | 6 +- 2 files changed, 134 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 56b91ee4bcbd3..16aaa48ce17fe 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -30,6 +30,7 @@ //! then mean that all later passes would have to check for these figments //! and report an error, and it just seems like more mess in the end.) +use super::writeback::Resolver; use super::FnCtxt; use crate::expr_use_visitor as euv; @@ -40,7 +41,9 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind}; +use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts}; +use rustc_session::lint; use rustc_span::sym; use rustc_span::{MultiSpan, Span, Symbol}; @@ -97,7 +100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, closure_hir_id: hir::HirId, span: Span, - body: &hir::Body<'_>, + body: &'tcx hir::Body<'tcx>, capture_clause: hir::CaptureBy, ) { debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id()); @@ -157,6 +160,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.compute_min_captures(closure_def_id, delegate.capture_information); + let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); + if should_do_migration_analysis(self.tcx, closure_hir_id) { + let need_migrations = self.compute_2229_migrations_first_pass( + closure_def_id, + span, + capture_clause, + body, + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), + ); + + if !need_migrations.is_empty() { + let need_migrations_hir_id = + need_migrations.iter().map(|m| m.0).collect::>(); + + let migrations_text = + migration_suggestion_for_2229(self.tcx, &need_migrations_hir_id); + + self.tcx.struct_span_lint_hir( + lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, + closure_hir_id, + span, + |lint| { + let mut diagnostics_builder = lint.build( + "drop order affected for closure because of `capture_disjoint_fields`", + ); + diagnostics_builder.note(&migrations_text); + diagnostics_builder.emit(); + }, + ); + } + } + // We now fake capture information for all variables that are mentioned within the closure // We do this after handling migrations so that min_captures computes before if !self.tcx.features().capture_disjoint_fields { @@ -520,6 +555,86 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list); } + /// Figures out the list of root variables (and their types) that aren't completely + /// captured by the closure when `capture_disjoint_fields` is enabled and drop order of + /// some path starting at that root variable **might** be affected. + /// + /// The output list would include a root variable if: + /// - It would have been moved into the closure when `capture_disjoint_fields` wasn't + /// enabled, **and** + /// - It wasn't completely captured by the closure, **and** + /// - The type of the root variable needs Drop. + fn compute_2229_migrations_first_pass( + &self, + closure_def_id: DefId, + closure_span: Span, + closure_clause: hir::CaptureBy, + body: &'tcx hir::Body<'tcx>, + min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, + ) -> Vec<(hir::HirId, Ty<'tcx>)> { + fn resolve_ty>( + fcx: &FnCtxt<'_, 'tcx>, + span: Span, + body: &'tcx hir::Body<'tcx>, + ty: T, + ) -> T { + let mut resolver = Resolver::new(fcx, &span, body); + ty.fold_with(&mut resolver) + } + + let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { + upvars + } else { + return vec![]; + }; + + let mut need_migrations = Vec::new(); + + for (&var_hir_id, _) in upvars.iter() { + let ty = resolve_ty(self, closure_span, body, self.node_ty(var_hir_id)); + + if !ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) { + continue; + } + + let root_var_min_capture_list = if let Some(root_var_min_capture_list) = + min_captures.and_then(|m| m.get(&var_hir_id)) + { + root_var_min_capture_list + } else { + // The upvar is mentioned within the closure but no path starting from it is + // used. + + match closure_clause { + // Only migrate if closure is a move closure + hir::CaptureBy::Value => need_migrations.push((var_hir_id, ty)), + + hir::CaptureBy::Ref => {} + } + + continue; + }; + + let is_moved = root_var_min_capture_list + .iter() + .find(|capture| matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue(_))) + .is_some(); + + // 1. If we capture more than one path starting at the root variabe then the root variable + // isn't being captured in its entirety + // 2. If we only capture one path starting at the root variable, it's still possible + // that it isn't the root variable completely. + if is_moved + && ((root_var_min_capture_list.len() > 1) + || (root_var_min_capture_list[0].place.projections.len() > 0)) + { + need_migrations.push((var_hir_id, ty)); + } + } + + need_migrations + } + fn init_capture_kind( &self, capture_clause: hir::CaptureBy, @@ -1136,6 +1251,21 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol { tcx.hir().name(var_hir_id) } +fn should_do_migration_analysis(tcx: TyCtxt<'_>, closure_id: hir::HirId) -> bool { + let (level, _) = + tcx.lint_level_at_node(lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, closure_id); + + !matches!(level, lint::Level::Allow) +} + +fn migration_suggestion_for_2229(tcx: TyCtxt<'_>, need_migrations: &Vec) -> String { + let need_migrations_strings = + need_migrations.iter().map(|v| format!("{}", var_name(tcx, *v))).collect::>(); + let migrations_list_concat = need_migrations_strings.join(", "); + + format!("let ({}) = ({});", migrations_list_concat, migrations_list_concat) +} + /// Helper function to determine if we need to escalate CaptureKind from /// CaptureInfo A to B and returns the escalated CaptureInfo. /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way) diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index b6d740a4fdb57..4d18b2cb3fc49 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -650,7 +650,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } -trait Locatable { +crate trait Locatable { fn to_span(&self, tcx: TyCtxt<'_>) -> Span; } @@ -668,7 +668,7 @@ impl Locatable for hir::HirId { /// The Resolver. This is the type folding engine that detects /// unresolved types and so forth. -struct Resolver<'cx, 'tcx> { +crate struct Resolver<'cx, 'tcx> { tcx: TyCtxt<'tcx>, infcx: &'cx InferCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, @@ -679,7 +679,7 @@ struct Resolver<'cx, 'tcx> { } impl<'cx, 'tcx> Resolver<'cx, 'tcx> { - fn new( + crate fn new( fcx: &'cx FnCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, From 3c71a7b60f8c661899a4e0cbe498ac67f3f02632 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Tue, 29 Dec 2020 23:43:44 -0500 Subject: [PATCH 16/19] Tests for 2229 lint --- .../migrations/insignificant_drop.rs | 130 +++++++++++++++++ .../migrations/insignificant_drop.stderr | 105 ++++++++++++++ .../migrations/no_migrations.rs | 84 +++++++++++ .../migrations/significant_drop.rs | 137 ++++++++++++++++++ .../migrations/significant_drop.stderr | 103 +++++++++++++ 5 files changed, 559 insertions(+) create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/no_migrations.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs new file mode 100644 index 0000000000000..37fab71be45df --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -0,0 +1,130 @@ +#![deny(disjoint_capture_drop_reorder)] +//~^ NOTE: the lint level is defined here + +// Test cases for types that implement a insignificant drop (stlib defined) + +// `t` needs Drop because one of its elements needs drop, +// therefore precise capture might affect drop ordering +fn test1_all_need_migration() { + let t = (String::new(), String::new()); + let t1 = (String::new(), String::new()); + let t2 = (String::new(), String::new()); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t, t1, t2) = (t, t1, t2); + let _t = t.0; + let _t1 = t1.0; + let _t2 = t2.0; + }; + + c(); +} + +// String implements drop and therefore should be migrated. +// But in this test cases, `t2` is completely captured and when it is dropped won't be affected +fn test2_only_precise_paths_need_migration() { + let t = (String::new(), String::new()); + let t1 = (String::new(), String::new()); + let t2 = (String::new(), String::new()); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t, t1) = (t, t1); + let _t = t.0; + let _t1 = t1.0; + let _t2 = t2; + }; + + c(); +} + +// If a variable would've not been captured by value then it would've not been +// dropped with the closure and therefore doesn't need migration. +fn test3_only_by_value_need_migration() { + let t = (String::new(), String::new()); + let t1 = (String::new(), String::new()); + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + println!("{}", t1.1); + }; + + c(); +} + +// Copy types get copied into the closure instead of move. Therefore we don't need to +// migrate then as their drop order isn't tied to the closure. +fn test4_only_non_copy_types_need_migration() { + let t = (String::new(), String::new()); + + // `t1` is Copy because all of its elements are Copy + let t1 = (0i32, 0i32); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + let _t1 = t1.0; + }; + + c(); +} + +fn test5_only_drop_types_need_migration() { + struct S(i32, i32); + + let t = (String::new(), String::new()); + + // `s` doesn't implement Drop or any elements within it, and doesn't need migration + let s = S(0i32, 0i32); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + let _s = s.0; + }; + + c(); +} + +// Since we are using a move closure here, both `t` and `t1` get moved +// even though they are being used by ref inside the closure. +fn test6_move_closures_non_copy_types_might_need_migration() { + let t = (String::new(), String::new()); + let t1 = (String::new(), String::new()); + let c = move || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t1, t) = (t1, t); + println!("{} {}", t1.1, t.1); + }; + + c(); +} + +// Test migration analysis in case of Drop + Non Drop aggregates. +// Note we need migration here only because the non-copy (because Drop type) is captured, +// otherwise we won't need to, since we can get away with just by ref capture in that case. +fn test7_drop_non_drop_aggregate_need_migration() { + let t = (String::new(), 0i32); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + }; + + c(); +} + +fn main() { + test1_all_need_migration(); + test2_only_precise_paths_need_migration(); + test3_only_by_value_need_migration(); + test4_only_non_copy_types_need_migration(); + test5_only_drop_types_need_migration(); + test6_move_closures_non_copy_types_might_need_migration(); + test7_drop_non_drop_aggregate_need_migration(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr new file mode 100644 index 0000000000000..8b35105cf8258 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr @@ -0,0 +1,105 @@ +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:13:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | let _t1 = t1.0; +LL | | let _t2 = t2.0; +LL | | }; + | |_____^ + | +note: the lint level is defined here + --> $DIR/insignificant_drop.rs:1:9 + | +LL | #![deny(disjoint_capture_drop_reorder)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: let (t, t1, t2) = (t, t1, t2); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:31:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | let _t1 = t1.0; +LL | | let _t2 = t2; +LL | | }; + | |_____^ + | + = note: let (t, t1) = (t, t1); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:47:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | println!("{}", t1.1); +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:65:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | let _t1 = t1.0; +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:83:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | let _s = s.0; +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:98:13 + | +LL | let c = move || { + | _____________^ +LL | | +LL | | +LL | | println!("{} {}", t1.1, t.1); +LL | | }; + | |_____^ + | + = note: let (t1, t) = (t1, t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/insignificant_drop.rs:113:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/no_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/no_migrations.rs new file mode 100644 index 0000000000000..73592ce04c28f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/no_migrations.rs @@ -0,0 +1,84 @@ +// run-pass + +// Set of test cases that don't need migrations + +#![deny(disjoint_capture_drop_reorder)] + + +// Copy types as copied by the closure instead of being moved into the closure +// Therefore their drop order isn't tied to the closure and won't be requiring any +// migrations. +fn test1_only_copy_types() { + let t = (0i32, 0i32); + + let c = || { + let _t = t.0; + }; + + c(); +} + +// Same as test1 but using a move closure +fn test2_only_copy_types_move_closure() { + let t = (0i32, 0i32); + + let c = move || { + println!("{}", t.0); + }; + + c(); +} + +// Don't need to migrate if captured by ref +fn test3_only_copy_types_move_closure() { + let t = (String::new(), String::new()); + + let c = || { + println!("{}", t.0); + }; + + c(); +} + +// Test migration analysis in case of Insignificant Drop + Non Drop aggregates. +// Note in this test the closure captures a non Drop type and therefore the variable +// is only captured by ref. +fn test4_insignificant_drop_non_drop_aggregate() { + let t = (String::new(), 0i32); + + let c = || { + let _t = t.1; + }; + + c(); +} + + +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +// Test migration analysis in case of Significant Drop + Non Drop aggregates. +// Note in this test the closure captures a non Drop type and therefore the variable +// is only captured by ref. +fn test5_significant_drop_non_drop_aggregate() { + let t = (Foo(0), 0i32); + + let c = || { + let _t = t.1; + }; + + c(); +} + +fn main() { + test1_only_copy_types(); + test2_only_copy_types_move_closure(); + test3_only_copy_types_move_closure(); + test4_insignificant_drop_non_drop_aggregate(); + test5_significant_drop_non_drop_aggregate(); + +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs new file mode 100644 index 0000000000000..1818e2dcc6478 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -0,0 +1,137 @@ +#![deny(disjoint_capture_drop_reorder)] +//~^ NOTE: the lint level is defined here + +// Test cases for types that implement a significant drop (user defined) + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +#[derive(Debug)] +struct ConstainsDropField(Foo, Foo); + +// `t` needs Drop because one of its elements needs drop, +// therefore precise capture might affect drop ordering +fn test1_all_need_migration() { + let t = (Foo(0), Foo(0)); + let t1 = (Foo(0), Foo(0)); + let t2 = (Foo(0), Foo(0)); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t, t1, t2) = (t, t1, t2); + let _t = t.0; + let _t1 = t1.0; + let _t2 = t2.0; + }; + + c(); +} + +// String implements drop and therefore should be migrated. +// But in this test cases, `t2` is completely captured and when it is dropped won't be affected +fn test2_only_precise_paths_need_migration() { + let t = (Foo(0), Foo(0)); + let t1 = (Foo(0), Foo(0)); + let t2 = (Foo(0), Foo(0)); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t, t1) = (t, t1); + let _t = t.0; + let _t1 = t1.0; + let _t2 = t2; + }; + + c(); +} + +// If a variable would've not been captured by value then it would've not been +// dropped with the closure and therefore doesn't need migration. +fn test3_only_by_value_need_migration() { + let t = (Foo(0), Foo(0)); + let t1 = (Foo(0), Foo(0)); + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + println!("{:?}", t1.1); + }; + + c(); +} + +// The root variable might not implement drop themselves but some path starting +// at the root variable might implement Drop. +// +// If this path isn't captured we need to migrate for the root variable. +fn test4_type_contains_drop_need_migration() { + let t = ConstainsDropField(Foo(0), Foo(0)); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + }; + + c(); +} + +// Test migration analysis in case of Drop + Non Drop aggregates. +// Note we need migration here only because the non-copy (because Drop type) is captured, +// otherwise we won't need to, since we can get away with just by ref capture in that case. +fn test5_drop_non_drop_aggregate_need_migration() { + let t = (Foo(0), 0i32); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.0; + }; + + c(); +} + +// Test migration analysis in case of Significant and Insignificant Drop aggregates. +fn test6_significant_insignificant_drop_aggregate_need_migration() { + struct S(i32, i32); + + let t = (Foo(0), String::new()); + + let c = || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t) = (t); + let _t = t.1; + }; + + c(); +} + +// Since we are using a move closure here, both `t` and `t1` get moved +// even though they are being used by ref inside the closure. +fn test7_move_closures_non_copy_types_might_need_migration() { + let t = (Foo(0), Foo(0)); + let t1 = (Foo(0), Foo(0), Foo(0)); + + let c = move || { + //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| NOTE: let (t1, t) = (t1, t); + println!("{:?} {:?}", t1.1, t.1); + }; + + c(); +} + +fn main() { + test1_all_need_migration(); + test2_only_precise_paths_need_migration(); + test3_only_by_value_need_migration(); + test4_type_contains_drop_need_migration(); + test5_drop_non_drop_aggregate_need_migration(); + test6_significant_insignificant_drop_aggregate_need_migration(); + test7_move_closures_non_copy_types_might_need_migration(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr new file mode 100644 index 0000000000000..52b6a628cc0ba --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -0,0 +1,103 @@ +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:24:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | let _t1 = t1.0; +LL | | let _t2 = t2.0; +LL | | }; + | |_____^ + | +note: the lint level is defined here + --> $DIR/significant_drop.rs:1:9 + | +LL | #![deny(disjoint_capture_drop_reorder)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: let (t, t1, t2) = (t, t1, t2); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:42:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | let _t1 = t1.0; +LL | | let _t2 = t2; +LL | | }; + | |_____^ + | + = note: let (t, t1) = (t, t1); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:58:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | println!("{:?}", t1.1); +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:75:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:90:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:105:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.1; +LL | | }; + | |_____^ + | + = note: let (t) = (t); + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/significant_drop.rs:120:13 + | +LL | let c = move || { + | _____________^ +LL | | +LL | | +LL | | println!("{:?} {:?}", t1.1, t.1); +LL | | }; + | |_____^ + | + = note: let (t1, t) = (t1, t); + +error: aborting due to 7 previous errors + From caf06bf5f5f3470f79362210a58c927711effd4d Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 2 Jan 2021 21:28:28 -0500 Subject: [PATCH 17/19] Mark the lint doc as compile_fail --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f1e5a4d47c787..199be00990761 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3002,7 +3002,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,compile_fail /// # #![deny(disjoint_capture_drop_reorder)] /// # #![allow(unused)] /// struct FancyInteger(i32); From 8f15cc1d88e2a4fdc41984da6178a8c2c92b1e2b Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Tue, 19 Jan 2021 03:15:36 -0500 Subject: [PATCH 18/19] PR fixup --- compiler/rustc_typeck/src/check/upvar.rs | 85 ++++++++++--------- .../migrations/insignificant_drop.rs | 2 +- .../migrations/significant_drop.rs | 2 +- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 16aaa48ce17fe..542d9a58e8aed 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -162,34 +162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); if should_do_migration_analysis(self.tcx, closure_hir_id) { - let need_migrations = self.compute_2229_migrations_first_pass( - closure_def_id, - span, - capture_clause, - body, - self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), - ); - - if !need_migrations.is_empty() { - let need_migrations_hir_id = - need_migrations.iter().map(|m| m.0).collect::>(); - - let migrations_text = - migration_suggestion_for_2229(self.tcx, &need_migrations_hir_id); - - self.tcx.struct_span_lint_hir( - lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, - closure_hir_id, - span, - |lint| { - let mut diagnostics_builder = lint.build( - "drop order affected for closure because of `capture_disjoint_fields`", - ); - diagnostics_builder.note(&migrations_text); - diagnostics_builder.emit(); - }, - ); - } + self.perform_2229_migration_anaysis(closure_def_id, capture_clause, span, body); } // We now fake capture information for all variables that are mentioned within the closure @@ -555,6 +528,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list); } + /// Perform the migration analysis for RFC 2229, and emit lint + /// `disjoint_capture_drop_reorder` if needed. + fn perform_2229_migration_anaysis( + &self, + closure_def_id: DefId, + capture_clause: hir::CaptureBy, + span: Span, + body: &'tcx hir::Body<'tcx>, + ) { + let need_migrations = self.compute_2229_migrations_first_pass( + closure_def_id, + span, + capture_clause, + body, + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), + ); + + if !need_migrations.is_empty() { + let need_migrations_hir_id = need_migrations.iter().map(|m| m.0).collect::>(); + + let migrations_text = migration_suggestion_for_2229(self.tcx, &need_migrations_hir_id); + + let local_def_id = closure_def_id.expect_local(); + let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); + self.tcx.struct_span_lint_hir( + lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, + closure_hir_id, + span, + |lint| { + let mut diagnostics_builder = lint.build( + "drop order affected for closure because of `capture_disjoint_fields`", + ); + diagnostics_builder.note(&migrations_text); + diagnostics_builder.emit(); + }, + ); + } + } + /// Figures out the list of root variables (and their types) that aren't completely /// captured by the closure when `capture_disjoint_fields` is enabled and drop order of /// some path starting at that root variable **might** be affected. @@ -617,17 +629,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_moved = root_var_min_capture_list .iter() - .find(|capture| matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue(_))) - .is_some(); - - // 1. If we capture more than one path starting at the root variabe then the root variable - // isn't being captured in its entirety - // 2. If we only capture one path starting at the root variable, it's still possible - // that it isn't the root variable completely. - if is_moved - && ((root_var_min_capture_list.len() > 1) - || (root_var_min_capture_list[0].place.projections.len() > 0)) - { + .any(|capture| matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue(_))); + + let is_not_completely_captured = + root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0); + + if is_moved && is_not_completely_captured { need_migrations.push((var_hir_id, ty)); } } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index 37fab71be45df..5b5092e9db9a4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -108,7 +108,7 @@ fn test6_move_closures_non_copy_types_might_need_migration() { // Note we need migration here only because the non-copy (because Drop type) is captured, // otherwise we won't need to, since we can get away with just by ref capture in that case. fn test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), 0i32); + let t = (String::new(), String::new(), 0i32); let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index 1818e2dcc6478..25b5539b86289 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -85,7 +85,7 @@ fn test4_type_contains_drop_need_migration() { // Note we need migration here only because the non-copy (because Drop type) is captured, // otherwise we won't need to, since we can get away with just by ref capture in that case. fn test5_drop_non_drop_aggregate_need_migration() { - let t = (Foo(0), 0i32); + let t = (Foo(0), Foo(0), 0i32); let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` From 84f0a0a1c6627e83408d1faf46e29d29d2bc13e9 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Tue, 26 Jan 2021 04:08:23 -0500 Subject: [PATCH 19/19] New migration --- compiler/rustc_typeck/src/check/upvar.rs | 2 +- .../migrations/insignificant_drop.rs | 14 +++++++------- .../migrations/insignificant_drop.stderr | 14 +++++++------- .../migrations/significant_drop.rs | 14 +++++++------- .../migrations/significant_drop.stderr | 14 +++++++------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 542d9a58e8aed..04a9e65e6647d 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1270,7 +1270,7 @@ fn migration_suggestion_for_2229(tcx: TyCtxt<'_>, need_migrations: &Vec>(); let migrations_list_concat = need_migrations_strings.join(", "); - format!("let ({}) = ({});", migrations_list_concat, migrations_list_concat) + format!("drop(&({}));", migrations_list_concat) } /// Helper function to determine if we need to escalate CaptureKind from diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index 5b5092e9db9a4..02b373620966e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -12,7 +12,7 @@ fn test1_all_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t, t1, t2) = (t, t1, t2); + //~| NOTE: drop(&(t, t1, t2)); let _t = t.0; let _t1 = t1.0; let _t2 = t2.0; @@ -30,7 +30,7 @@ fn test2_only_precise_paths_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t, t1) = (t, t1); + //~| NOTE: drop(&(t, t1)); let _t = t.0; let _t1 = t1.0; let _t2 = t2; @@ -46,7 +46,7 @@ fn test3_only_by_value_need_migration() { let t1 = (String::new(), String::new()); let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; println!("{}", t1.1); }; @@ -64,7 +64,7 @@ fn test4_only_non_copy_types_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; let _t1 = t1.0; }; @@ -82,7 +82,7 @@ fn test5_only_drop_types_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; let _s = s.0; }; @@ -97,7 +97,7 @@ fn test6_move_closures_non_copy_types_might_need_migration() { let t1 = (String::new(), String::new()); let c = move || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t1, t) = (t1, t); + //~| NOTE: drop(&(t1, t)); println!("{} {}", t1.1, t.1); }; @@ -112,7 +112,7 @@ fn test7_drop_non_drop_aggregate_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; }; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr index 8b35105cf8258..656c132c12dee 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr @@ -16,7 +16,7 @@ note: the lint level is defined here | LL | #![deny(disjoint_capture_drop_reorder)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: let (t, t1, t2) = (t, t1, t2); + = note: drop(&(t, t1, t2)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/insignificant_drop.rs:31:13 @@ -31,7 +31,7 @@ LL | | let _t2 = t2; LL | | }; | |_____^ | - = note: let (t, t1) = (t, t1); + = note: drop(&(t, t1)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/insignificant_drop.rs:47:13 @@ -45,7 +45,7 @@ LL | | println!("{}", t1.1); LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/insignificant_drop.rs:65:13 @@ -59,7 +59,7 @@ LL | | let _t1 = t1.0; LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/insignificant_drop.rs:83:13 @@ -73,7 +73,7 @@ LL | | let _s = s.0; LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/insignificant_drop.rs:98:13 @@ -86,7 +86,7 @@ LL | | println!("{} {}", t1.1, t.1); LL | | }; | |_____^ | - = note: let (t1, t) = (t1, t); + = note: drop(&(t1, t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/insignificant_drop.rs:113:13 @@ -99,7 +99,7 @@ LL | | let _t = t.0; LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: aborting due to 7 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index 25b5539b86289..ed5e4ea8be011 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -23,7 +23,7 @@ fn test1_all_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t, t1, t2) = (t, t1, t2); + //~| NOTE: drop(&(t, t1, t2)); let _t = t.0; let _t1 = t1.0; let _t2 = t2.0; @@ -41,7 +41,7 @@ fn test2_only_precise_paths_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t, t1) = (t, t1); + //~| NOTE: drop(&(t, t1)); let _t = t.0; let _t1 = t1.0; let _t2 = t2; @@ -57,7 +57,7 @@ fn test3_only_by_value_need_migration() { let t1 = (Foo(0), Foo(0)); let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; println!("{:?}", t1.1); }; @@ -74,7 +74,7 @@ fn test4_type_contains_drop_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; }; @@ -89,7 +89,7 @@ fn test5_drop_non_drop_aggregate_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.0; }; @@ -104,7 +104,7 @@ fn test6_significant_insignificant_drop_aggregate_need_migration() { let c = || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t) = (t); + //~| NOTE: drop(&(t)); let _t = t.1; }; @@ -119,7 +119,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { let c = move || { //~^ERROR: drop order affected for closure because of `capture_disjoint_fields` - //~| NOTE: let (t1, t) = (t1, t); + //~| NOTE: drop(&(t1, t)); println!("{:?} {:?}", t1.1, t.1); }; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr index 52b6a628cc0ba..6c21b27b493ba 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -16,7 +16,7 @@ note: the lint level is defined here | LL | #![deny(disjoint_capture_drop_reorder)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: let (t, t1, t2) = (t, t1, t2); + = note: drop(&(t, t1, t2)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/significant_drop.rs:42:13 @@ -31,7 +31,7 @@ LL | | let _t2 = t2; LL | | }; | |_____^ | - = note: let (t, t1) = (t, t1); + = note: drop(&(t, t1)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/significant_drop.rs:58:13 @@ -45,7 +45,7 @@ LL | | println!("{:?}", t1.1); LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/significant_drop.rs:75:13 @@ -58,7 +58,7 @@ LL | | let _t = t.0; LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/significant_drop.rs:90:13 @@ -71,7 +71,7 @@ LL | | let _t = t.0; LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/significant_drop.rs:105:13 @@ -84,7 +84,7 @@ LL | | let _t = t.1; LL | | }; | |_____^ | - = note: let (t) = (t); + = note: drop(&(t)); error: drop order affected for closure because of `capture_disjoint_fields` --> $DIR/significant_drop.rs:120:13 @@ -97,7 +97,7 @@ LL | | println!("{:?} {:?}", t1.1, t.1); LL | | }; | |_____^ | - = note: let (t1, t) = (t1, t); + = note: drop(&(t1, t)); error: aborting due to 7 previous errors